Redis HyperLogLog

Redis HyperLogLog 完全攻略

“极致省内存的基数统计神器”

12KB 内存,统计 10 亿级不重复元素,误差 < 1%
完美替代 Set 做 UV、IP 去重、用户行为分析!


一、HyperLogLog 核心特点

特性说明
用途基数统计(Cardinality) —— 统计不重复元素数量
内存固定≈ 12 KB,无论统计 1 个还是 10 亿
误差率≈ 0.81%(标准误差)
不支持删除只能添加,不能 DEL 单个元素
命令PFADDPFCOUNTPFMERGE
内部结构基于 HyperLogLog 算法 + 稀疏/密集存储优化

二、HyperLogLog 命令全表(仅 3 个!)

命令说明示例
PFADD key element [element ...]添加元素PFADD page:uv "u1" "u2" "u1"
PFCOUNT key [key ...]统计基数PFCOUNT page:uv2
PFMERGE destkey sourcekey [sourcekey ...]合并多个 HLLPFMERGE all:uv day1 day2

PF = Probabilistic Filter(概率过滤器)


三、核心实战场景


1. 网站日 UV 统计(百万级用户)

# 用户访问首页
PFADD uv:20251112:home "user:1001" "user:1002" "user:1001"

# 获取今日 UV
PFCOUNT uv:20251112:home   → 2

# 保留 30 天
EXPIRE uv:20251112:home 2592000

10亿用户 UV → 仅 12KB 内存!


2. 多日 UV 合并(周/月 UV)

# 每天统计
PFADD uv:20251112 "u1" "u2"
PFADD uv:20251113 "u2" "u3"
PFADD uv:20251114 "u3" "u4"

# 合并本周 UV
PFMERGE uv:week:202511 "uv:20251112" "uv:20251113" "uv:20251114"
PFCOUNT uv:week:202511   → 4

3. 文章独立访问用户数

PFADD article:1001:uv "u1" "u2" "u1" "u3"
PFCOUNT article:1001:uv   → 3

4. 实时去重 IP 统计

PFADD ip:daily "192.168.1.1" "192.168.1.2" "192.168.1.1"
PFCOUNT ip:daily   → 2

5. 用户行为路径去重(A→B→C)

PFADD path:login_to_pay "u1" "u2" "u1"
PFCOUNT path:login_to_pay

四、HyperLogLog vs Set 对比(UV 统计)

对比项HyperLogLogSet
内存占用≈12KBN × 64 字节
10万 UV12KB≈6.4MB
1000万 UV12KB≈640MB
支持删除不支持支持
精确度≈99.19%100%
适用场景大基数、不需精确小基数、需精确

结论:UV > 10万,用 HLL!


五、误差分析与精度控制

统计数量标准误差实际误差范围
10,000±1.64%±164 人
100,000±0.81%±810 人
1,000,000±0.26%±2,600 人
10,000,000±0.081%±8,100 人

误差可接受?99.9% 的业务都 OK!


六、内存与性能优化建议

建议说明
每天一个 keyuv:20251112 → 方便合并、过期
定期清理EXPIRE 自动删除
合并前评估PFMERGE 前确认必要性
避免滥用小数据用 Set 更精确
# 自动清理脚本(每天 00:00)
EXPIRE uv:20251013 86400   # 保留30天

七、常见问题与解决方案

问题原因解决方案
UV 统计偏低元素未添加确保每次访问都 PFADD
内存泄漏key 未过期EXPIRE
不能删除用户HLL 不支持只能重建
合并后 UV 爆炸重复合并控制合并频率

八、一键速查表

# 每日 UV
PFADD uv:20251112 "u1" "u2" "u1"
PFCOUNT uv:20251112

# 周 UV 合并
PFMERGE uv:week:202511 "uv:20251112" "uv:20251113"
PFCOUNT uv:week:202511

# 设置过期
EXPIRE uv:20251112 2592000   # 30天

九、客户端代码示例

Python (redis-py)

import redis
r = redis.Redis()

# 记录用户访问
r.pfadd('uv:20251112:home', 'user:1001', 'user:1002', 'user:1001')

# 获取 UV
uv = r.pfcount('uv:20251112:home')
print(f"今日 UV: {uv}")

# 合并周 UV
r.pfmerge('uv:week:202511', 'uv:20251112', 'uv:20251113')
week_uv = r.pfcount('uv:week:202511')

Go (go-redis)

ctx := context.Background()
rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})

rdb.PFAdd(ctx, "uv:20251112", "u1", "u2")
uv, _ := rdb.PFCount(ctx, "uv:20251112").Result()
fmt.Println(uv) // 2

十、HyperLogLog 在高并发中的妙用

1. 实时大屏 UV 展示

# 每秒更新
PFADD uv:realtime "u1" "u2" ...
PFCOUNT uv:realtime

2. 多维度 UV 分析

PFADD uv:20251112:mobile "u1" "u3"
PFADD uv:20251112:pc     "u2" "u4"
PFCOUNT uv:20251112:mobile

3. 结合 Lua 实现原子统计

EVAL "
  redis.call('pfadd', KEYS[1], ARGV[1])
  return redis.call('pfcount', KEYS[1])
" 1 uv:20251112 "u1"

十一、HLL vs 其他去重方案

方案内存精度删除推荐场景
Set100%支持< 10万
HyperLogLog12KB≈99.2%不支持> 10万
Bitmap1bit/用户100%支持已知用户ID

完成!你已精通 Redis HyperLogLog!

# 一行命令体验 HLL 全功能
redis-cli <<EOF
PFADD hll a b c a b
PFCOUNT hll
PFMERGE hll2 hll hll
PFCOUNT hll2
EXPIRE hll 86400
EOF

下一步推荐

  1. Redis Bitmap 签到系统
  2. HLL + 定时任务 实现自动报表
  3. UV 统计系统架构设计

需要我送你

  • “亿级 UV 实时统计系统(HLL + 分片)”
  • “多维度用户行为分析平台”
  • “HLL + ClickHouse 离线分析方案”

回复:亿级UV | 行为分析 | 离线方案 即可!

文章已创建 2481

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部