Redis Set 去重统计不准怎么办:从 SADD 返回值到 Key 粒度一步步排查
一个活动报名页显示“已报名 1250 人”,运营同学却说后台订单只有 1178 条。第一眼看像是缓存延迟,但我们不能直接下结论。Redis Set 做去重统计时,数量不准通常藏在三个地方:返回值理解错、Key 粒度混在一起、过期时间没处理好。
这篇文章我们从一个很小的现场开始,一步一步把问题拆开,看清楚 `SADD`、`SCARD` 和 Key 设计到底应该怎么配合。
摘要
Redis Set 适合保存“不重复成员”,常用于报名用户、接口请求编号、当天访问用户等场景。要让统计稳定,写入时要看 `SADD` 的新增结果,读取时用 `SCARD` 回查数量,同时按业务维度设计 Key,并给临时统计设置合理过期时间。
适合人群
适合正在用 Redis 做去重、UV、活动参与人数、幂等请求记录的后端同学。文章示例使用 Redis 命令和少量伪代码,不依赖特定语言框架。
目录
- 问题现场:为什么显示数量比订单多
- 先验证 SADD:它返回的不是总人数
- 继续定位:Key 粒度混乱会把数据串起来
- 修复方案:写入、统计、过期分开处理
- 常见坑和最终检查
问题现场:为什么显示数量比订单多
我们先复现一个简单场景:活动 ID 是 9001,同一个用户可能重复点击报名按钮。业务希望“一个用户只算一次”,于是代码把用户 ID 写进 Redis Set。
SADD activity:join:9001 10001 SADD activity:join:9001 10002 SADD activity:join:9001 10001 SCARD activity:join:9001
按 Set 的语义,用户 `10001` 第二次写入不应该增加人数。如果页面仍然变多,我们就要先看写入逻辑是不是把每次点击都当成新增了。

先验证 SADD:它返回的不是总人数
第一轮猜测是:代码是不是误解了 `SADD` 的返回值?`SADD` 返回的是本次真正新增的成员数量,不是 Set 里的总成员数。
127.0.0.1:6379> SADD activity:join:9001 10001 (integer) 1 127.0.0.1:6379> SADD activity:join:9001 10001 (integer) 0 127.0.0.1:6379> SCARD activity:join:9001 (integer) 1
这段结果说明了两件事:第一次写入返回 `1`,代表新增成功;第二次写入返回 `0`,代表成员已经存在。要展示当前总人数,应该用 `SCARD`,不能把每一次请求都累加到一个普通数字字段里。
如果业务同时维护了一个 `join_count`,就很容易出现偏差:重复点击让计数器增加了,但 Set 实际人数没变。此时应以 Set 的数量为准,或者只在 `SADD` 返回 `1` 时再更新其他统计。
继续定位:Key 粒度混乱会把数据串起来
如果 `SADD` 返回值没用错,我们继续看 Key。很多统计不准不是命令错了,而是 Key 粒度太粗。比如把所有活动都写到同一个 Key:
SADD activity:join 9001:10001 SADD activity:join 9002:10001
这能去重,但统计某一个活动时就不方便,还容易在读取时切错维度。更清晰的做法是把活动 ID 放到 Key 里,把用户 ID 当成员。
SADD activity:join:9001 10001 SADD activity:join:9002 10001 SCARD activity:join:9001
这一步我们能定位到第二个常见原因:成员内容和 Key 维度混在一起,导致后续统计、清理、对账都变复杂。Key 负责业务范围,成员负责唯一对象,职责分开后排查会轻很多。

修复方案:写入、统计、过期分开处理
现在我们把方案收拢。写入时只关心成员是否新增,统计时用 `SCARD`,临时活动结束后让 Key 自动过期。
SADD activity:join:9001 10001 EXPIRE activity:join:9001 604800 SCARD activity:join:9001
在业务代码里,可以把逻辑拆成三个动作:
added = SADD activity:join:{activityId} {userId}
if added == 1:
写入报名记录或发送首次报名消息
count = SCARD activity:join:{activityId}
注意:如果活动 Key 已经存在,反复设置过期时间可能会延长活动窗口。更稳的写法是创建 Key 后设置一次过期,或者按活动结束时间计算剩余秒数,避免每天访问都把 Key 往后顺延。

