基于Redis bitmap实现签到功能

需求场景

Bitmap 对于一些特定类型的计算非常有效。

假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户A上线了多少天,用户B上
线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加beta测试等活动——这个模式可以使
用SETBIT和BITCOUNT来实现。

比如说,每当用户在某一天上线的时候,我们就使用SETBIT,以用户名作为key,将那天所代表的网站
的上线日作为offset 参数,并将这个offset 上的为设置为1。

举个例子,如果今天是网站上线的第100天,而用户(uid=10086)在今天阅览过网站,那么执行命令SETBIT sign:10086 100 1;如果明天用户(uid=10086)也继续阅览网站,那么执行命令SETBIT sign:10086 101 1,以此类推。

  1. sign:10086 代表位数组
  2. 101代表位数组的第几位
  3. 1代表该位置上的bit值设置为1

当要计算用户(uid=10086)总共以来的上线次数时,就使用BITCOUNT命令:执行BITCOUNT sign:10086,得出的结果就是用户(uid=10086)上线的总天数。

BITCOUNT命令作用:

统计字符串被设置为1的bit数.

一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。

start 和 end 参数的设置,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,

start、end 是指bit组的字节的下标数,二者皆包含。

性能

以上线次数统计例子,即使运行10年,占用的空间也只是每个用户10*365比特位(bit),也即是每个
用户456字节。对于这种大小的数据来说,BITCOUNT的处理速度就像GET和INCR这种O(1)复杂度的
操作一样快。

如果你的bitmap数据非常大,那么可以考虑使用以下两种方法:

  1. 将一个大的bitmap分散到不同的key中,作为小的bitmap来处理。使用Lua脚本可以很方便地完成这一工作。

  2. 使用BITCOUNT的start和end参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存(caching)。

代码实现

https://github.com/billfeller/billfeller.github.io/blob/master/code/ISign.php

你可能感兴趣的:(redis)