vlambda博客
学习文章列表

你知道redis签到打卡统计怎么做吗?你知道个锤子

每天与你分享 

IT编程开发 技术干货 架构方案 技术思维导图 设计模式 算法题库

正文内容

准备


 Redis 的字符串数据是以二进制的形式存放的,Redis 的 Bit 操作非常适合处理签到统计这个场景,因为 Bit 的值为 0 或 1,用户是否签到也可以用 0 或 1 来表示,如果我们把签到的天数对应到每个字节上,那就是就是 1,没打的那就是 0,那么一个用户一年365天下来的记录就是 365 位的长度,1000 万用户一年只需要耗费大约 430 M 左右的存储空间就可以了,而且速度非常的快,那到底这个是这么计算来呢?

其实就是:

在一台 MacBook Pro 上,offset 为 2^32-1(分配 512MB)需要~300ms,offset 为 2^30-1 (分配 128MB) 需要~80ms,offset 为 2^28-1(分配 32 MB)需要~30ms左右,offset 为 2^26-1(分配 8MB)需要 8ms。

所以可以知道大概的空间占用计算公式是:

存储空间等于:(offset / 8 / 1024 / 1024) MB

这里的 offset ,大家可以当做用户 ID 来看。


那么究竟要怎么样去打卡签到呢,这个时候可以利用 setbit 命令来实现这个功能,setbit 的作用是:在你想要的位置操作字节值,比如说用户 4 在 4 月 14 号 签到了,那么 setbit (20200414, 4 ,1) 就可以实现签到功能了,这里的 offset 就是 4了,同样的道理,不同的用户不同的日期,改变对应的值就好可以了。

废话不多说我们来敲代码实战一下:

代码

1. 创建一个 Redis 连接

$redis_obj=app('redis.connection');

2. 如何去设计 key 呢?

$Key_01 = 'login_ok:'.\now()->format('Ymd'); // 输出类似:login:20200414 // 写法2 $Key_02 = 'login_ok:'.\date('Ymd',\time());

3. 签到

setbit - SETBIT KEY_NAME OFFSET (Time complexity: O(1))

对 key 所储存的对应的字符串值,以下命令设置或清除指定偏移量上的位 bit

$redis_obj->setbit($Key_01,$this->user->id,1);

存储方面不但耗费内存少,而且快,操作还很方便呢,还有非常低的灵活高效的统计计算成本。

4. 计算一月内的签到数据

bitop - BITOP operation destkey key [key ...]

对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 dekskey 上

AND : 对一个或多个 key 求逻辑并

OR : 对一个或多个 key 求逻辑或

XOR : 对一个或多个 key 求逻辑异或

NOT : 对给定 key 求逻辑非

$redis_obj->bitop('AND', 'threeAnd', 'login:20200414', 'login:20200413', 'login:20200412','...');echo "连续N天都签到打卡的用户数量:" . $redis_obj->bitCount('threeAnd');$redis->bitop('OR', 'threeOr', 'login:20200414', 'login:20200413', 'login:20200412','....');echo "N天中签到用户数量(有一天签也算签了):" . $redis_obj->bitCount('threeOr');
$redis_obj->bitop('AND', 'monthActivities'', $redis_obj->keys('login:202004*'));echo "连续N个月签到用户数量:" . $redis_obj->bitCount('monthActivities');
echo "查询当前用户指定第N天是否签到:" . $redis->getbit('login:20200414', $this->user->id);.....

整体来说还是挺好用挺方便的

最后

redis的位运算无论是存储上面还是在统计计算上面,都比 mysql 的方案方便和好,所以推荐大家以后还是使用redis的位运算哈!


推荐阅读