PS:向公众号发送关键字可以搜索文章哦!
业务背景
现有一个业务需求,需要从一批很大的用户活跃数据(2亿+)中判断用户是否是活跃用户。由于此数据是基于用户的各种行为日志清洗才能得到,数据部门不能提供实时接口,只能提供包含用户及是否活跃的指定格式的文本由业务方使用。
存在的挑战
海量数据如何尽可能用小的空间存储
如何能快速获取指定的数据
如何能快速的写入到目标存储
解决思路
由于我的业务中只需要根据某个用户id查询是否是活跃用户,不存在复杂的查询条件,所以用redis很合适。
如此大的数据如果用普通的键值对一一存储所以用户的活跃数据,即使每个key/value占用的内存很小,但数亿个key/value所花费的内存也每个节点随便都需要数G,业务中有很多类似的需求,都用这种方式的话,存储是个很大的问题。
这里使用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亿/(8*1024*1024)=11.9M内存。这里大家了解下二进制就能理解。
具体操作:
写入一个key,值是一亿个bit,足够容纳你的数据中最大offset就行,假如这个key的名称是a。
然后写入数据
//用户id123456是活跃用户
setbit a 123456 1
//用户id234567不是活跃用户
setbit a 234567 0
getbit a 123456
这样完美解决了存储和访问的问题!
接下来还要解决数据写入问题,这么多数据要怎样快速写入呢?使用redis官方提供的方式,将数据转成redis协议格式,使用redis-cli提供的pipe模式写入。
一个命令的例子:*4$6setbit $9is_active $3123$11
复制上面*4表示这个命令总共有四个参数:
$数据表示下面的参数的字节数量,一个参数对应一个$
以换行结尾,注意,换行必须是\r\n,linux中需要转换。
得到redis协议格式的文本后,使用redis-clie执行。
cat data.txt|redis-cli --pipe
@不迷失|知识改善生活
微信公众号:java技术
专注技术研究与视频教学,分享有价值的技术与经验,关注程序员的发展!
技术博客:http://bumishi.cn
技术交流群:245130488
@不迷失教学视频
腾讯课堂:http://bumishi.ke.qq.com
百度课堂:http://chuanke.com/s3377987.html
推荐阅读