Redis位图(bitmap)介绍和在签到场景的应用

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

基本原理:

《Redis设计与实现》中对位图的实现描述是:Redis使用字符串对象来表示位数组,因为字符串对象使用的SDS数据结构是二进制安全的,所以程序可以直接使用SDS结构来保存位数组,并使用SDS结构的操作函数来处理为数组。

所以位图本质上结构就是redis的字符串类型SDS(simple dynamic string)。

bigmap底层.png

计算机的存储,都是以二进制0和1存储的数据,位图就是直接对数据的比特位进行读取、赋值等操作。

redis位图相关指令

setbit命令

指令: SETBIT key offset value
复杂度: O(1)
含义:设置或者清空key的value(字符串)在offset处的bit值(只能只0或者1)。offset位负数或者浮点数,执行报错。(set the original bit value stored at offset)
getbit命令
复制代码

getbit命令

指令: getbit key offset
复杂度: O(1)
含义:获取key的value(字符串)在offset处的bit值(只能只0或者1)。(get the bit value stored at offset.)
复制代码

bitcount命令

指令: bitcount key
复杂度: O(N)
含义:获取key的value(字符串)所有比特位设置位1的总个数(The number of bits set to 1)。
复制代码

bitfield命令

指令: bitfield key [option1] [option2] ....
复杂度: O(1) * 每个指定的子命令
含义: 操作多字节位域,它会执行一系列操作,并返回一个响应数组,在参数列表中每个响应数组匹配相应的操作。
官方文档: http://www.redis.cn/commands/bitfield.html
复制代码

bitpos命令

指令: bitpos key 0|1
复杂度: O(N)
含义: 命令返回字符串里面第一个被设置为1或者0的bit位。(后面还可以接start end两个参数,但是偏移量的单位是字节,不是比特位,几乎没用)
复制代码

bitop命令

指令:BITOP [AND|OR|NOT|XOR ]destkey key1 key2
复杂度: O(N)
含义: 对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
官方文档: http://www.redis.cn/commands/bitop.html
复制代码

空间占用&第一次分配空间需要的时间 空间占用量随着偏移量的增大而增大,在redis4.0版本可使用memory usage [key] 查看key的空间占用情况。

占用空间.png

官方文档数据 offset为2^32-1(分配512MB)需要~300ms
offset为2^30-1(分配128MB)需要~80ms
offset为2^28-1(分配32MB)需要~30ms
offset为2^26-1(分配8MB)需要8ms

大概的空间占用计算公式是:($offset/8/1024/1024)MB

应用场景

签到是一个很典型的位图使用场景
指令应用简介
getbit 查看签到状态
setbit 标记签到
bitcount 累计签到次数
bitfield 批量查询签到标记

下面是签到应用场景演示,如果签到后还需要有一些用户奖励领取的逻辑,当然还可能涉及到补签等用户行为,则可以利用两个比特位来实现逻辑。

累计签到应用场景

累计签到.gif

累计签到02.gif

连续签到应用场景

连续签到.gif

连续签到02.gif

日期签到场景

日期签到.gif

日期签到02.gif

应用详情

getbit查看第n比特位值----“第N个比特位”标识“第几天的签到状态”
指令示例截图:

01.png
含义: 查看key为 Test4SignMzy 的value值,第一位比特位是0

需求运用:

key可以作为签到活动的某个周期, “第N个比特位”标识“第几天的签到状态”。

setbit将第n比特位标记成0或1----用户“第n天签到”就将“第n个比特位”标记为1 指令示例截图:

02.png

含义:

将key为 Test4SignMzy 的value值,第一位比特位赋值为1,然后查看到比特位以改变为1。
复制代码

需求运用:

key可以作为签到活动的某个周期,用户“第n天签到”就将这个redis key对应value值的“第n个比特位”标记为1。

bitcount统计所有比特位中为1的个数----用户“累计签到N次”用该值查询 指令示例截图:

03.png
含义:

key为 Test4SignMzy 的value值,所占用的所有比特位中,比特位值为1的总数是4个。
复制代码

需求运用: key可以作为签到活动的某个周期,用户“累计签到N次”,就可以用value值一共有多少个比特位为1得知。

bitfield 命令可以在一次调用中同时对多个位范围进行操作 指令示例截图:

04.png 含义:

第一个执行“bitfield Test4SignMzy get u1 1 get u1 2 get u1 3 get u1 4 get u1 8 get u1 9 get u1 10 get u1 99”,意思就是查看Test4SignMzy对应的value的第1、2、3、4、8、9、10、99比特位的值,得到的值当作无符号1位整数返回。加入原本不存在第99位,返回0代替。 

第二个执行“bitfield Test4SignMzy get u1 #1 get u1 #2 get u1 #3 get u1 #4 get u1 #8 get u1 #9 get u1 #10 get u1 #99”,意思和第一个执行含义一样,只不过“get u1 N”中第三个参数“N”表示从这个key的value值的第0位开始,往后偏移N位比特位;而“get u1 #N”中第三个参数“#N”表示从这个key的value值的第0位开始,往后偏移“N乘1(第二个参数表示的长度)”位比特位。 
复制代码

需求运用:

可以查看一个用户连续几天,或者一个周期内所有天的签到状态,由此可以得到连续目前连续签到多少天,周期内最大连续签到多少天。

猜你喜欢

转载自juejin.im/post/7079605753094340616