适用版本:Redis 7.2.x
一、什么是 HyperLogLog
HyperLogLog,简称 HLL,是 Redis 提供的一种 近似去重计数 结构。它的核心用途不是保存具体数据,而是回答这样一个问题:
“这一批数据里,大约有多少个不重复的元素?”
例如:
- 今天网站大约有多少独立访客(UV)
- 某个活动页一周内大约触达了多少独立用户
- 某个业务线近 30 天大约有多少去重设备
这里的关键词是:
- 去重:重复元素只算一次
- 计数:只关心数量,不关心具体是谁
- 近似:结果不是百分之百精确,而是有可接受误差
HyperLogLog 最大的价值在于:用非常小且相对固定的内存,完成海量数据的去重计数。
二、为什么需要 HyperLogLog
如果要做去重计数,很多人第一反应是用 Set:
SADD uv:20260609 user1 user2 user3
SCARD uv:20260609
这样当然可以,而且结果精确。但问题在于:
- 去重用户越多,Set 占用内存越大
- 如果每天几百万、几千万独立用户,内存成本会很高
- 如果还要做周 UV、月 UV、活动 UV,多维度累计后成本更明显
而 HyperLogLog 的设计目标就是:
- 不保存元素本身
- 只保留用于估算基数的信息
- 牺牲少量精度,换取极高的空间效率
在 Redis 中,一个 HyperLogLog 通常只需要 很小的固定级别内存,却能统计非常大的基数规模。
三、HyperLogLog 的核心原理
HyperLogLog 背后的算法思想比较巧妙,初学时不需要陷入复杂数学细节,但要理解它的大方向。
1. 先做哈希
无论输入的是用户 ID、手机号、设备号还是订单号,Redis 都会先对元素做哈希处理,把它映射成一个足够均匀的二进制值。
例如:
user_1001 -> 1010010110...
user_1002 -> 0000011011...
哈希的目的,是让不同元素尽可能均匀分布,便于后续估算。
2. 观察“前导零”分布
HyperLogLog 的一个关键思想是:
- 随机哈希值中,前导零越多的情况越少见
- 如果我们在大量数据中看到了很长的前导零,说明样本量可能已经很大
比如:
- 看到前导零长度为 1,很常见
- 看到前导零长度为 10,概率已经很小
- 看到前导零长度为 20,说明样本规模通常更大
3. 分桶记录局部最大值
为了让估算更稳定,HyperLogLog 不会只看一个整体,而是把哈希值拆成多个桶:
- 一部分位用于确定落到哪个桶
- 另一部分位用于统计前导零长度
每个桶只记录“当前见过的最大前导零长度”,最后综合所有桶的信息估算总基数。
4. 结果是近似值
由于它保存的是统计特征而不是原始元素,所以无法精确还原所有成员,也不能判断某个元素是否已经存在,只能用于 估算不重复数量。
这也是它和 Set 的本质区别。
四、HyperLogLog 适用场景
1. 网站 UV 统计
例如统计某一天网站独立访客数:
- 每次访问就把用户标识加入 HLL
- 最后直接取估算值
这类场景通常不要求精确到个位,更看重趋势和规模。
2. 活动页独立用户数
营销活动里常见问题:
- 活动页曝光 UV
- 参与活动 UV
- 分享用户 UV
这类指标往往更关注相对变化与量级,HyperLogLog 非常适合。
3. 大规模日志去重统计
例如:
- 某天出现过多少独立设备
- 某周出现过多少独立 IP
- 某月有多少不重复订单来源
如果只是做监控报表,近似值通常就够用了。
4. 多集合合并后的基数估算
HyperLogLog 支持合并,因此可以方便计算:
- 周 UV:合并 7 天数据
- 月 UV:合并 30 天数据
- 渠道总 UV:合并多个渠道数据
五、常用命令与示例
Redis 关于 HyperLogLog 的命令不多,但都很实用。
1. PFADD:添加元素
PFADD uv:20260609 user:1001 user:1002 user:1003
这条命令表示把多个元素加入 HyperLogLog 中。
特点:
- 重复添加同一个元素没有问题
- Redis 不会保存具体元素内容
- 返回值用于表示内部寄存器是否发生变化
2. PFCOUNT:获取近似基数
PFCOUNT uv:20260609
返回的是 估算后的去重数量。
例如:
- 实际是 1000000
- 返回可能是 998000 或 1003000
存在误差,但通常在业务可接受范围内。
3. PFMERGE:合并多个 HyperLogLog
PFMERGE uv:week:202606w24 uv:20260609 uv:20260610 uv:20260611 uv:20260612 uv:20260613 uv:20260614 uv:20260615
PFCOUNT uv:week:202606w24
这个场景很常见:
- 每天维护一个日 UV HLL
- 周报时合并成周 UV
- 月报时合并成月 UV
注意:合并后的结果仍然是近似基数估算。
六、和 Set 去重计数的区别
很多初学者会把 Set 和 HyperLogLog 混用,实际上两者定位完全不同。
| 维度 | Set | HyperLogLog |
|---|---|---|
| 是否精确 | 精确 | 近似 |
| 是否保存元素本身 | 是 | 否 |
| 能否取出成员 | 可以 | 不可以 |
| 内存消耗 | 随元素数量增长明显 | 很小且相对固定 |
| 适合场景 | 需要精确去重、还要访问成员 | 只关心数量规模 |
如果业务要求:
- “列出所有访客 ID”
- “判断某个用户是否访问过”
- “对访客集合做交并差”
那就不能只用 HyperLogLog。
如果业务要求只是:
- “今天大概多少 UV”
- “本周大概多少独立设备”
那么 HLL 非常合适。
七、一个典型案例:网站 UV 统计
1. 每天一个 key
可以约定 key 格式:
uv:day:{yyyyMMdd}
例如:
uv:day:20260609
2. 用户访问时写入
假设使用用户 ID 或设备 ID 作为唯一标识:
PFADD uv:day:20260609 user:1001
PFADD uv:day:20260609 user:1002
PFADD uv:day:20260609 user:1001
虽然 user:1001 添加了两次,但统计时只会算一次。
3. 查询当天 UV
PFCOUNT uv:day:20260609
4. 合并得到周 UV
PFMERGE uv:week:2026w24 uv:day:20260609 uv:day:20260610 uv:day:20260611 uv:day:20260612 uv:day:20260613 uv:day:20260614 uv:day:20260615
PFCOUNT uv:week:2026w24
这套方案实现简单,内存压力也远小于 Set。
八、HyperLogLog 的优点
1. 极省内存
这是 HLL 最核心的优势。面对海量去重计数场景,它比 Set 更适合做统计型任务。
2. 命令简单
只有 PFADD、PFCOUNT、PFMERGE 三类核心命令,学习门槛不高。
3. 适合报表和趋势统计
很多报表不要求绝对精确,更关心趋势、量级和变化率。对于这种需求,HyperLogLog 的性价比非常高。
4. 支持聚合
可以自然地从日级统计聚合到周级、月级、渠道级。
九、使用 HyperLogLog 时的注意事项
1. 它是“近似统计”,不是精确计数
这是最重要的一点。
如果你的业务是:
- 财务结算
- 订单去重
- 权限判定
- 精确奖品发放
这类必须精确的场景,不应该使用 HyperLogLog 作为唯一依据。
2. 不能取出具体成员
HLL 不能告诉你:
- 哪些用户来过
- 某个用户是否来过
- 两个集合的交集成员是谁
它只擅长回答“有多少个不同元素”。
3. 合并方便,但仍然是近似值
PFMERGE 很强大,但合并后结果仍然是估算值,不能因为合并了多份数据就误以为结果变成精确计数。
4. 不适合小而精确的集合管理
如果数据规模很小,而且你还经常需要成员判断、成员遍历,那直接用 Set 往往更简单。
5. key 管理仍然要有生命周期设计
虽然 HLL 内存小,但如果每天、每周、每月都保留很多 key,长期积累也会带来资源占用问题。可以根据业务设置过期时间:
EXPIRE uv:day:20260609 2592000
十、实战设计建议
1. 明确唯一标识是什么
去重统计的前提,是确定“什么算同一个对象”。例如:
- 用户 ID
- 设备 ID
- IP 地址
- Cookie ID
唯一标识不同,统计口径也会不同。
2. 分层设计 key
建议在 key 中显式体现维度:
uv:day:20260609
uv:week:2026w24
uv:channel:appstore:20260609
uv:campaign:618:20260609
这样后续做聚合、过期、排障都更清晰。
3. HLL 做统计,明细存别处
实际业务中常见做法是:
- 用 HyperLogLog 做去重计数
- 用日志、数据库或明细表保存原始事件
这样既有低成本统计,也保留追溯能力。
十一、小结
HyperLogLog 是 Redis 中专门为 大规模去重计数 准备的高级数据结构。它的核心价值不是“精确”,而是“用极小内存得到足够可靠的基数估算”。
可以重点记住以下几点:
- HyperLogLog 用于统计不重复元素的大致数量
- 它不保存元素本身,只保存估算信息
- 常用命令是
PFADD、PFCOUNT、PFMERGE - 适合 UV、独立设备数、独立访客数等统计场景
- 不适合需要精确结果、成员查询或成员导出的业务
如果说 Set 是“精确但更重”的去重工具,那么 HyperLogLog 就是“轻量但近似”的统计工具。对海量数据报表来说,它往往是非常划算的选择。
📝 版权声明:本文为原创技术博客,转载请注明出处。
如文章中存在错误或不准确之处,欢迎在评论区指正,感谢您的阅读与支持!