news 2026/4/15 12:06:07

Redis 如何统计独立用户访问量?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Redis 如何统计独立用户访问量?

Redis 如何统计独立用户访问量?(UV 统计的 4 种方案)

在网站分析、广告监测、推荐系统等场景中,独立用户访问量(UV,Unique Visitor)是一个核心指标。UV 的关键在于去重——同一个用户多次访问只计一次。

Redis 提供了多种数据结构来高效实现 UV 统计,各有优劣。本文将详细对比Set、Bitmap、HyperLogLog、incr + 日期维度(即用户提到的两种方式)四种方案,并通过流程图和代码示例帮助你选型。

一、方案概览(附选型流程图)

整数且连续
如user_id=1~1亿

字符串或稀疏ID
如uuid/手机号

允许0.81%误差
如大屏展示

必须精确

需要每日独立统计

需要统计UV

用户ID类型?

Bitmap方案
内存极小, 准确

是否允许微小误差?

HyperLogLog方案
内存12KB, 性能极高

Set方案
内存随基数增长

能否预聚合?

incr + 日期维度
辅助计数, 需配合Set/HLL

二、方案一:Set 集合(精确去重)

最直观的方法:每个统计周期(如一天)维护一个 Set,将每个访问过的用户 ID 加入 Set,最后用SCARD获取基数。

# 示例:用户 1001 访问首页redis.sadd("uv:home:2025-04-15","user_1001")# 获取当天 UVuv=redis.scard("uv:home:2025-04-15")

优点:精确、支持用户 ID 任意类型(字符串/整数)。
缺点:内存占用高,每个用户 ID 都需要存储一份(例如 1000 万用户,每个 ID 按 30 字节算,需约 300MB)。
适用:用户量小(< 百万级)或必须精确统计的场景。

三、方案二:Bitmap(位图法,精确且内存极省)

当用户 ID 是整数且相对连续(如自增 user_id)时,可以用 Bitmap 将每个 user_id 映射到位偏移量,存在则置 1。

# 用户 ID=1001 访问,设置第 1001 位为 1redis.setbit("uv:home:2025-04-15",1001,1)# 统计当日 UV(统计 1 的个数)uv=redis.bitcount("uv:home:2025-04-15")

内存计算:如果有 1 亿用户,只需1亿 bit ≈ 12 MB,比 Set 节省数十倍。
优点:精确、内存极小、性能高(bitcount 时间复杂度 O(n) 但 Redis 做了优化)。
缺点:用户 ID 必须为整数且不太稀疏(若 ID 最大为 10 亿,但实际只有 100 万用户,依然会占用 125MB 的连续空间,造成浪费)。
适用:用户 ID 是自增整数、最大 ID 可控(如 2^32 以内)、对内存敏感且要求精确的场景。

四、方案三:HyperLogLog(近似去重,误差 0.81%)

你提到的HyperLogLog是一种概率性数据结构,用 12KB 固定内存即可统计上亿级别的 UV,误差率约为 0.81%。

# 添加元素redis.pfadd("uv:home:2025-04-15","user_1001","user_1002")# 获取近似 UVuv=redis.pfcount("uv:home:2025-04-15")

原理:通过哈希函数将元素映射为二进制串,观察低位连续零的个数来估计基数。
优点:内存固定(12KB),性能极高(O(1) 添加),适合海量数据。
缺点:不精确(误差 ±0.81%),无法取出具体有哪些用户(只能计数),不适合敏感计费场景。
适用:大屏展示、趋势分析、非精准营销统计等可容忍误差的场景。

五、方案四:incr + 日期维度(你提到的“incr自增”)

严格来说,单纯使用INCR无法实现独立用户去重,因为INCR是累加计数器,每次访问都 +1,得到的是 PV(页面访问量),不是 UV。

# 这样得到的是 PV,不是 UVredis.incr("pv:home:2025-04-15")

如何用 incr 辅助 UV?
通常做法是incr + Set/Bitmap/HLL 组合

  • 用 Set 或 HLL 存储独立用户(保证去重)
  • 同时用 incr 记录总访问次数(PV)
# 记录 PVredis.incr("pv:home:2025-04-15")# 记录 UV(使用 HLL)redis.pfadd("uv:home:2025-04-15",user_id)

所以,你提到的“incr 通过自增方式判断用户的访问量”并不适用于 UV,应理解为 PV 统计。但为了贴合你的原文,我们修正说明:incr 适合 PV,UV 必须依赖去重结构

六、四种方案对比表

方案内存占用精确性支持用户ID类型时间复杂度(写入)典型应用
SetO(N)(每个元素完整存储)精确任意O(1)小规模精确统计
BitmapO(max_id) 位,连续整数时极省精确非负整数O(1)亿级整数ID,如手机号后几位
HyperLogLog固定 12KB近似(误差 0.81%)任意(需哈希)O(1)海量UV快速估算
incr(PV)固定(每个key一个整数)精确无(只是计数)O(1)页面访问总量(非UV)

