Redis怎样统计独立访客UV_基于Set的SADD指令天然去重特性

老墨大大_4385

老墨大大_4385

2026-03-31

258人浏览

原创

sadd统计uv最直接因自动去重且o(1)时间复杂度;适用单日/稳定id场景,禁用incr/hset误计;key须按时间窗口和业务维度设计并配expire;获取uv仅用scard,禁用smembers或keys;跨周期合并应预建周期key或离线计算。

redis怎样统计独立访客uv_基于set的sadd指令天然去重特性

为什么用 SADD 统计 UV 最直接

因为每个用户 ID 写入 SET 时,SADD 自动忽略重复值,底层哈希表保证 O(1) 去重 —— 不需要你写 if 判断是否存在,也不依赖外部逻辑兜底。

常见错误现象:INCR 或 HSET 误用:有人用 INCR uv:20240601 统计,结果把 PV 当 UV;或者用 HSET 存用户 ID + 时间戳,却忘了查重,导致重复计数。

  • 适用场景:单日 UV、按设备 ID / 登录 ID / 匿名 token 统计(注意 ID 必须稳定且有业务意义)
  • 不适用场景:需要实时精确到秒级去重的长周期 UV(如 30 天去重),SET 占内存高,建议用 HyperLogLog
  • 性能影响:1000 万用户 ID 的 SET 约占 200–300MB 内存,比 PFADD 高 5–10 倍,但精度 100%

SADD 的 key 设计决定统计粒度

key 名不是随便拼的,它直接绑定时间窗口和业务维度。比如 uv:day:20240601 和 uv:hour:2024060114 是两个完全独立的集合,互不影响。

容易踩的坑:uv:user_id 这种 key 意味着全量用户塞进一个 set,无法分片、无法过期、无法清理 —— 一旦写错,内存只增不减。

  • 推荐格式:uv:{time_window}:{scope},例如 uv:day:20240601:web(Web 端单日 UV)
  • 必须配 EXPIRE:写完 SADD 紧跟 EXPIRE uv:day:20240601 86400,否则 key 永久存在
  • 避免中文或空格:uv:日活:20240601 会导致部分客户端解析异常,一律用英文+数字+下划线

如何安全地获取当日 UV 数量

SCARD 是唯一正确方式。别用 SMEMBERS 拉全量再 count,数据一过万就卡顿甚至触发慢日志。

常见错误现象:用 KEYS uv:day:* 扫所有日期 key 再逐个 SCARD —— 这在生产环境属于高危操作,阻塞主线程。

  • 正确做法:应用层维护日期变量,明确调用 SCARD uv:day:20240601
  • 批量查询多个日期?用 pipeline 封装多个 SCARD,不要用 KEYS 或 SCAN 做元数据扫描
  • 注意返回值类型:SCARD 返回整数,若 key 不存在返回 0,不是 nil —— 别在代码里判 nil 导致逻辑跳过

跨天/跨周期 UV 合并的现实约束

Redis 原生命令不支持两个 SET 取并集后直接返回基数,SUNIONSTORE 会写新 key,SUNION 会把全部元素传回客户端 —— 100 万用户 ID 就是几 MB payload,网络和内存双开销。

真正能落地的方案只有两种:要么提前规划好周期 key(如用 uv:week:2024W23 单独维护),要么导出到离线系统用 Spark/Hive 计算。

  • 别在 Redis 里做 SUNION + SCARD 组合:一次请求可能耗时数百毫秒,且不可缓存
  • 如果必须运行时合并,用 SUNIONSTORE tmp:uv:merge uv:day:20240601 uv:day:20240602,再 SCARD,最后 DEL tmp:uv:merge —— 但要注意并发写冲突
  • 更稳的做法:每天凌晨用 Lua 脚本原子化地把昨日 key merge 到周 key 中,避免白天查时临时计算

UV 统计看着简单,难点从来不在加法,而在 key 生命周期管理、内存水位预估、以及跨周期合并时对 Redis 特性的误判 —— 很多人卡在“以为 SADD 写进去就完了”,其实后面三步才是真功夫。

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
counta和count的区别
counta和count的区别

Count函数用于计算指定范围内数字的个数,而CountA函数用于计算指定范围内非空单元格的个数。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2023.11.20

3308

5

登录token无效
登录token无效

登录token无效解决方法:1、检查token的有效期限,如果token已经过期,需要重新获取一个新的token;2、检查token的签名,如果签名不正确,需要重新获取一个新的token;3、检查密钥的正确性,如果密钥不正确,需要重新获取一个新的token;4、使用HTTPS协议传输token,建议使用HTTPS协议进行传输 ;5、使用双因素认证,双因素认证可以提高账户的安全性。

2023.09.14

14086

6

登录token无效怎么办
登录token无效怎么办

登录token无效的解决办法有检查Token是否过期、检查Token是否正确、检查Token是否被篡改、检查Token是否与用户匹配、清除缓存或Cookie、检查网络连接和服务器状态、重新登录或请求新的Token、联系技术支持或开发人员等。本专题为大家提供token相关的文章、下载、课程内容,供大家免费下载体验。

2023.09.14

1665

5

token怎么获取
token怎么获取

获取token值的方法:1、小程序调用“wx.login()”获取 临时登录凭证code,并回传到开发者服务器;2、开发者服务器以code换取,用户唯一标识openid和会话密钥“session_key”。想了解更详细的内容,可以阅读本专题下面的文章。

2023.12.21

3877

3

token什么意思
token什么意思

token是一种用于表示用户权限、记录交易信息、支付虚拟货币的数字货币。可以用来在特定的网络上进行交易,用来购买或出售特定的虚拟货币,也可以用来支付特定的服务费用。想了解更多token什么意思的相关内容可以访问本专题下面的文章。

2024.03.01

6041

5

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

2023.08.10

4318

6

常用的数据库软件
常用的数据库软件

常用的数据库软件有MySQL、Oracle、SQL Server、PostgreSQL、MongoDB、Redis、Cassandra、Hadoop、Spark和Amazon DynamoDB。更多关于数据库软件的内容详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.02

4609

19

内存数据库有哪些
内存数据库有哪些

内存数据库有Redis、Memcached、Apache Ignite、VoltDB、TimesTen、H2 Database、Aerospike、Oracle TimesTen In-Memory Database、SAP HANA和ache Cassandra。更多关于内存数据库相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.14

4175

11

mongodb和redis哪个读取速度快
mongodb和redis哪个读取速度快

redis 的读取速度比 mongodb 更快。原因包括:1. redis 使用简单的键值存储,而 mongodb 存储 json 格式的数据,需要解析和反序列化。2. redis 使用哈希表快速查找数据,而 mongodb 使用 b-tree 索引。因此,redis 在需要高性能读取操作的应用程序中是一个更好的选择。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

2024.04.02

7812

6

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.9万人学习