Redis를 카운터로 사용하여 투표 시스템 개선

齐天大圣
풀어 주다: 2020-05-08 16:41:59
원래의
2222명이 탐색했습니다.

먼저 적용 시나리오 살펴보기: 몇 년 전 WeChat에는 많은 투표 시스템이 있었습니다. 많은 사람들이 자신의 친구나 친구 집단에서 투표를 위해 투표할 사람을 찾습니다. 당시 비교적 규모가 큰 놀이공원에서도 이 투표 행사를 진행했는데, 일정 표를 넘으면 무료로 플레이할 수 있었던 것 같습니다. 저도 친구들한테 투표해달라는 부탁을 받았는데 하루에 3~5표씩 투표할 수 있었던 것 같더라고요. 자세한 내용은 기억이 안 나네요. 시스템에 들어간 후 친구의 투표 버튼을 눌렀는데 아무 일도 일어나지 않았습니다. 네트워크 문제인 줄 알았는데, 나중에 알고 보니 프로그램 문제였습니다. 투표하는 사람이 너무 많아 한동안 시스템이 이를 감당하지 못할 것이라고 당시 추측했습니다.

그때 우연히 redis를 배우고 있었거든요. 그래서 이 기능은 redis의 카운터를 통해 개선될 수 있다고 생각합니다.

여기에서는 사용자의 구체적인 투표 상황을 고려하지 않고 사용자의 총 투표 수만 계산합니다. 예를 들어 A가 B에게 투표한 기록은 고려하지 않습니다. 이러한 상황을 고려한다면 다른 솔루션을 사용해야 합니다(메시지 대기열을 사용할 수 있음).

검증

먼저 각 사용자의 투표수를 검증해야 합니다. 사용자는 매일 세 번의 투표 기회를 가지므로 키를 생성하고 유효 기간을 내일 아침으로 설정할 수 있습니다. 사용자가 투표할 때마다 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 메모리 구성만 있습니다. 증가 성능은 초당 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