七、实战选型建议

  • 你的用户 ID 是整数且密集(如 user_id 从 1 到 5000 万)
    👉 首选Bitmap,精确且内存最小。

  • 用户 ID 是字符串(如 UUID、手机号),且允许 0.81% 误差
    👉 首选HyperLogLog,12KB 内存统计上亿 UV。

  • 必须精确统计,且用户量较小(< 500 万)
    👉 用Set,简单可靠。

  • 既要 PV 又要 UV
    👉 组合:INCR记录 PV +PFADD记录 UV(HLL)或SADD(Set)。

  • 数据敏感场景(如计费、反作弊)
    ❌ 不能用 HyperLogLog,必须用 Bitmap 或 Set。

八、代码示例:三种方案对比(Python + Redis)

importredis r=redis.Redis(decode_responses=True)# 模拟 100 万个用户 ID(字符串)user_ids=[f"user_{i}"foriinrange(1_000_000)]# 1. Set 方式key_set="uv:set"r.delete(key_set)foruidinuser_ids:r.sadd(key_set,uid)print(f"Set 精确 UV:{r.scard(key_set)}")print(f"Set 内存:{r.memory_usage(key_set)/1024/1024:.2f}MB")# 2. HyperLogLog 方式key_hll="uv:hll"r.delete(key_hll)foruidinuser_ids:r.pfadd(key_hll,uid)print(f"HLL 近似 UV:{r.pfcount(key_hll)}")print(f"HLL 内存:{r.memory_usage(key_hll)}字节")# 固定约 12KB# 3. Bitmap 方式(假设 user_id 转为整数,此处用 i 模拟)key_bit="uv:bitmap"r.delete(key_bit)foriinrange(1,1_000_001):r.setbit(key_bit,i,1)print(f"Bitmap 精确 UV:{r.bitcount(key_bit)}")print(f"Bitmap 内存:{r.memory_usage(key_bit)/1024/1024:.2f}MB")

运行结果参考(百万级):

  • Set:内存约 30~40 MB
  • HLL:12 KB
  • Bitmap:0.12 MB(100 万 bit = 0.125 MB)

九、总结

你的原始说法修正/补充
“incr 通过自增方式判断用户的访问量”incr 得到的是 PV(总访问次数),不是 UV。UV 需要去重。
“HyperLogLog 用来做基数统计,误差很小,不适合数据敏感场景”✅ 正确。误差约 0.81%,内存固定 12KB,适合海量近似统计。

最终结论

  • 对精度要求不高、数据量极大 →HyperLogLog
  • 需要精确、用户 ID 为整数 →Bitmap
  • 需要精确、用户 ID 为字符串且量小 →Set
  • 想要统计 PV →incr

合理选择数据结构,能让你的 UV 统计既快又省内存。


📌 扩展思考:如果既要精确又要省内存,可以结合分段 Bitmap + 冷热分离,但会增加复杂度。有没有更好的思路?

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/15 12:03:57

抗体芯片:高通量蛋白质免疫检测技术

一、引言蛋白质免疫检测是生物医学研究中的常用手段。传统免疫印迹法&#xff08;Western blot&#xff09;虽具备较高的特异性和灵敏度&#xff0c;但在处理多样本、多靶点检测时存在通量低、操作繁琐、样本消耗量大等局限。抗体芯片技术在此基础上发展而来&#xff0c;具备同…

作者头像 李华
网站建设 2026/4/15 12:00:52

WVP平台SIP服务器搭建避坑指南:从设备注册到视频调用的全流程详解

WVP平台SIP服务器搭建避坑指南&#xff1a;从设备注册到视频调用的全流程详解 在智能视频监控领域&#xff0c;GB/T28181标准已经成为设备互联互通的重要规范。作为该标准的核心组件&#xff0c;SIP服务器的稳定运行直接关系到整个监控系统的可靠性。本文将深入剖析WVP平台下SI…

作者头像 李华
网站建设 2026/4/15 12:00:11

5个简单步骤:快速上手ECMWF CDS API获取气候数据

5个简单步骤&#xff1a;快速上手ECMWF CDS API获取气候数据 【免费下载链接】cdsapi Python API to access the Copernicus Climate Data Store (CDS) 项目地址: https://gitcode.com/gh_mirrors/cd/cdsapi ECMWF CDS API是访问Copernicus气候数据存储库的Python接口&…

作者头像 李华
网站建设 2026/4/15 11:58:11

GEE实战:用Sentinel-2 2A级数据做地表覆盖分类,完整代码与避坑指南

GEE实战&#xff1a;用Sentinel-2 2A级数据做地表覆盖分类&#xff0c;完整代码与避坑指南 当我们需要监测森林砍伐、城市扩张或农作物生长时&#xff0c;地表覆盖分类是最基础也最关键的遥感应用之一。相比传统的1C级数据&#xff0c;Sentinel-2的2A级产品经过大气校正&#x…

作者头像 李华