Redis をカウンターとして使用して投票システムを改善する

齐天大圣
リリース: 2020-05-08 16:41:59
オリジナル
2128 人が閲覧しました

まず、アプリケーション シナリオを見てみましょう。数年前、WeChat には多くの投票システムがありました。多くの人は、友人や友人の輪の中で投票を求める人を探しています。当時は比較的大きな遊園地でもこの投票イベントが行われており、一定の投票数を超えると無料で遊べるようでした。友達にも投票してほしいと頼まれて、1日3~5票くらいだったような気がしますが、詳細ははっきりとは覚えていません。システムに入った後、友人の投票ボタンをクリックしましたが、何も起こらなかったことがわかりました。ネットワークに問題があるのか​​と思いましたが、後でプログラムの問題であることがわかりました。当時私は、投票する人が多すぎてシステムがしばらく処理できなくなったのではないかと推測しました。

なぜなら、その時私はたまたま redis を学んでいたからです。なので、この機能はredisのカウンターで改善できると思います。

ここでは、ユーザーの具体的な投票状況は考慮せず、ユーザーの総投票数のみをカウントします。たとえば、A が B に投票したときの記録は考慮しません。この状況を考慮した場合は、他のソリューションを使用する必要があります (メッセージ キューを使用できます)。

検証

まず、各ユーザーが投じた投票数を検証します。ユーザーには毎日 3 回投票する機会があるため、キーを作成し、その有効期間を明日の朝に設定できます。ユーザーが投票するたびに 1 が加算され、3 票に到達すると、今日の投票数がなくなりましたと表示されます。

// 投票次数校验
function checkVote($uid)
{
    $key = "uid:$uid:cnt";
    $tomrTime = mktime(0,0,0, date('m'), date('d')+1, date('Y'));
    
    if (!$redis->exsits($key)) {
        $redis->set($key, 0, ['ex' => $tomrTime - time()]);
        return true;
    } else if ( ($cnt = $redis->get($key)) < 3 ) {
        return true;
    } else {
        return false;
    }
}
ログイン後にコピー

統計的投票

投票数を確認した後、ユーザーが獲得した投票数をカウントする必要があります。

// 得票数计数
// uid表示投票人id
// touid表示得票人id
function vote ($uid, $toUid)
{
    $key = "uid:$toUid:vote";
    
    // 投票数校验
    if (checkVote($uid)) {
        // 统计投票数及参选人得票数
        $redis->incr($key);
        $redis->incr("uid:$uid:cnt");
        
        return true;
    } else {
        return false;
    }
}
ログイン後にコピー

私自身の Alibaba Cloud ホスト構成には 1 コア CPU と 1G メモリ構成しかありません。incr パフォーマンスは 1 秒あたり 100,000 回以上に達することがあります。redis のパフォーマンスは本当にひどいです。

# redis-benchmark -t incr -q
INCR: 105708.25 requests per second
ログイン後にコピー

Mysql はユーザーの投票数を非同期で更新します

最後に、スケジュールされたタスクを実行するだけで、mysql にタスクを実行させることができます。一定時間ごとにユーザーの投票数を同期します。

この方法では、無限ループを作成し、すべてのユーザーを走査するまで毎回 50 人のユーザーの投票を取得し、ループを終了してスクリプトを終了します。

$start = 0;
while (true) {
    // 每次循环取50个用户id
    $users = $DB->query("SELECT uid,votes FROM users LIMIT $start, 50");
    if (!$users) {
        exit();
    }
    $keys = [];
    foreach ($users as $userinfo) {
        $keys[] = "uid:{$userinfo[&#39;uid&#39;]}:vote";
    }
    $votes = $redis->mget($keys);
    foreach ($votes as $index => $vote) {
        if ($vote != $users[$index][&#39;votes&#39;]) {
            $DB->query("UPDATE users SET votes = &#39;$vote&#39; WHERE uid=&#39;{$users[$index][&#39;uid&#39;]}");
        }
    }
    $start += 50;
}
ログイン後にコピー

Redisのmgetコマンドは複数のキーの値を一度に取得します。 redis に保存されている redis 投票数を取得したら、まずそれを Mysql の投票数と比較する必要があります。 Mysql データが異なる場合にのみ更新します。

以上がRedis をカウンターとして使用して投票システムを改善するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート
私たちについて 免責事項 Sitemap
PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!