用Redis咋能快查关注数,简单又高效的思路分享
- 问答
- 2025-12-24 17:43:09
- 2
说到用Redis快查关注数,比如查一个用户有多少粉丝,或者关注了多少人,这确实是Redis最典型的应用场景之一,核心思路就一句话:别去数据库里现算,直接把数存好,用的时候一读就行。 下面我详细拆解一下怎么把这个思路落地,保证既简单又高效。
最核心、最直接的办法:用String类型存一个数字
这是最直观的,比如用户A的粉丝数,我就在Redis里存一个键值对,键的名字得有规律,follower_count:user:A,对应的值就是粉丝数量,15203。
- 怎么用:当有人关注用户A时,程序干两件事:1. 在数据库里建立关注关系,2. 立刻给Redis里的
follower_count:user:A这个值加1(使用Redis的INCR命令),取消关注就减1(DECR命令),查数量的时候,直接用GET follower_count:user:A,这个速度是微秒级的,快得没影。 - 优点:极其简单,速度最快,理解起来没任何难度。
- 需要注意的点:这个数字可能会“不准”,因为极端情况下,可能数据库更新成功了,但Redis增减失败了(比如网络闪断),所以它适合对数字的“绝对精确性”要求不是百分百苛刻的场景,比如微博的粉丝数,差几个根本无所谓,如果非要绝对精确,可以在系统低峰期,定期从数据库同步一次正确的数量到Redis,纠正一下。
当需要知道“谁”关注了,而不仅仅是“多少”个:用Set集合
我们不光想知道粉丝数量,还想知道具体是哪些人关注了我,或者判断某个人B是不是已经关注了A,这时候,String类型就不够了,得用Redis的Set(集合)类型。
- 怎么用:为每个用户创建一个Set,比如用户A的粉丝集合,键可以叫
followers:user:A,当用户B关注A时,就把B的用户ID(user:B)加入到这个集合里(使用SADD命令),取消关注就从集合里移除(SREM命令)。 - 查什么:
- 查总数:直接用
SCARD followers:user:A命令,这个命令能瞬间返回集合的元素个数,也就是粉丝数,效率同样极高。 - 查具体名单:用
SMEMBERS followers:user:A能取出所有粉丝ID,但要注意,如果粉丝量巨大(比如百万级),这个命令可能会慢,而且一次返回大量数据有风险,更常见的做法是分页查,用SSCAN命令。 - 判断是否关注:用
SISMEMBER followers:user:A user:B,能立刻知道B是不是A的粉丝。
- 查总数:直接用
- 优点:功能强大,除了计数,还能做很多关系判断。
- 缺点:比单纯的String耗内存,如果用户粉丝量极大(千万甚至上亿),这个Set会非常大,占用很多Redis内存,操作起来也可能变慢,这时候就需要更高级的招了。
对付海量数据:用HyperLogLog做近似计数

这是一种“杀手级”的应用,如果你的场景是:我需要统计的量非常大(比如一个明星大V的粉丝数上亿),并且我可以接受这个数字有微小的误差(比如误差在0.81%以内),但我的首要目标是极致节省内存,那么HyperLogLog(简称PF)就是为你准备的。
- 怎么用:和String类似,为每个用户分配一个PF结构,键比如叫
pf_followers:user:A,当有新人关注时,就用PFADD pf_followers:user:A user:B命令,查询总数用PFCOUNT pf_followers:user:A。 - 优点:内存占用小得惊人,官方说法是,统计1亿个不重复元素,只需要大概12KB内存,而且无论你要统计的元素有多少,它占用的内存都是固定的,这对于省成本来说太友好了。
- 缺点:就一条,数字是“近似”的,不精确,所以它只适用于那种“展示个大概规模”的场景,比如页面侧边栏显示“10万+粉丝”,具体是100,102还是100,201,不重要。
总结一下怎么选
就是看你的具体需求:
- 只要数字,追求最快最直接 -> 用 String,配合
INCR/DECR,记得处理好可能的数据不一致问题。 - 既要数字,还要知道是谁,关系判断 -> 用 Set,配合
SADD/SCARD/SISMEMBER,适合粉丝量不是天文数字的场景。 - 海量数据统计,允许一点点误差,死磕内存节省 -> 用 HyperLogLog,配合
PFADD/PFCOUNT。
一个非常重要的实战技巧:分桶计数

这个技巧来自一篇名为《Redis 设计与实现》的经典资料,用来解决“超级大V”的计数问题,比如一个用户有5亿粉丝,你用Set存5亿个ID,内存肯定爆炸,即使用String,频繁的 INCR 操作在极高并发下也可能有压力。
“分桶”的思路很巧妙:我不只存一个总数,而是把计数分散到多个小的Redis键里。
用户A的粉丝数,我不再只用一个 follower_count:user:A,而是用100个(这个数量可以调整):
follower_count_bucket:user:A:1
follower_count_bucket:user:A:2
...
follower_count_bucket:user:A:100
当有新粉丝关注时,我随机选一个桶(比如第57号桶),给这个桶里的数字加1,查总数的时候,我需要把这100个桶的值全部 GET 出来,在程序里加一下。
- 为什么这样更好?
- 分散写入压力:原来所有并发都争抢一个键,现在分散到100个键上,大大降低了单个键的竞争,提升了并发处理能力。
- 控制单键大小:避免了单个键的Value值过大(虽然String类型值可以很大,但小一点总归好)。
- 平衡了读写:写操作(INCR)因为分散而变快了,读操作(GET 100个键)虽然变复杂了,但依然是O(1)操作,只是多了网络开销,由于读操作通常可以通过缓存等手段优化,而写操作是实打实的压力,所以这个权衡往往是值得的。
就是用Redis快查关注数的主流思路,核心就是利用Redis内存操作的极致速度,把计算结果提前存好,用空间换时间,具体用哪种结构,取决于你对数据精确度、功能丰富度和内存成本之间的权衡。
本文由革姣丽于2025-12-24发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://www.haoid.cn/wenda/67683.html
