关注功能高并发怎么扛?Redis ZSet + Lua + MQ 异步落库一整套

简介: 关注功能高并发怎么设计?本文拆解 Redis ZSet 存关系、Lua 保原子性、MQ 异步落库、消费端令牌桶削峰四环,抗住瞬间洪峰。

大家好,我是晚安code。

关注功能高并发有多难扛?(2026 年 8 月实测,适用于 Redis 6.0+ / RocketMQ 4.9+)这次我把整套「Redis 缓冲 + ZSet 存关系 + Lua 保原子 + MQ 异步落库 + 令牌桶削峰」的方案完整写出来,你照着这套思路做高并发设计,能少走我踩过的弯路。

一、直接写库,关注接口为什么扛不住

先说结论:关注功能的高并发瓶颈,从来不在功能本身,而在你把高频写操作直接怼给了数据库。

关注这个动作拆开看,一次请求至少要干三件事:往关系表插入一条记录、给对方的粉丝数 +1、给自己维护的关注列表加一个成员。很多项目第一版就是这么干的——一个事务里同步写完这三步。用户量一上来,问题全暴露了:

  1. 关系表频繁 insert,索引不断膨胀,写入越来越慢;
  2. 高并发下「插入 + 计数」不是原子的,粉丝数可能对不上账;
  3. 数据库 IO 是有上限的,瞬时洪峰一来直接打穿。

我在见到的经典事故,就是「关注接口双写 Redis + DB」:请求来了先写 MySQL 再写 Redis,并发一上来,两边数据就开始打架——有人取关成功了,Redis 里关系还在;有人关注重复提交,计数翻倍。

说白了,关系数据本身不难存,难的是让数据库别被高频写压垮。所以整套方案的核心思路只有一个:把「高频写」前置到 Redis,用 MQ 把落库这件事切成异步,数据库只吃它扛得住的量。

二、Redis 缓冲层:把关系放进 ZSet

Redis ZSet(Sorted Set,有序集合):Redis 的一种数据结构,每个成员带一个 score 分值,成员按 score 自动排序。你可以理解为「带时间戳的收藏夹」——既能去重判断存没存过,又能按时间倒序翻页。

关注关系选 ZSet 而不是 Set,就一个原因:关注列表天然需要按时间排序。「最近关注了谁」是社交产品里最常见的查询,Set 只能存成员、排不了序,ZSet 用关注时间当 score,ZRANGE 一查就是按时间排好的列表。

我这里的存储模型是双向两份:

following:{用户ID}    member=被关注人ID,score=关注时间戳
follower:{用户ID}     member=粉丝ID,score=关注时间戳

关注时间做 score,取出来天然就是一条时间线,就像朋友圈按发布时间排。注意看这张概念图里的时间圆点——score 就是那条看不见的排序轨道:

ZSet 里 score 是排序轨道,时间戳当 score 就能按时间查

这样设计的好处是:

  • 插入高效ZADD 复杂度 O(log N),时间戳做 score,天然有序;
  • 查询高效ZRANGE 分页查关注/粉丝列表、ZSCORE 判断是否已关注,都是毫秒级;
  • 取关干净ZREM 一条命令删掉关系,两个 key 一起维护。

关注功能高并发架构图:请求进入 Redis 缓冲层,Lua 原子更新 ZSet,异步发送 MQ 由消费端令牌桶限流后落库

上面这张图就是完整链路:关注接口收到请求 → Lua 脚本原子更新 Redis → 发 MQ → 消费者令牌桶限流 → 异步落库。下面逐个环节拆。

三、Lua 脚本:高并发下 Redis 更新也要原子

Lua 脚本:Redis 内置的脚本语言,脚本会整段在 Redis 服务端原子执行——执行期间不会被其他命令插入。你可以理解为「Redis 内的一次性原子事务」。

很多人以为写了 Redis 就万事大吉,其实高并发下 Redis 的「检查 + 更新」也必须用 Lua 串成一步。看这段伪代码,是不是很眼熟:

-- 关注:判断 + 插入 + 计数,三条命令
local exists = redis.call('zscore', KEYS[1], ARGV[1])
if exists then return 1 end  -- 已关注
redis.call('zadd', KEYS[1], ARGV[2], ARGV[1])
redis.call('hincrby', 'follow:count', ARGV[1], 1)
return 0

如果这三步分开执行,并发下就会出问题:两个请求同时判断「没关注」,然后各插一次、计数加两次。我在生产环境就踩过这个坑——上线当天关注数虚高,排查半天发现就是计数器被并发叠加了。

用 Lua 把「判断是否已关注 → 插入 ZSet → 更新计数」合并成一步,Redis 单线程保证整段脚本不会被打断,原子性天然解决。关注和取关各写一个脚本,eval 一次调用就完成,性能比拆分命令还好。

这个「合并成一步」就是 Lua 原子性的精髓——三条散落的命令,被串成一把钥匙上的三个齿,要么一起动,要么都不动:

