SDIFF 不能直接找出“新增关注”,因其仅执行集合差运算且不记录时间顺序;需先构建两个语义明确的快照集合(如按日期命名),再用 SDIFF 计算差集,否则易因键名错误、空键或客户端处理问题导致结果异常。

SDIFF 能不能直接找出“新增关注”
不能——SDIFF 本身只做集合差运算,不记录时间或顺序。所谓“新增”,本质是对比两个时间点的 follow_set:旧快照 vs 新快照。你得先有这两个集合,SDIFF 才能算出“新加入的成员”。常见错误是拿当前关注集和一个空集、或和用户资料集去差,结果要么全返回、要么恒为空。
怎么构造两个可比的 Set
关键在命名和写入时机。必须让 Redis 里同时存在两个有明确语义的 Set:
-
follow:uid:123:20240520(昨天快照) -
follow:uid:123:20240521(今天快照)
或者更稳妥地用带过期的临时键:follow:uid:123:tmp_new 和 follow:uid:123:tmp_old,每次更新前先 RENAME 旧键再写新键。别用 SADD 增量写入后直接差——那不是“新增”,是“当前全量减去某静态参考集”,语义错位。
SDIFF 返回结果为空却以为有新增
典型原因有三个:
- 两个键名拼错,比如少写了
:uid:或日期格式不一致(2024-05-21vs20240521),SDIFF对不存在的键视为空集,SDIFF a b中若b不存在,结果等价于SMEMBERS a - 用了
SDIFFSTORE但目标键已存在且没清空,导致结果被追加而非覆盖 - 客户端自动去重或截断了返回的
RESP2数组,尤其在某些 Lua 脚本或旧版驱动里,把单元素结果误判为 nil
调试时先手动跑:SDIFF follow:uid:123:20240520 follow:uid:123:20240521,看原始输出是否符合预期。
性能和数据一致性要注意什么
大关注量用户(比如百万级)下,SDIFF 是 O(N+M) 时间复杂度,N、M 分别为两个 Set 的基数。如果每天全量 dump 再 diff,内存和 CPU 压力会随关注数线性上涨。更轻量的做法是改用「增量日志」:每次 SADD 同时往 follow_log:uid:123(List 或 Stream)推一条记录,再用 XREAD 拉取未处理的新增 ID。不过这就脱离 SDIFF 场景了——真正要用 SDIFF,就得接受它只适合中低频、中小规模的离线比对。
另外,Redis Cluster 下 SDIFF 要求所有 key 在同一个 slot,否则报 CROSSSLOT Keys in request don't hash to the same slot 错误。所以键名设计必须带相同哈希标签,比如都写成 {follow:uid:123}:20240520 和 {follow:uid:123}:20240521。










