最近要做一个圣诞抽奖活动, 需要记录每天用户签到的记录, 以前一般都是用普通的字符串数据类型, 每个用户的签到用一个 key
- // 用户 10 在活动第一天的签到 key 为 record:1:10
- $key = "record:$day:$id";
- if ($Redis->get($key)) {
- echo '已签到';
- } else {
- $Redis->set($key, 1)
- }
那么一个用户一天的签到记录就要占一个字节, 用户一多就产生非常多的 key, 浪费宝贵的内存.
位图
为了解决这个问题, Redis 另一种数据类型位图就非常适合. 位图并不是特殊的数据类型, 内容其实就是字符串, 每一位只存储 0 或 1, 非常适合存储这种布尔类型的数据
位图使用 setbit/getbit 来存取数据
- > SETBIT key offset value
- > GETBIT key offset
比如一个用户圣诞连续五天的签到记录可以只使用一个 key, 10010 代表用户只有第二天和第五天签过到
- $key = "record:$id";
- if ($Redis->getbit($key, $day)) {
- echo '已签到';
- } else {
- $Redis->setbit($key, $day, 1)
- }
现在一个用户五天的签到记录只会产生一个 key, 占用内存仅为 5bit 不到一个字节
进一步, 如果你的用户系统中用户 id 是连续的 int 类型, 还能更节省. 因为只记录每个用户 5 天的签到记录, 在一串位图中, 每个用户占 5 个坑, 这样所有的用户的签到数据只会使用一个 key
- // 用户 1 占前 5 个坑
- $offset = ($id - 1) * 5 + $day -1;
- if ($Redis->getbit('record', $offset)) {
- echo '已签到';
- } else {
- $Redis->setbit('record', $offset, 1)
- }
现在只需要一个 key 就可以存下所有用户的签到记录了.
需要注意的是位图一个 key 最多存储 512mb 的内容, 如果你的用户数大于 8*1024*1024*1024*512 / 5 ≈ 87 亿 并不适用这个方法.
其他用法
bitcount 用来统计指定位置范围内 1 的个数, bitpos 用来查找指定范围内出现的第一个 0 或 1.
- > setbit s 0 1
- > setbit s 3 1 #s=1001
- > bitcount s [start, end]
- (integer) 2
- > bitpos s 0 [start, end]
- (integer) 1
来源: https://www.cnblogs.com/luke44/p/12031078.html