首頁 >資料庫 >Redis >使用redis來做計數器完善投票系統

使用redis來做計數器完善投票系統

齐天大圣
齐天大圣原創
2020-05-08 16:34:302241瀏覽

首先看應用場景:幾年前,微信裡許多投票系統。很多人找好友或朋友圈找人拉票。當時,有一個比較大的樂園也做了這個投票活動,好像是超過一定票數就可以免費玩。我也被好友要求給他投票,有一天好像可以投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;
    }
}

我自己的阿里雲主機配置只有1核心cpu1G記憶體的配置,每秒incr效能能達到10萬多次,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指令的是一次取得多個key的值。取得了redis裡存放的redis得票數後,要先和Mysql裡的得票數做比對。不一樣的時候才去更新Mysql的資料。

以上是使用redis來做計數器完善投票系統的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn