Home  >  Article  >  Database  >  Use redis as a counter to improve the voting system

Use redis as a counter to improve the voting system

齐天大圣
齐天大圣Original
2020-05-08 16:34:302219browse

Let’s first look at the application scenarios: A few years ago, there were many voting systems in WeChat. Many people look for people in their friends or circle of friends to canvass for votes. At that time, a relatively large amusement park also conducted this voting event. It seemed that if you exceeded a certain number of votes, you could play for free. I was also asked by my friends to vote for him. It seemed that I could vote 3 or 5 votes a day. I can’t remember the details clearly. After I entered the system, I clicked the voting button for my friend and found that nothing happened. I thought it was a problem with my network, but later I found out it was a problem with the program. I guessed at the time that there were too many people voting and the system couldn't handle it for a while.

Because at that time, I happened to be learning redis. So, I think this function can be improved through redis' counter.

Here, we only count the total number of votes cast by users, without considering the specific voting situation of users. For example, we do not consider the record of when A voted for B. If you consider this situation, you need to use other solutions (message queues can be used).

Verification

First, verify the number of votes cast by each user. Users have three opportunities to vote every day, so we can create a key and set its validity period to tomorrow morning. Each time the user casts a vote, 1 will be added. When the user reaches 3 votes, it will be prompted that the number of votes has been used up today.

// 投票次数校验
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;
    }
}

Statistical voting

After the number of votes is verified, it is necessary to count the number of votes obtained by the user.

// 得票数计数
// 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;
    }
}

My own Alibaba Cloud host configuration only has 1 core CPU and 1G memory configuration. The incr performance can reach more than 100,000 times per second. The redis performance is really terrible.

# redis-benchmark -t incr -q
INCR: 105708.25 requests per second

Mysql asynchronously updates the number of user votes

Finally, we only need to do a scheduled task, and let mysql go to it every certain time Synchronize the user's vote count.

The method is to make an infinite loop, and get the votes of 50 users each time, until all users are traversed, then exit the loop and end the script.

$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;
}

The mget command of Redis obtains the values ​​​​of multiple keys at one time. After obtaining the number of redis votes stored in redis, you must first compare it with the number of votes in Mysql. Only update Mysql data when it is different.

The above is the detailed content of Use redis as a counter to improve the voting system. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Previous article:Use Redis to store tokensNext article:Use Redis to store tokens