Redis数据类型之bimap详解
- bitmap简介
- bitmap常用操作
- 应用场景
- 源码阅读
- 布隆过滤器
- 图解布隆过滤器
bitmap简介
bitmap 在Redis 中又叫 bitops ,它就是通过一个bit位来表示某个元素对应的值或者状态。
bitmap 的实现在Redis中其实并没有去新增加一个数据类型,它的底层实现其实就是一个 String也就是一个char buf[]
。而大家要知道1Byte = 8bit,所以这个数组中每一个下标对应8个元素的状态。
bitmap 其中的key也就是元素,key只能为>=0的整数
则可以当成基于bit位的 偏移量 Redis中 我们可以叫它 offset
,所以它们就像数组的下标一样不需要额外的空间保存,每一次getbit/setbit都可以当做是对数组下标所对应的值的一次操作,所以bitmap本身会极大的节省储存空间。
- 优点
- 节省空间
- 效率高
setbit和getbit的时间复杂度都是O(1),其他位运算效率也高
- 缺点
- 本质上位只有0和1的区别,所以一般只能用于状态记录
- 对于需要统计的key的数量不大,但key与key之前跨度较大的场景不适用
bitmap常用操作
- SETBIT key offset value :设置或修改key上的偏移量(offset)的位(value)的值;
return的不是成功失败状态,而是所修改的偏移量上原来存储的旧的值
- GETBIT key offset :返回指定key上偏移量(offset)的值,若key不存在,那么返回0;
- BITCOUNT key :返回指定key上被bit位被设置为 1 的数量;
- BITOP operation destkey key [key …] :
- BITOP and destkey key [key …] :对一个或多个key逻辑并,结果保存到destkey;
- BITOP or destkey key [key …] :对一个或多个key逻辑或,结果保存到destkey;
- BITOP xor destkey key [key …] :对一个或多个key逻辑异或,结果保存到destkey;
- BITOP not destkey key :对一个key逻辑非,结果保存到destkey;
注意哦 NOT操作时,key只能有一个
应用场景
- 各种用户活跃/登录统计
- 广播消息用户已读未读标记
源码阅读
因为 bitmap 并不是一个新的数据类型,其表现形式是一个 char buf[],所以咱们拿setbit的源码出来看看吧
/*
* 找到要设置的字节的目标位,然后记录下原来的该位的值,最后把该位设置为目标值
* GETBIT命令与其实现思路一致
*/
void setbitCommand(client *c) {
robj *o;
char *err = "bit is not an integer or out of range";
size_t bitoffset;
ssize_t byte, bit;
int byteval, bitval;
long on;
// 解析 offset
if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset,0,0) != C_OK)
return;
// 解析 value
if (getLongFromObjectOrReply(c,c->argv[3],&on,err) != C_OK)
return;
/* bit 位 只能是 0 / 1 否则直接返回失败 */
if (on & ~1) {
addReplyError(c,err);
return;
}
/*
* 查找字符串对象
* 如不存在则创建字符串对象
* 如字符串存在但空间不足则扩容
*/
if ((o = lookupStringForBitCommand(c,bitoffset)) == NULL) return;
/*
* 计算元素所对应的字节位置(因为上面说过 1byte = 8bit)
* 位运算bitoffset >> 3 相当于 bitoffset / 8
*/
byte = bitoffset >> 3;
// 获取对应的字节
byteval = ((uint8_t*)o->ptr)[byte];
// 算出 bit 的位置(基于当前字节)
bit = 7 - (bitoffset & 0x7);
// 获得bit旧值用于操作成功后的return
bitval = byteval & (1 << bit);
/* 更新字节中的位,并设置它的值 */
byteval &= ~(1 << bit);
byteval |= ((on & 0x1) << bit);
((uint8_t*)o->ptr)[byte] = byteval;
// 发送修改通知
signalModifiedKey(c,c->db,c->argv[1]);
notifyKeyspaceEvent(NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
server.dirty++;
// 向客户端返回旧的值
addReply(c, bitval ? shared.cone : shared.czero);
}
布隆过滤器
布隆过滤器(Bloom Filter)是由Howard Bloom在1970年提出的一种比较巧妙的概率型数据结构,它可以告诉你某种东西 一定不存 在或者 可能存在 。当布隆过滤器说,某种东西存在时,这种东西可能不存在;当布隆过滤器说,某种东西不存在时,那么这种东西一定不存在。
而布隆过滤器便是基于 bitmap 实现的。
布隆过滤器的核心便是将key进行 n 次不同的 hash运算,得到n个不同的hash值,然后以hash值为 偏移量(offset) ,在bitmap中将偏移量(offset)对应的值进行标记为1。任何key进入判断是否存在时都会通过那些hash函数计算出对应的n个hash值,然后去判断hash值对应的 **偏移量(offset)**的value 是否全部等于1。如果有任何一个值为0,则该Key一定不存在;否则该Key可能存在。
图解布隆过滤器
看看布隆过滤器如何解决 缓存穿透 问题。
你的点赞就是我创作的最大动力,如果写的不错,来个三连行不行