原文:巧用redis位图存储亿级数据与访问 - 简书

业务背景

现有一个业务需求,需要从一批很大的用户活跃数据(2亿+)中判断用户是否是活跃用户。由于此数据是基于用户的各种行为日志清洗才能得到,数据部门不能提供实时接口,只能提供包含用户及是否活跃的指定格式的文本由业务方使用。

存在的挑战

  1. 海量数据如何尽可能用小的空间存储
  2. 如何能快速获取指定的数据
  3. 如何能快速的写入到目标存储

解决思路

  1. 由于我的业务中只需要根据某个用户id查询是否是活跃用户,不存在复杂的查询条件,所以用redis很合适。

  2. 如此大的数据如果用普通的键值对一一存储所有用户的活跃数据,即使每个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

如果key不存在,也会自动创建。

当然,如果某个位还不存在,redis也会自动填充。

可以通过getbit获取某个二进制位的值

getbit a 10 //获取键a的值上第10位的值(0或1两种状态)

这是所谓的位图。

那么我们考虑在redis中放一个key,通过这个key直接操作二进制位,redis中单个key的最大值是512M,可以达到40多亿bit,足够很多业务的需要了。我们以用户id作为offset,该offset的值作为是否活跃的值即可达到我们的目的。这样只需要一个key就能解决对所有数据的查询问题。假设我们的id最大值是1亿,那么我们需要一亿个bit就行了,相当于只需要1亿/(810241024)=11.9M内存。这里大家了解下二进制就能理解。

//用户id123456是活跃用户
setbit a 123456 1
//用户id234567不是活跃用户
setbit a 234567 0

getbit a 123456

具体操作:

循环所有id列表,id作为offset,通过setbit写入该id是否活跃。

查询时,调用getbit a 123456即可

这样完美解决了存储和访问的问题!

  1. 接下来还要解决数据写入问题,这么多数据要怎样快速写入呢?使用redis官方提供的方式,将数据转成redis协议格式,使用redis-cli提供的pipe模式写入。
    一个命令的例子:
*4
$6
setbit
$9
is_active
$3
123
$1
1

上面*4表示这个命令总共有四个参数:
$数据表示下面的参数的字节数量,一个参数对应一个$
以换行结尾,注意,换行必须是\r\n,linux中需要转换。
得到redis协议格式的文本后,使用redis-cli执行。

cat data.txt|redis-cli  --pipe

巧用redis位图存储亿级数据与访问 - 简书的更多相关文章

  1. 巧用redis位图存储亿级数据与访问

    业务背景 现有一个业务需求,需要从一批很大的用户活跃数据(2亿+)中判断用户是否是活跃用户.由于此数据是基于用户的各种行为日志清洗才能得到,数据部门不能提供实时接口,只能提供包含用户及是否活跃的指定格 ...

  2. 分布式数据库中间件Mycat百亿级数据存储(转)

    此文转自: https://www.jianshu.com/p/9f1347ef75dd 2013年阿里的Cobar在社区使用过程中发现存在一些比较严重的问题,如高并发下的假死,心跳连接的故障,只实现 ...

  3. 基于Redis位图实现系统用户登录统计

    项目需求,试着写了一个简单登录统计,基本功能都实现了,日志数据量小.具体性能没有进行测试~ 记录下开发过程与代码,留着以后改进! 1. 需求 1. 实现记录用户哪天进行了登录,每天只记录是否登录过,重 ...

  4. Redis位图法记录在线用户的状态

    Redis位图法记录在线用户的状态 位图 Redis官方文档对于位图的介绍如下: 位图不是一个真实的数据类型,而是定义在字符串类型上的面向位的操作的集合.由于字符串类型是二进制安全的二进制大对象,并且 ...

  5. 通用技术 mysql 亿级数据优化

    通用技术 mysql 亿级数据优化 一定要正确设计索引 一定要避免SQL语句全表扫描,所以SQL一定要走索引(如:一切的 > < != 等等之类的写法都会导致全表扫描) 一定要避免 lim ...

  6. Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  7. 基于Redis位图实现用户签到功能

    场景需求 适用场景如签到送积分.签到领取奖励等,大致需求如下: 签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等. 如果连续签到中断,则重置计数,每月初重置计数. 当月签到满 ...

  8. 基于Mysql数据库亿级数据下的分库分表方案

    移动互联网时代,海量的用户数据每天都在产生,基于用户使用数据的用户行为分析等这样的分析,都需要依靠数据都统计和分析,当数据量小时,问题没有暴露出来,数据库方面的优化显得不太重要,一旦数据量越来越大时, ...

  9. Mongodb亿级数据量的性能测试

    进行了一下Mongodb亿级数据量的性能测试,分别测试如下几个项目:   (所有插入都是单线程进行,所有读取都是多线程进行) 1) 普通插入性能 (插入的数据每条大约在1KB左右) 2) 批量插入性能 ...

随机推荐

  1. 洛谷——P2515 [HAOI2010]软件安装

    https://www.luogu.org/problem/show?pid=2515#sub 题目描述 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中 ...

  2. Altium Designer如何调整鼠标形状

    在 里面有一个

  3. JS里的函数的call()与back()方法

    function cat(){} cat.prototype={ food:"fish", say: function(){ alert("I love "+t ...

  4. 【转】排列组合 "n个球放入m个盒子m"问题 总结

    出处:https://blog.csdn.net/qwb492859377/article/details/50654627 球,盒子都可以分成是否不能区分,和能区分,还能分成是否能有空箱子,所以一共 ...

  5. 算法 Tricks(六)— if 条件分支的简化

    考虑下面的三分支的定义式: f=⎧⎩⎨⎪⎪a,b,a+b,x>yx<yx=y int f = 0; if (x >= y) f += a; if (x <= y) f += b ...

  6. 使用GDB进行嵌入式远程调试

    PC主机:Ubuntu 10.4 目标板:TQ2440开发板,linux内核2.6.30 NOTE:为了使用gdb进行调试,强烈建议使用nfs服务,否则调试会非常麻烦. 使用nfs服务可以参考:S3C ...

  7. 关于Altium Designer的一些设置

    把原理图设置成A4纸张,是为了便于打印机打印出原理图来 原理图一定一定要和pcb图保持一致,这样是为了以后查找错误方便...

  8. MFC屏蔽 WindowS按键

    LRESULT CALLBACK LowLevelKeyboardPorc(int nCode,WPARAM wParam,LPARAM lParam)//屏蔽按键的真正实现方法{ BOOL fEat ...

  9. 微服务API模拟框架frock介绍

    本文来源于我在InfoQ中文站翻译的文章,原文地址是:http://www.infoq.com/cn/news/2016/02/introducing-frock Urban Airship是一家帮助 ...

  10. [Angular] Test Container component with async provider

    The main idea for testing contianer component is to make sure it setup everythings correctlly. Call ...