Lua 脚本 = 把「判断、更新、计数」锁进一把钥匙,原子完成

四、发 MQ 异步落库:打 Tag 精确消费

MQ(Message Queue,消息队列):一个中转消息的中间件,生产者发消息、消费者异步取消息,两边解耦。你可以理解为「业务之间递纸条的收发室」——不是当面交接,而是放进信箱异步处理。

Redis 只是缓冲层,不是持久层。关系最终要落到数据库,但绝不能同步落。正确做法是:Redis 更新成功后,立即发一条消息到 MQ,接口直接返回「关注成功」,剩下的落库交给消费者慢慢做。

这里有个细节值得展开——发消息要打 Tag。以 RocketMQ 为例,同一个 Topic 下按业务场景打不同标签:

// 生产端:关注/取关打不同 Tag
Message msg = new Message(
    "FOLLOW_TOPIC",          // Topic
    isFollow ? "FOLLOW" : "UNFOLLOW",  // Tag 标签
    userId + ":" + targetId   // 业务数据
);
producer.send(msg);

消费者订阅时按 Tag 过滤,只处理自己关心的消息:

consumer.subscribe("FOLLOW_TOPIC", MessageSelector.byTag("FOLLOW || UNFOLLOW"));

为什么要打 Tag?三个理由:消费端能精确过滤,不用消费全部消息再业务层判断;方便分场景限流,关注和取关可以配置不同的处理速率;排查问题时定位快,一看 Tag 就知道这条消息是什么业务。

消息队列削峰的核心价值就在这:接口侧把瞬时洪峰甩给 MQ,MQ 像一个水库,把洪峰的水蓄住,再按下游能承受的流速放出去。这就是常说的削峰填谷。

你看这张图就明白了——上面是劈头盖脸的暴雨(洪峰),下面是稳稳的一条小溪(落库速率),中间的 MQ 就是那个水库闸门:

MQ 是水库,接口是暴雨,数据库是小溪——削峰填谷全靠这个闸门

可能有人会问:Redis 更新成功了,MQ 消息发了,万一落库失败,数据不就对不上了?

放心,这正是异步方案必须配的兜底。消费者落库用「主键幂等」——follow 表用 (user_id, target_id) 建唯一索引,重复消息 insert 时冲突直接跳过;再加一层死信队列,重试几次还失败的进 DLQ 人工排查。Redis 作为读缓存,可以接受偶尔重建,数据库这一层最终一致就行。

五、消费端令牌桶:数据库只吃它吃得下的量

令牌桶(Token Bucket):一种限流算法,系统按固定速率往桶里放令牌,请求要先拿到令牌才能处理,桶满了就丢弃新令牌。你可以理解为「景区按固定频率放人进门的闸机」——人再多,进场的速率是定死的。

到消费端这一步,MQ 里已经堆了一大堆落库消息。如果消费者一股脑全拉出来写库,等于把洪峰从接口侧平移到了数据库侧,前面白干了。所以消费端必须限速,这就是令牌桶上场的地方

我用的是 Redis 实现的分布式令牌桶:消费者每处理一条消息前,先 eval 一个 Lua 脚本拿令牌,拿到才继续,拿不到就稍等重试。核心脚本长这样:

local bucket = 'token:' .. KEYS[1]   -- 桶名
local tokens = tonumber(redis.call('get', bucket) or '0')
local capacity = tonumber(ARGV[1])   -- 桶容量
if tokens >= 1 then
    redis.call('decr', bucket)
    return 1   -- 拿到令牌
end
return 0       -- 桶空,稍后再试

配合一个定时任务按固定速率补令牌,消费速率就被稳稳控住了。数据库的写入 TPS 从「不可控的洪峰」变成「恒定的 500」,压力直接可量化。

限流方案 是否支持突发 实现复杂度 适用场景
固定窗口 否,瞬间可能双倍 粗粒度限流
滑动窗口 部分 要求平滑
令牌桶 是,桶存突发量 削峰填谷、消费端限速
漏桶 否,恒定速率 强制匀速

对比下来,消费端削峰选令牌桶最合适:平时流量平稳时桶是满的、不排队;活动洪峰时桶蓄不住的部分直接丢弃或排队,数据库永远只看到固定速率。我实际调参时,桶容量按「数据库能承受的最大 TPS × 3」设置,既给了突发余量,又不至于把库打爆。

FAQ

可能有人会问:为什么关注功能不能先写数据库再删缓存?

顺序反过来会带来缓存与数据库的短暂不一致:删缓存和写库之间一旦有并发读,读到的就是旧缓存。异步落库 + Redis 兜底的方案里,Redis 是读的主来源,写库是后台补账,只要幂等键兜底,最终一致就够用。

六、总结:这套方案的核心思路

