你知道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的位运算哈!
推荐阅读