redis的其它模块:队列、位图、HyperLogLog、布隆过滤器、GeoHash
延时队列
实现队列的一种简单的方式:用zset,其中的score就是剩余时间。
还有一种实现简单队列的方式就是用redis中的list,可以用阻塞读命令blpop、brpop,这样在读不到数据时就会立即进入休眠状态,然后一旦有数据就会醒过来,降低延迟。如果用普通的命令rpush、lpush、lpop、rpop,取不到数据时应该手动设置休眠。注意如果一个读线程一直为空,那么redis连接就成了闲置链接,此时读会抛出异常,注意捕获异常及时重试。
stream
它是一个支持多播的可持久化消息队列。
位图
位图的本质是byte数组,是字符串,用它来存储可以大大节约空间,比如一个用户一年的签到记录,就可以用365位来表示。对于统计月活用户来说,要实现自动去重。
要实现hello这个字符串,首先要把每个字母的二进制表示出来,然后将其倒置排列成一个完整的位图,计算位置开始设置:(比如h是01101000 e是01100101,那么he就是01101000 + 01100101)需要第1/2/4、。。位设置为1
设置某位:setbit 键 1 1(把第1位设置为1)
取某位:getbit 键 1(取第一位)
整取:get 键(如果组合出来是不可打印字符,就会显示该字符的16进制)
整存:set 键 值
位图统计指令:
bitcount是用来统计指定范围内1的个数:
bitcount 键 0 2 (前3个字符中1的个数,注意是字符不是字节)
bitpos查找指定范围内第一个1或0的位置:
bitpos 键 1 2 2 (从第3个字符算起,第一个1的位置)
bitfield可以用来一次性取多位设置多位
bifield结合incrby还可以指定多位自增,自增会有溢出的情况,默认是折返(将溢出位丢掉)、还可以选择失败策略(溢出不执行)、饱和截断(超过范围停留在最大最小值)
HyperLogLog
对于这样一个问题:统计一个网站的访问用户数据,因为用户要去重所以要用set,但是如果是千万级的用户量,用set是非常浪费空间的,但是这个统计数据又不要求绝对精确,这时就可以使用hyperloglog,它有去重功能,统计标准误差只有不到1%,却可以节省大量空间,hyperloglog只需要12k的内存。
pfadd 键 值(存值)
pfcount 键(取出统计个数)
pfmerge 键 键(合并两个集合)
hyperloglog基于的统计原理是:给定一系列随机整数,记录下低位连续0位的最大长度k,通过k值可以估算出随机数的数量。该结构通过大量统计进行加权估计来保证得到一个比较精确的值。对单一的桶来说,这种估计不准确,对大量的桶并加权来说会准确。在结构中记录比较少时大多数桶的值都是0,此时就会采用稀疏存储节约空间,当多起来就会采用密集存储,也就是12k。
pfcount的复杂度是平均O1的,它会缓存计算结果,如果一个记录调用可能改变计算结果时,刷新也不会立即发生,只有调用pfcount命令时才会计算,当稀疏存储时刷新会比较快,密集存储比较慢,但另一个方面,密集存储时这个值很大,大多数记录的存入不会导致该值发生变化。
布隆过滤器
新闻推送时,不能向用户推送相同的内容,此时就要存储一个用户历史看过的记录,这个记录是非常庞大的,而需求只需要知道出现过还是没出现过就行了,此时就可以使用布隆过滤器,布隆过滤器不会误判已经出现的内容没有出现,但是有一定几率误判没有出现的内容出现了。
bf.add 键 值
bf.exists 键 值
bf.madd 键 多个值(add多个)
bf.mexists 键 多个值(判断多个)
GeoHash
如果有一条数据分别有三个字段:key、经度、维度,如何求这个key附近的key?可以用数据库sql,假定一个r用where来限定查询,如果不满意就增大r,但是数据库的性能很有限。
这时就要用GeoHash算法,这个算法首先将经度和维度映射成一个数字,类似如果切两下蛋糕就会切出4块来一样,可以把每一块命名为00/01/10/11,这个数字也可以按照某个规则还原回经度维度,原来在二维平面上靠近的点数字依然接近,块划得越细越精确,存在一定的误差。redis在进行Geo排序时将这些数字放进一个zset中,通过其排序功能就能得到附近的元素。redis的Geo命令可以添加点,计算点之间的位置,计算附近的点。