1. 认知错位:当业务并发单元是“用户”,MQ 却只懂“队列”
在 AI 时代,以阿里云百炼平台为例,用户通过大模型生成的图片、视频等临时产物,需要被转化为长期的“个人数字资产”并持久化落库。这是一条典型的异步消息处理链路:生产侧写入 OSS 临时目录并发送消息,消费侧进行安全审核与持久化。
表面上看,这是一个极简的 Pub/Sub 模型。但当你面对海量用户时,魔鬼就藏在细节里:这条消息流,天然是按用户组织的。
如果你用传统的 RocketMQ 或 Kafka Topic 来承载,很快就会撞上一堵高墙。传统 Topic 的隔离单元是“队列(Queue / Partition)”,所有用户共享同一组队列。这就导致了三个无解的痛点:
- 队头阻塞(Head-of-Line Blocking):单用户流量风暴会占满消费线程,其他用户的资产入库全部被迫排队等待。
- 限流颗粒度粗:传统 MQ 只能做全局限流,无法针对单一“暴走用户”进行精准降级。
- 挂起粒度大:一旦触发限流,MQ 的挂起是整个消费组级别的。要停一个用户,就得把所有人一起停了。
为了解决这个问题,过去很多架构师被迫在 MQ 之上再造一套 MQ——在业务代码里硬写复杂的用户路由层和用户级限流组件。这不仅恶心,而且极度脆弱。
2. 破局:为什么我们不能建 100 万个 Topic?
既然要隔离,最直观的想法是:“那我给每个用户建一个 Topic 不就行了?” 在传统 MQ 的经验里,这近乎是架构设计的禁忌。传统 Topic 非常“重”,依赖强一致的元数据同步,单个 Broker 支撑几万个 Topic 就会出现性能断崖,根本不可能支撑“百万级”规模。
但 RocketMQ 5.x 引入的 LiteTopic(轻量主题) 彻底改变了游戏规则。
LiteTopic 的核心特性可以用三个词概括:超大规模、按需创建、自动回收。
- 单 Broker 支撑百万级队列,彻底打破了传统元数据的性能瓶颈。
- 无需预建:发送消息时指定 LiteTopic,不存在则由 Broker 自动创建。
- 自动清理:通过 TTL 机制,闲置队列自动回收。
我们可以用下面这张对比图,直观地看看传统架构与 LiteTopic 架构的本质差异:
graph TD
subgraph 传统 MQ 架构 : 队列隔离 (大锅饭)
P1[用户 A 消息] --> Q1(共享 Topic 队列)
P2[用户 B 消息] --> Q1
P3[用户 C 暴增消息] --> Q1
Q1 --> C1[消费者集群]
C1 -.->|用户 C 占满线程<br>A 和 B 被迫阻塞| Block[SLA 下降]
end
subgraph LiteTopic 架构 : 用户隔离 (一人一 Topic)
L1[用户 A] --> LT1(LiteTopic_UserA)
L2[用户 B] --> LT2(LiteTopic_UserB)
L3[用户 C 暴增] --> LT3(LiteTopic_UserC)
LT1 --> C2[消费者集群]
LT2 --> C2
LT3 --> C2
C2 -.->|对 UserC 定向限流挂起<br>A 和 B 正常消费| Pass[互不干扰]
end
3. 架构落地:把多租户治理“下推”给基础设施
百炼资产中心正是利用了 LiteTopic,实现了极其优雅的架构改造。他们没有在业务侧写一行复杂的路由和限流代码,而是直接将多租户治理的职责“下推”给了基础设施。
具体落地非常轻量:
- 生产侧(零维护):按
用户 ID写入对应的 LiteTopic。系统不再需要预先配置和维护 Topic 清单,新用户注册产生动作时,Topic 自动创建。 - 消费侧(零改动):使用一次通配符订阅(Wildcard Subscription)覆盖全部用户的 LiteTopic。新用户接入,消费端代码一行都不用改。
- 限流侧(精准打击):在消费回调中,如果检测到某用户触发限流,直接返回挂起指令。Broker 会在指定时长内仅仅停止该用户 LiteTopic 的投递,其他用户的消息丝毫不受影响。
4. 总结:同一个原语,两种维度的降维打击
百炼网关之前用 LiteTopic 重构了大模型限流,将其作为分布式的“漏桶”;而这次资产中心则用它做用户级的消息隔离治理。
同一个技术原语,在不同的场景下都展现出了惊人的破坏力,这验证了一个深刻的架构哲学:当业务的并发单元是“用户”时,消息系统的治理单元也必须是“用户”。