常见坑和最终检查
第一个坑是把 `SADD` 的返回值当总人数。它只能告诉你本次新增了几个成员,总人数要用 `SCARD`。
第二个坑是成员值不稳定。比如有的地方写用户 ID,有的地方写手机号,有的地方写 `user:10001`,这些在 Redis 看来都是不同成员,去重自然会失效。成员格式要统一。
第三个坑是大 Set 直接拉全量成员。统计人数用 `SCARD` 即可,不要为了数数量去读出所有成员。需要抽样排查时再用少量扫描,不要把全部成员一次性取回应用层。
最终检查可以按这四步走:
TYPE activity:join:9001 SCARD activity:join:9001 SISMEMBER activity:join:9001 10001 TTL activity:join:9001
如果类型是 `set`,数量和业务记录能对上,关键用户存在性正确,生命周期也符合活动结束时间,这个去重统计就基本稳住了。
总结
Redis Set 去重统计不准时,不要只盯着“Redis 有没有问题”。我们按现场一步步看,真正容易出错的是业务使用方式:把 `SADD` 返回值当总数、Key 粒度不清、成员格式不统一、过期策略顺延。
推荐落地规则很简单:Key 表示业务范围,成员表示唯一对象;新增看 `SADD`,总数看 `SCARD`,生命周期交给明确的过期策略。这样再遇到重复点击、重复请求或活动统计,就能少很多对账麻烦。
前端详情页返回列表丢失滚动位置怎么办:从复现到恢复一步步排查
- 上一篇
- 前端详情页返回列表丢失滚动位置怎么办:从复现到恢复一步步排查
- 下一篇
- Linux crontab 定时任务不运行怎么办:从时间表达式到环境变量一步步排查
-
- 数据库 · Redis | 1小时前 | Redis · Streams · 消费者组 · Pending · XACK · 消息堆积 消费者组 XACK XPENDING XAUTOCLAIM Redis Streams
- Redis Streams 消费者组消息堆积怎么办:从 XPENDING 到 XACK 一步步排查
- 385浏览 收藏
-
- 数据库 · Redis | 2天前 | Redis · 数据库 · HyperLogLog · UV统计 · redis hyperloglog UV统计 PFADD PFCOUNT 去重计数
- Redis HyperLogLog 统计 UV 实战:PFADD、PFCOUNT 和误差边界怎么用
- 180浏览 收藏
-
- 数据库 · Redis | 2天前 | Redis · 消息队列 · Stream · 消费组 · redis 消息队列 Redis Stream 消费组 XREADGROUP XACK XPENDING XAUTOCLAIM
- Redis Stream 消息队列实战:消费组、ACK 和失败重投怎么配
- 187浏览 收藏
-
- 数据库 · Redis | 2星期前 |
- RedisLua脚本实现复杂正则匹配方法
- 438浏览 收藏
-
- 数据库 · Redis | 2星期前 |
- Redis客户端缓冲区优化技巧
- 146浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- MiMo Code
- MiMo Code 是小米大模型团队开源的新一代 AI 编程助手,面向开发者提供代码理解、生成与辅助开发能力,适合作为 AI 编程工具收藏和体验。
- 42次使用
-
- TRAE Work
- TRAE AI IDE | 国内首款 AI 原生集成开发环境,深度集成 Doubao-1.5-pro 与 DeepSeek 模型,支持中文自然语言一键生成完整代码框架,实时预览前端效果并智能修复 BUG。首创 Builder 模式实现需求到代码的自动化开发,兼容 Windows/macOS 系统,官网下载即用。
- 63次使用
-
- MeloLab
- MeloLab 是一款 AI 音乐生成工具,可根据文本创意生成歌曲、人声、混音、分轨和背景音乐,适合创作者快速制作音乐素材。
- 52次使用
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 8706次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 9115次使用
-
- Golang迭代如何在Go中循环数据结构使用详解
- 2022-12-22 148浏览
-
- 详解如何在Go语言中循环数据结构
- 2022-12-22 406浏览
-
- 分享Redis高可用架构设计实践
- 2023-01-24 286浏览
-
- B-Tree、B+Tree以及B-link Tree
- 2023-01-19 235浏览
-
- Go与Redis实现分布式互斥锁和红锁
- 2022-12-22 117浏览

