前几天咱们介绍了Redis基本架构和简单应用,后续笔者还会进行更多的Redis应用和原理剖析,争取每天和朋友们进步一点点,充实自我。
今天,笔者继续带来Redis应用实战——位图和HyperLogLog
应用三:节衣缩食——位图
在我们平时开发过程中,会有一些bool 型数据需要存取,比如用户一年的签到记录,签了是1,没签是0,要记录365天。如果使用普通的key/value, 每个用户要记录365个,当用户上亿的时候,需要的存储空间是惊人的。
为了解决这个问题,Redis 提供了位图数据结构,这样每天的签到记录只占据一一个位,365天就是365个位,46个字节(一个稍长一点的字符串)就可以完全容纳下,这就大大节约了存储空间。
位图不是特殊的数据结构,它的内容其实就是普通的字符串,也就是 byte 数组。我们 可以使用普通的 get/set 直接获取和设置整个位图的内容,也可以使用位图操作 getbit/setbit 等将 byte 数组看成「位数组」来处理。 以老钱的经验,在面试中有 Redis 位图使用经验的同学很少,如果你对 Redis 的位图有 所了解,它将会是你的面试加分项。
基本使用
Redis的位数组是自动扩展,如果设置了某个偏移位置超出了现有的内容范围,就会自 动将位数组进行零充。 接下来我们使用位操作将字符串设置为 hello (不是直接使用 set 指令),首先我们需要得到 hello 的 ASCII 码,用 Python 命令行可以很方便地得到每个字符的 ASCII 码的二进制值。
>>> bin(ord('h'))
'0b1101000' # 高位 -> 低位
>>> bin(ord('e'))
'0b1100101'
>>> bin(ord('l'))
'0b1101100'
>>> bin(ord('l'))
'0b1101100'
>>> bin(ord('o'))
'0b1101111'
接下来我们使用 redis-cli 设置第一个字符,也就是位数组的前 8 位,我们只需要设置值为 1 的位,如上图所示,h 字符只有 1/2/4 位需要设置,e 字符只有 9/10/13/15 位需要 设置。值得注意的是位数组的顺序和字符的位顺序是相反的。
127.0.0.1:6379> setbit s 1 1
(integer) 0
127.0.0.1:6379> setbit s 2 1
(integer) 0
127.0.0.1:6379> setbit s 4 1
(integer) 0
127.0.0.1:6379> setbit s 9 1
(integer) 0
127.0.0.1:6379> setbit s 10 1
(integer) 0
127.0.0.1:6379> setbit s 13 1
(integer) 0
127.0.0.1:6379> setbit s 15