Redis中bitmap的應用

Redis中bitmap的應用

redis中bitmap的相關方法php

  • SETBIT(key offset value)
key 所儲存的字符串值,設置或清除指定偏移量上的位(bit)。

offset是下標,value是0或者1,複雜度爲O(1)linux

  • GETBIT(key offset)
key 所儲存的字符串值,獲取指定偏移量上的位(bit)。

得到offset上的值,0或者1,複雜度爲O(1)redis

  • BITCOUNT
計算給定字符串中,被設置爲 1 的比特位的數量。

例如這個key保存的字符串二進制爲101011,則返回結果4。數據庫

  • BITOP(operation destkey key [key ...])
對一個或多個保存二進制位的字符串 key 進行位元操做,並將結果保存到 destkey 上。

operation 能夠是 ANDORNOTXOR 這四種操做中的任意一種windows

對兩個二進制串進行操做用的方法。測試

  • BITFIELD
3.2版本新加入的方法,功能很複雜。這裏不作討論

以上幾個方法結合使用,能夠實現如下幾種功能:

一、統計每日上線人數(活躍人數統計)

用帶有日期的字符串當key,拿用戶的uid看成offset,當天登陸了就執行一次下面的代碼ui

$redis->setBit('20170323_au',123,1);

這樣,全部登陸過的用戶,會組成這個key爲「20170323_au」的二進制字符串中spa

而後再使用code

$redis->bitCount('20170323_au');

就能夠拿到今天上線人數的統計了。blog

若是你想拿到最近三天的活躍人數怎麼辦?一樣簡單:

$redis->bitOp('OR','last_3_au','20170321_au','20170322_au','20170323_au');
$result = $redis->bitCount('last_3_au');

BITOP將三天的結果作OR操做

獲得的結果在bitCount一下就是最近三天的活躍人數了。

關於效率,有人統計了128million用戶的表現。

PERIOD TIME (MS)
Daily 50.2
Weekly 392.0
Monthly 1624.8

對比傳統的數據庫,實現起來的難易度和效率簡直不可同日而語。

下面是我本身的測試數據

<?php
require_once dirname(__FILE__) . '/../config/autoload.php';

$t1 = microtime(true);

$redis = RedisManage::getRedisForShare();

//makeTestData('20161221');
//makeTestData('20161222');
//makeTestData('20161223');

$redis->bitOp('OR', 'stat_3_day_3m', '20161221', '20161222', '20161223');
echo $redis->bitCount('stat_3_day_3m') . "\n";

echo "time taken: " . (microtime(true) - $t1);

function makeTestData($key)
{
    $redis = RedisManage::getRedisForShare();
    for ($i = 0; $i < 3000000; $i++) {
        $redis->setBit($key, $i, mt_rand(0, 1));
    }
}

先建立了3條3million的數據。

最後顯示結果:

並且這是windows環境下的測試結果。linux應該會更快。

這要比傳統的關係型數據庫使用count,group by要效率不少。

並且,由於是bitmap的緣由,300萬個用戶的數據佔用的長度爲3000000/8=375000字節,也就是45kb不到。

1年也就是16.3Mb的數據。

二、用來判斷當天是不是第一次登陸(或者天天限領一次的邏輯判斷)

以前遊戲的經驗,是經過數據庫中的一個column來記錄上一次登陸的時間戳,再用當前時間跟數據庫(MySQL)中記錄的時間作對比來判斷是不是同一天登陸。比較傳統的作法。

這裏能夠一樣利用上面的方法,

$login_status = $redis->getBit('20170323', $uid);
if($login_status == 0){
  // first login today and send login gifts
}

三、同來作連續登錄獎勵發放的條件判斷

一樣,用來作連續登錄的判斷也很方便,只須要將以前幾天的登陸記錄作一下and操做,在作判斷就能夠了。

$redis->bitOp('AND', 'stat_3_day_continue', '20161221', '20161222', '20161223');
$is_3_day_continue = $redis->getBit('stat_3_day_continue', $uid);
if($is_3_day_continue){
  // three days login gifts send
}

結語

只要是涉及到相似簽到功能的記錄,不管是以什麼時間間隔爲單位(最終就是反應在key的不一樣),均可以使用Redis的bitmap數據類型。不管是從效率上,仍是資源上,都有很大的優點。

相關文章
相關標籤/搜索