Redis - HyperLogLog

Redis - HyperLogLog

Redis 在2.8.9版本添加了 HyperLogLog 结构

在介绍HyperLogLog之前,我们先思考一个常见的业务问题:如果开发一个大型网站,要记录每个网页每天的UV数据,我们应该如何实现呢?

如果统计PV那非常容易,给每个网页一个独立的Redis计数器就可以了,这个计数器的key后缀加上当天的日期。这样来一个请求,incrby一次,最终就可以统计出所有的PV数据。但是UV不一样,它要去重,也许我们可以想到一个简单的方案,为每个网页创建一个set集合来存储当天访问过此页面的用户ID。但是如果我们的页面非常巨大,比如一个爆款页面几千万的UV,需要一个很大的set集合来统计,这样就非常浪费空间了。

Redis提供了 HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。

在Redis里面,每个 HyperLogLog 键只需要花费 12 KB内存,就可以计算接近2^64个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

使用方法

HyperLogLog 提供了两个指令 pfadd 和 pfcount, 一个是增加计数,一个是获取计数。pfadd 用法和 set 集合的 sadd 是一样的,来一个用户ID,就将用户ID塞进去就是。pfcount 和 scard 用法是一样的,直接获取计数值。

添加数据


pfadd key element [element ...]
  • 添加指定元素到 HyperLogLog 中。

统计数据

pfcount key [key ...]
  • 返回给定 HyperLogLog 的基数估算值。

合并数据

pfmerge destkey sourcekey [sourcekey...]
  • 将多个 HyperLogLog 合并为一个 HyperLogLog
127.0.0.1:6379> pfadd hll1 foo bar zap a
(integer) 1
127.0.0.1:6379> pfadd hll2 a b c
(integer) 1
127.0.0.1:6379> pfmerge hll2 hll1 hll
OK
127.0.0.1:6379> pfcount hll1
(integer) 4
127.0.0.1:6379> pfcount hll2
(integer) 7
127.0.0.1:6379> 

说明:

  • 用于进行基数统计,不是集合,不保存数据,只记录数量而不是具体数据
  • 核心是基数估算算法,最终数值存在一定误差
  • 误差范围:基数估计的结果是一个带有 0.81% 标准错误的近似值
  • 耗空间极小,每个hyperloglog key占用了12K的内存用于标记基数
  • pfadd命令不是一次性一次性分配12K内存使用,会随着基数的增加内存逐渐增大
  • Pfmerge命令合并后占用的存储空间为12K,无论合并之前数据量多少

计算用户uv

127.0.0.1:6379> pfadd uv user1
(integer) 1
127.0.0.1:6379> pfadd uv user2
(integer) 1
127.0.0.1:6379> pfadd uv user3
(integer) 1
127.0.0.1:6379> pfcount uv
(integer) 3
127.0.0.1:6379> pfadd uv user3
(integer) 0
127.0.0.1:6379> pfcount uv
(integer) 3
127.0.0.1:6379> pfadd uv user4 user5 user5
(integer) 1
127.0.0.1:6379> pfcount uv
(integer) 5

pfadd的pf是什么意思

它是 HyperLogLog这个数据结构的发明人 Philippe Flajolet 的首字母缩写,老师觉的他发型很酷,卡起来是个佛系教授

pfmerge 适合什么场合用

HyperLogLog 除了上面的 pfadd 和 pfcount 之外,还提供了第三个指令 pfmerge,用于将多个 pf 计数值累加在一起形成一个新的 pf 值。

比如网站中我们有两个内容差不多的页面,运营说需要这两个页面的数据进行合并。其中页面的UV访问量也需要合并 pfmerge 就可以派上用场了。

注意事项

HyperLogLog 这个数据结构不是免费的,不是说使用这个数据结构要花钱,它需要占据一定 12k 的存储空间,所以它不适合统计单个用户相关的数据。如果你的用户上亿,可以算算,这个空间成本是非常惊人的。但是相比 set 存储方案,HyperLogLog 所使用的空间那真是可以使用千斤对比四两来形容了。

不过不要过于担心,因为 Redis 对 HyperLogLog 的存储进行了优化,在计数比较小时,它的存储空间采用稀疏矩阵存储,空间占用很小,仅仅在计数慢慢变大,稀疏矩阵占用空间渐渐超过了阈值时才会一次性转变成稠密矩阵,才会占用 12k 的空间。

HyperLogLog 实现原理

请添加图片描述

这张图的意思是,给定一系列的随机整数,我们记录下低位连续零位的最大长度k,通过这个k值可以估算出随机数的数量

pf的内存占用为什么是12k

算法中使用了1024个桶进行独立计数,不过在 Redis 的 HyperLogLog实现中用到的是 16384个桶,也就是 2^14,每个桶的 maxbits 需要6个 bits 来存储,最大可以表示 maxbts=63,于是总共占用内存就是 2^14 * 6 / 8 = 12k 字节。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值