redis-cli --bigkeys仅估算大key元素数,无法精确识别千万级set;须用scard验证,分片迁移应采用sscan+sadd双写,删除用unlink避免阻塞。

redis-cli --bigkeys只能发现,不能定位千万元素Set
执行 redis-cli --bigkeys 会告诉你 “Largest set found 'user_tags' with 1M elements”,但不会显示具体是 100 万还是 1000 万,更不会告诉你这个 Set 是否正在持续膨胀。它只做采样统计,对超大 Set 的元素数是向下取整估算的,实际可能差一个数量级。
真正要确认是否达到千万级,必须用 scard 命令直接查:
redis-cli scard user_tags
如果返回 10248921 这类七位数以上结果,基本可判定为高危大 Key。注意:此时不要立刻执行 smembers —— 它会把全部元素拉到客户端,极易打爆网络和内存。
拆分千万级Set不能靠hgetall式遍历
常见错误是写个脚本循环 sscan user_tags 0 count 1000 拉全量再重分片,这在千万级下极慢且不可控:SCAN 游标可能中途失效、客户端 OOM、网络超时频发。
更稳妥的做法是服务端分片 + 客户端路由:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 用
sscan user_tags 0 count 50000分批获取(count设为 5w 而非默认 10,减少往返次数) - 每批拿到后,立即按哈希规则写入新 Key:
sadd user_tags_001 {item}、sadd user_tags_002 {item}… - 新 Key 命名建议带业务前缀+分片编号,如
user_tags_v2_shard_07,避免和旧 Key 冲突 - 拆分期间保持双写:新增元素同时写入原 Set 和新分片 Set,直到迁移完成
删除原Set必须用UNLINK而非DEL
DEL user_tags 是同步阻塞操作,千万级 Set 删除可能卡主线程 2–5 秒,所有请求排队超时;而 UNLINK user_tags 是异步删除,命令秒返回,Redis 后台线程清理内存,不阻塞后续请求。
但要注意两点:
-
UNLINK仅 Redis 4.0+ 支持,7.0 默认可用,无需额外配置 - 执行前确保已停写原 Key,否则新写入的元素会被丢弃(UNLINK 不保证原子性覆盖)
- 删完用
exists user_tags验证,别只信返回值 —— 有时 UNLINK 返回 1 但 key 还在内存里未释放完
拆分后务必验证去重逻辑是否被破坏
Set 的核心价值是自动去重,拆成多个子 Set 后,业务层必须自行保障跨分片唯一性,否则就退化成普通列表了。
典型陷阱:
- 用用户 ID 哈希取模分片,但没考虑扩容重哈希,导致相同元素落到不同分片
- 双写期间网络抖动,部分写入失败,造成数据不一致
- 查询时只查单个分片,漏掉其他分片里的同名 tag
上线前必须跑一致性校验脚本:从所有子 Set 中抽样比对元素分布,并用 sunion 模拟合并后总集大小,与原 scard 结果对比。差值不为 0 就说明拆分过程有遗漏或重复。










