zoukankan      html  css  js  c++  java
  • 巧用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表示这个命令总共有四个参数:
    $数据表示下面的参数的字节数量,一个参数对应一个$
    以换行结尾,注意,换行必须是 ,linux中需要转换。
    得到redis协议格式的文本后,使用redis-cli执行。

    cat data.txt|redis-cli  --pipe
    

     

  • 相关阅读:
    Vim快捷键键位图大全
    Docker快速入门
    针对base64编码和URIEncode的一点研究
    JavaEE初学笔记之Servlet与Tomcat
    【编码】彻底弄懂ASCII、Unicode、UTF-8之间的关系
    React的世界观及与Vue之比较
    彻底搞懂CSS文本、空白换行问题
    Vue实现懒加载的基本思路
    CSS中的px与物理像素、逻辑像素、1px边框问题
    Vue插值文本换行问题
  • 原文地址:https://www.cnblogs.com/williamjie/p/9486086.html
Copyright © 2011-2022 走看看