SINTER是唯一靠谱、原子、高效的方式,它基于内存集合运算,自动选取最小集合优化性能,毫秒级返回结果,避免网络往返与客户端计算开销;而遍历比对需拉取全部好友ID到客户端,引发高延迟、内存膨胀和重复遍历。

为什么用 SINTER 而不是遍历比对?
直接查两个用户的好友集合交集,是共同好友推荐最自然的建模方式。SINTER 是 Redis 原生命令,在服务端完成集合运算,避免把海量好友 ID 拉到应用层做嵌套循环——后者在万级好友量时很容易卡住接口或打爆内存。
关键前提是:每个用户的好友列表必须用 Set 类型存储,且成员是标准、去重的用户 ID(如 "u1001"),不能混入时间戳、状态标记等额外字段。
SINTER 的实际调用与边界情况处理
假设用户 A 的好友 Set 是 friends:u1001,用户 B 是 friends:u1002,执行:
redis-cli SINTER friends:u1001 friends:u1002
返回结果就是共同好友 ID 列表。但要注意这些现实问题:
- 如果任一 key 不存在,
SINTER返回空集合(不是报错),业务需判断结果长度是否为 0,而非依赖异常捕获 - 若某用户好友数超 50 万,
SINTER仍能执行,但响应延迟可能升至几十毫秒——建议对高频请求加缓存(如common_friends:u1001_u1002,TTL 设为 1 小时) - Redis Cluster 下,所有参与
SINTER的 key 必须落在同一 slot,否则报CROSSSLOT错误;解决方法是用哈希标签强制路由,例如把 key 改为friends:{u1001}和friends:{u1002}
如何支撑“推荐”而不仅是“查询”?
单纯交集只能回答“他俩有多少共同好友”,但推荐需要排序和过滤。常见做法是组合其他结构:
Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。
- 把共同好友按“互相关注时长”排序:提前用
ZSET存friendship_time:u1001,再用ZINTERSTORE+SINTER结果做二次筛选 - 排除已发送过好友请求的用户:维护一个
sent_req:u1001Set,最后用SDIFF剔除 - 限制返回数量防拖慢:用
SINTER后接SRANDMEMBER或管道中加LIMIT(注意:原生命令不支持 LIMIT,需在客户端截断)
不要试图在一个命令里塞进所有逻辑——Redis 的强项是原子集合运算,排序、分页、业务规则过滤交给应用层更可控。
容易被忽略的更新一致性问题
当用户 A 取关用户 C,你只删了 friends:u1001 里的 "u1003",但没动任何“共同好友缓存”,下次查 A 和 B 的交集时,C 还可能出现在结果里——因为缓存未失效。
推荐做法是:所有写操作(增/删好友)后,主动清掉涉及该用户的全部共同好友缓存,例如:
DEL common_friends:u1001_u1002 common_friends:u1001_u1003 ...
或者更省事:用带前缀的 key 模式(如 cf:u1001:*),配合 SCAN + DEL 批量清理(注意 SCAN 不保证实时性,适合低频变更场景)。
真正难的不是算交集,而是让每一次取关、拉黑、隐私设置变更,都能及时反映在推荐结果里——这需要写操作路径足够清晰,且缓存粒度和失效策略匹配业务容忍度。

