回顾一下整套链路:关注功能高并发设计,核心就一句话——Redis 当缓冲层挡住高频写,ZSet 存关系保排序,Lua 脚本把判断和更新合成原子一步,MQ 异步承接落库并打 Tag 分场景,消费端令牌桶把数据库压在恒定速率。五个环节各司其职,缺一个都容易在洪峰时出岔子。

以我踩过坑的经验,新手最容易漏的是第二环——以为 Redis 天然原子,结果计数器被并发打爆。原子性不会因为数据进了 Redis 就自动有,该用 Lua 还得用

关注接口高并发设计自查清单:

  1. Redis 缓冲:关系写入全部前置 Redis;
  2. ZSet 双向存储:following / follower 各一份;
  3. Lua 原子:判断 + 插入 + 计数合并一个脚本;
  4. MQ 异步:发消息打 Tag,接口立即返回;
  5. 令牌桶限流:消费端限速落库,保护数据库。

这套方案同样适用于点赞、收藏、订阅这类「高频写关系」功能——把场景换一下,思路是通的。这套关注功能高并发方案在你那边落地时,建议先把量级估清楚:预估并发 1 万以内,简化到「Redis + 定时任务」也能扛;真正到了活动级洪峰,再上 MQ + 令牌桶不迟。如果想深入,推荐看 Redis 官方文档的 Lua 脚本章节,和 RocketMQ 的消息过滤文档(搜:Redis eval 文档、RocketMQ Tag 过滤)。


我是晚安code,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你在做关注、点赞这类高并发功能时,遇到过哪些「数据对不上账」的坑?

目录
相关文章
|
3天前
|
云安全 人工智能 运维
阿里云联动百位企业安全专家,共识Agent防御最佳实践
当Agent成为新员工,你的安全边界在哪里?
1731 2
阿里云联动百位企业安全专家,共识Agent防御最佳实践
|
11天前
|
人工智能 JSON 安全
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
阿里云AI安全产品联动防御Fastjson攻击
2443 13
Fastjson远程代码执行漏洞,阿里云AI安全为您保驾护航
|
12天前
|
人工智能 自然语言处理 数据挖掘
Qwen3.8-Max-Preview深度全解析:2.4万亿参数旗舰MoE模型+Token Plan限时优惠完整落地指南
2026年7月,全新旗舰级混合专家大模型Qwen3.8-Max-Preview正式开放抢先体验,作为通义千问Qwen3系列规格最高、综合推理能力顶尖的新一代模型,该模型总参数量达到2.4万亿(2.4T),是当前线上可调用的原生多模态旗舰模型,综合推理水准对标海外顶级Fable 5模型,在复杂工程开发、长文档深度分析、多步骤智能体自治、跨境多语言创作、海量数据挖掘五大高难度业务场景实现跨越式性能提升。
1172 2
|
10天前
|
人工智能 前端开发 Linux
Codex 桌面版安装 + CC Switch 接入第三方 API 完整教程(2026 最新)
2026最新教程:手把手教你安装Codex桌面版,通过CC Switch v3.17.0一键接入Fenno等国产API(兼容OpenAI Responses格式),跳过账号登录,完整启用代码审查、多步任务与上下文感知功能。零基础友好,全程图文实操。(239字)
919 1
|
13天前
|
人工智能
Qwen3.8抢先体验!正式版即将发布并开源!
千问Qwen3.8即将开源,参数达2.4T,进化速度以“天”计,实力媲美Fable 5。预览版Qwen3.8-Max已上线阿里Token Plan等平台,限时优惠:日间Credits低至1折,夜间更优,个人/团队版月付仅35元起!
1171 49
|
10天前
|
自然语言处理 测试技术 API
通义千问Qwen3.8-Max-Preview全功能解析:2.4万亿参数旗舰模型深度使用指南
在大模型技术持续迭代的当下,通义千问推出的Qwen3.8-Max-Preview作为新一代旗舰预览版模型,凭借2.4万亿参数的超大规模、多模态融合能力与全场景适配特性,成为开发者与企业用户探索AI应用的核心工具。该模型采用稀疏混合专家(MoE)架构,是通义千问首个突破万亿参数的多模态模型,可同时处理文本、图像、视频与文档等多种数据形态,在全栈代码开发、复杂逻辑推理、长文档分析与多智能体协作等场景实现跨越式升级。本文将全面拆解Qwen3.8-Max-Preview的核心功能,详解API调用流程与配置方法,覆盖多场景实战技巧,帮助用户快速掌握这款旗舰模型的使用方法,充分释放其性能潜力。
601 2
|
10天前
|
SQL 关系型数据库 MySQL
【2026最新】DBeaver下载、安装、数据库管理一篇搞定(附官网社区版安装包)
DBeaver是一款免费开源的跨平台通用数据库管理工具,支持MySQL、PostgreSQL、SQLite、Oracle等几乎所有主流数据库,无需为每种数据库安装独立客户端,极大提升开发与数据分析效率。

热门文章

最新文章