一、Bitmaps概述和常用命令

Redis提供的Bitmaps这个“数据结构”可以实现对位的操作。Bitmaps本身不是一种数据结构,实际上就是字符串,但是它可以对字符串的位进行操作。

可以把Bitmaps想象成一个以位为单位数组,数组中的每个单元只能存0或者1,数组的下标在bitmaps中叫做偏移量。单个bitmaps的最大长度是512MB,即2^32个比特位。

bitmaps最大的优势是在存储数据时可以极大的节省空间,比如在一个项目中采用自增长的id来标识用户,就可以仅用512M的内存来记录4亿用户的信息(比如用户是否希望收到新的通知,用1和0标识)

redis bitmap 数据量 redis bitmap性能_redis bitmap 数据量


位数组的顺序和平时书写的顺序时完全相反的,比如b用二进制表示01100010,0位是最右端的1而Redis二进制0位是左端的0。

bitmaps适用于进行快速、简单、实时统计,包括独立访客,日活用户的统计,并且bitmaps极其节省空间。

getbit与setbit实现

01100010 b

01101001 i

01100111 g

设置值:setbit key < offset > < value >
例如:setbit bit 9 0 ,就会将第二个字节i 的第二位 1 设置成 0

  1. 计算所需位数组长度,len=(offset / 8)+1,len记录了保存offset指定的二进制位至少需要多少字节
  2. 检查key保存的位数组长度是否小于len,小于则扩展字符串长度位len字节,并将扩展的二进制位的值设置位0
  3. 计算byte = offset / 8,该值记录了offset偏移量指定的二进制位保存在位数组的哪个字节
  4. 计算bit = (offset mod 8)+1,bit值记录了offset偏移量指定的二进制位是byte字节的第几个二进制位。
  5. 根据byte与bit设置位数组中指定的二进制位的值。
  6. 向客户端返回原值

获取值:getbit key < offset >
例如:getbit bit 9 ,就会返回第二个字节i 的第二位 1

  1. 计算byte = offset / 8,该值记录了offset偏移量指定的二进制位保存在位数组的哪个字节。
  2. 计算bit = (offset mod 8)+1,bit值记录了offset偏移量指定的二进制位是byte字节的第几个二进制位。根据byte与bit返回位数组中指定的二进制位的值。

获取Bitmaps指定范围值为1的个数:bitcount key
bitcount key [start][end]

Bitmaps间的运算 :bitop
bitop or destkey key[key…]
bitop是一个复合操作,它可以做多个Bitmaps的and(交集)、or(并集)、not(非)、xor(异或)操作并将结果保存在destkey中。

计算Bitmaps中第一个值为targetBit的偏移量:bitpos
bitpos key targetBit [start] [end]
bitops有两个选项[start]和[end],分别代表起始字节和结束字节,返回字符串里面第一个被设置为1或者0的bit位。

二、实现页面的每日访问

当记录的活跃用户数占总数的比例高的时候,bitmaps相比集合类型要节省非常多的内存,但是如果每天的活跃用户数很少,则bitmaps并不试用。如果某应用拥有1亿用户,每日活跃用户数在5000W。

redis bitmap 数据量 redis bitmap性能_redis bitmap 数据量_02


redis bitmap 数据量 redis bitmap性能_偏移量_03


mysql 实现每日页面访问:

常见一张统计表,将每日登陆的用户id存储起来,关联用户的主键id (user_id)可能还要保存登陆ip,登陆时间等,t_user 中主键为自增,那么它的id最大值为1E,分配的内存为8字节 64位。那么每天的数据大小为:
5000W * 8K = 400M
使用Redis - Bitmaps 实现
解决方案:

  • 我们将每天访问网站的用户存储在一个bitmaps中,通过日期生成键,例如:unique:users:2017-07-11,这样我们就可以统计每天的用户访问情况,用户访问后,setbit key < offset > < value >,只需要将offset 对应为user_id,value 设置为 1 ,一个用户对应 1位 。原本的mysql 64 位保存一个id,现在就节省特别大的空间。 通过bitmaps的与或运算等功能统计出一个时间段内的活跃用户及连续N天访问网站用户等相关需求。
    10000000 / 8 = 12500000 K = 11.9 MB
  • 获取哪个用户是否登录 , 直接getbit 对应的user_id ,返回值是否为 1
  • 连续登录,获取每天保存的Bitmaps交集
    bitop and destkey key[key…]