redis 基本命令--位图
1.业务背景
现有一个业务需求,需要从一批很大的用户活跃数据(2亿+)中判断用户是否是活跃用户。
2. 存在的挑战
- 海量数据如何尽可能用小的空间存储
- 如何能快速获取指定的数据
- 如何能快速的写入到目标存储
3.解决思路
这里使用redis的位操作来处理。
redis中所有数据都是二进制形式存储的。redis支持一个setbit和getbit操作,它支持在某个key的value上直接对某个二进制位操作,每个二进制位都只有0和1两种状态,正好可以表示用户是否活跃两种状态。
比如redis中键a的value数据的二进制码是
0110 0110 0001
它总共有12位,在redis的位操作中,二进制中的第几位称为offset。
我们可以这样将这个数据的第10个二进制位为1:
setbit a 10 1
这样,原来的数据就变成了
0110 0110 0101
那么我们考虑在redis中放一个key,它的value很大很大,大到它的二级制位数大于最大的用户id,redis中单个key的最大值是512M,可以达到40多亿bit,足够很多业务的需要了,我们以用户id作为offset,该offset的值作为是否活跃的值即可达到我们的目的。这样只需要一个key就能解决对所有数据的查询问题。假设我们的id最大值是1亿,那么我们需要一亿个bit就行了,相当于只需要1亿/(81024*1024)=11.9M内存。这里大家了解下二进制就能理解。
具体操作:
写入一个key,值是一亿个bit,足够容纳你的数据中最大offset就行,假如这个key的名称是a.
然后写入数据
//用户id123456是活跃用户
setbit a 123456 1
//用户id234567不是活跃用户
setbit a 234567 0
getbit a 123456
这样完美解决了存储和访问的问题!
4. 位图值如何写入
接下来还要解决数据写入问题,这么多数据要怎样快速写入呢?使用redis官方提供的方式,将数据转成redis协议格式,使用redis-cli提供的pipe模式写入。 一个命令的例子: *4 6setbit6setbit9 is_active 312331231 1 上面*4表示这个命令总共有四个参数: (数据表示下面的参数的字节数量,一个参数对应一个) 以换行结尾,注意,换行必须是\r\n,linux中需要转换。 得到redis协议格式的文本后,使用redis-clie执行