1 bitmap简介
现代计算机都是用二进制(位)作为信息的基础,1个字节=8位,如big有2个字符组成,对应的ASCII值分别是98、105、103、对应的二进制分别是01100010、01101001、01100111,如下图
b i g
01100010 01101001 01100111
bitmap本身并不是数据结构,实际上就是字符串,但是它可以对字符串的位进行操作,可以把bitmap想象成一个以bit为单位的数组,数组每个单元只存储0、1,数组的下标叫bitmap的偏移量
bitmap最大支持2^32位,字符串最大512M,每个字节8位,所以bitmap最大支持长度为:8 * 1021 * 1024 * 512,约42亿
2 常用命令
下面以用户登录在某天登录来介绍
2.1 设置值
setbit key offset value
假如有20个用户,0、5、11、15、19在当天对网站进行了访问,执行如下命令
127.0.0.1:6379> setbit user:login:2020-08-30 0 1
(integer) 0
127.0.0.1:6379> setbit user:login:2020-08-30 5 1
(integer) 0
127.0.0.1:6379> setbit user:login:2020-08-30 11 1
(integer) 0
127.0.0.1:6379> setbit user:login:2020-08-30 15 1
(integer) 0
127.0.0.1:6379> setbit user:login:2020-08-30 19 1
(integer) 0
2.2 获取值
2.2.1 获取某个位上的值
getbit key offset
获取0号用户和8号用户在2020-08-30这天是否访问过
127.0.0.1:6379> getbit user:login:2020-08-30 0
(integer) 1
127.0.0.1:6379> getbit user:login:2020-08-30 8
(integer) 0
2.2.2 获取指定范围内个数为1的值
bitcount key [start end]
start:位的开始字节
end:位的截止字节
统计2020-08-30这天所有登录人数
127.0.0.1:6379> bitcount user:login:2020-08-30
(integer) 5
查询前前16名用户在2020-08-30这天登录人数
127.0.0.1:6379> bitcount user:login:2020-08-30 0 1
(integer) 4
2.3 bitmap间运算
假如1、2、5、15四个用户在2020-08-31这天进行访问
127.0.0.1:6379> setbit user:login:2020-08-31 1 1
(integer) 0
127.0.0.1:6379> setbit user:login:2020-08-31 2 1
(integer) 0
127.0.0.1:6379> setbit user:login:2020-08-31 5 1
(integer) 0
127.0.0.1:6379> setbit user:login:2020-08-31 15 1
bitmap间预算:bitop operation destkey key [key ...]
operation:操作名称,and(交集)、or(并集)、not(非)、xor(异或),并将结果保存在中
destkey:操作结果存储在destkey中
与运算:计算这两天都访问过网站的用户数
127.0.0.1:6379> bitop and user:login:2020-08-30and2020-08-31 user:login:2020-08-30 user:login:2020-08-31
(integer) 3
127.0.0.1:6379> bitcount user:login:2020-08-30and2020-08-31
(integer) 2
或运算:计算两天访问过网站的用户总数
127.0.0.1:6379> bitop or user:login:2020-08-30or2020-08-31 user:login:2020-08-30 user:login:2020-08-31
(integer) 3
127.0.0.1:6379> bitcount user:login:2020-08-30or2020-08-31
(integer) 7
2.4 计算bitmap中第一个值是targetBit的偏移量
bitpos key bit [start] [end]
key:键
bit:目标bit值
start:位的开始字节
end:位的截止字节
查看2020-08-30这天访问网站的最小用户id
127.0.0.1:6379> bitpos user:login:2020-08-30 1
(integer) 0
3 bitmap节省空间量
假设网站有1亿用户,每天访问用户量5000w,如果每天用集合类型和bitmap来存储访问用户可以得到如下统计
数据类型 每个用户id占用空间 需要存储用户量 全部内存量
集合类型 64位 5000w 64bit * 50000000 = 400MB
bitmap 1位 1亿 1bit * 100000000 = 12.5MB
可以看到bitmap来统计可以节省大量内存
4 最佳实践
4.1 很多应用用户id以一个指定的数字开头,直接用id作为偏移量会造成一定的浪费,通常做法是将用户id减去一个数值来作为偏移量。第一次初始化bitmap的时候,如果偏移量太大,那么初始化过程会比较慢,造成redis阻塞
4.2 如果统计数据过少,就没有必要用bitmap来存储了,同样1亿用户量,bitmap固定占用12.5MB内存,但是集合内存占用和用户量成正比