Redis中bitmap的应用

Redis中bitmap的应用

redis中bitmap的相关方法

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

offset是下标,value是0或者1,复杂度为O(1)

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

获得offset上的值,0或者1,复杂度为O(1)

  • BITCOUNT
计算给定字符串中,被设置为 1 的比特位的数量。

例如这个key保存的字符串二进制为101011,则返回结果4。

  • BITOP(operation destkey key [key ...])
对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。

operation 可以是 ANDORNOTXOR 这四种操作中的任意一种

对两个二进制串进行操作用的方法。

  • BITFIELD
3.2版本新加入的方法,功能很复杂。这里不做讨论

以上几个方法结合使用,可以实现以下几种功能:

1、统计每日上线人数(活跃人数统计)

用带有日期的字符串当key,拿用户的uid当作offset,当天登录了就执行一次下面的代码

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

这样,所有登录过的用户,会组成这个key为“20170323_au”的二进制字符串中

然后再使用

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

就可以拿到今天上线人数的统计了。

如果你想拿到最近三天的活跃人数怎么办?同样简单:

$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

对比传统的数据库,实现起来的难易度和效率简直不可同日而语。

下面是我自己的测试数据

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的数据。

2、用来判断当天是否是第一次登录(或者每天限领一次的逻辑判断)

之前游戏的经验,是通过数据库中的一个column来记录上一次登录的时间戳,再用当前时间跟数据库(MySQL)中记录的时间做对比来判断是否是同一天登录。比较传统的做法。

这里可以同样利用上面的方法,

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

3、同来做连续登陆奖励发放的条件判断

同样,用来做连续登陆的判断也很方便,只需要将之前几天的登录记录做一下and操作,在做判断就可以了。
Redis中bitmap的应用_第1张图片

$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数据类型。无论是从效率上,还是资源上,都有很大的优势。

你可能感兴趣的:(Redis中bitmap的应用)