软件架构演进史 04:消息队列——异步解耦的诞生(2010-2014)
当系统变复杂,各模块如何解耦?答案是:消息队列。
序幕
2010 年,中国互联网进入爆发期。那一年发生了很多大事:
-
3Q大战,360和腾讯正面刚 -
小米手机发布,移动互联网开始爆发 -
智能手机普及,App时代来临
互联网用户从PC端快速向移动端迁移,流量暴增。但很多公司的系统还是给PC设计的,根本扛不住移动端的流量冲击。
如果你那时候在淘宝下单买一件衣服,后台会经历什么?
用户下单 → 验证库存 → 锁定库存 → 创建订单 → 支付 → 通知仓库 → 发货 → 物流更新 → 短信通知用户
一个”下单”操作,涉及8个系统、几十次同步调用。任何一步卡住,用户就卡在”提交订单”页面转圈。
双 11 更恐怖——0点下单,10秒后还没成功,用户直接关页面走人。
问题:
-
双 11 订单量突破 1000 万 -
系统耦合严重,一个模块挂掉,整个系统崩溃 -
同步调用耗时长,用户体验差
传统架构的问题:
-
下单 → 库存 → 支付 → 物流,全部同步调用 -
任何一个环节慢,整个链路就卡住 -
峰值流量无法削峰,全部打到后端
直到消息队列出现。工程师们发现:与其让用户等待,不如把请求存下来,慢慢处理。这就是异步的魅力。
消息队列的诞生
什么是消息队列?
先讲个故事:
2010年,某电商公司的CTO王大嘴(花名)决定对系统进行改造。他的原话是:”我们要用消息队列把系统解耦,让各个模块独立发展。”
底下的工程师一脸蒙逼:”啥是消息队列?”
王大嘴说:”你们用过U盘吗?U盘就是电脑和电脑之间的’消息队列’。你把文件拷到U盘里,拔下来插到另一台电脑上,文件就传过去了。不用两台电脑一直连着。”
大家恍然大悟。
消息队列也是同理:系统A把消息丢到队列里,系统B从队列里取。不用A一直等着B处理完。
你一定遇到过这种情况:
在网上下单买了件衣服,页面显示”下单成功”,但其实后台还在处理:通知仓库备货、通知物流取件、更新会员积分、发送短信通知……
如果这些操作全部同步执行,用户要等到所有事情做完才能看到”成功”,可能要等3-5秒。
消息队列的核心思想:把同步调用变成异步消息。下单成功后,把后续任务丢到队列里就返回,仓库、物流、积分、短信各自从队列里取任务执行。
用户感受:下单1秒成功,体验流畅。
后台处理:慢慢处理,不着急。

组成部分:
- Producer(生产者):发送消息
- Broker(消息服务器):存储转发消息
- Consumer(消费者):接收处理消息
消息队列的优势
|
|
|
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
RabbitMQ vs Kafka
RabbitMQ
2007年,RabbitMQ 1.0发布。它是”传统企业”的最爱,也是很多工程师的”初恋”。
为什么选RabbitMQ?
- 协议标准:AMQP是企业级标准,跨语言、跨平台,Java、Python、Go都能用
- 路由灵活:direct、topic、fanout、headers,想怎么路由就怎么路由
- 可靠投递:事务、确认机制完善,金融级应用首选
- 管理界面:自带Web管理界面,运维友好
但缺点也明显:
-
Erlang开发,社区小,出了问题不好排查 -
吞吐量不如Kafka,单机万级/秒就到顶了 -
集群方案不如Kafka成熟

Kafka
2011年,LinkedIn开源Kafka,彻底改变了消息队列的格局,也成就了Kafka创始人Jay Kreps。
Kafka的革命性创新:
- 顺序写磁盘:写磁盘像写内存一样快,吞吐量百万级/秒
- partition + replica:数据分片+副本,容错能力MAX
- consumer group:消费者组概念,一个消息可以被多个组消费
- offset管理:自己管offset,不依赖服务端,消费者可以重放消息
- 日志存储:消息持久化到磁盘,可以重复消费,可以回溯
为什么Kafka这么快?
秘密在于顺序写和零拷贝。传统消息队列收到消息先写内存再刷磁盘,Kafka直接顺序追加到文件末尾,应用读取时使用sendfile零拷贝绕过内核缓冲区。

技术选型
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
选型建议:
- 业务消息、实时推送、金融级 → RabbitMQ
- 日志收集、大数据、实时计算 → Kafka
- 不确定 → Kafka(生态更好)
消息可靠投递
消息丢失问题
2013年,某电商公司因为消息丢失出了大事:
用户下单成功,页面显示”已下单”,但仓库根本没收到订单。等了3天没发货,用户投诉才发现——几千个订单在队列里丢了。
那段时间,运维每天提心吊胆:消息到底有没有发送到?消费者到底有没有处理?
消息丢失的三个场景:
- 生产者发送时丢失:发到一半网络断了,消息没到MQ
- 消息队列存储时丢失:MQ收到消息但还没持久化,MQ重启了
- 消费者处理时丢失:消费者拿到消息但处理一半挂了
每一个环节都可能丢消息,这就是消息可靠投递的难点。

解决方案
生产者确认:
# RabbitMQ 确认模式channel.confirmSelect();channel.addConfirmListener((seq, ack) => { // 消息确认});
消息持久化:
# Kafka 持久化配置props.put("acks", "all");props.put("retries", 3);
消费确认:
# Kafka 消费确认consumer.commitSync();
消息顺序性
顺序性问题
问题:消息顺序不确定,导致数据不一致。

解决方案
- 单分区有序:同一业务 ID 发到同一 partition
- 全局有序:所有消息到一个分区
- 版本号:消息带版本号,消费者按版本处理
分布式事务
分布式事务问题
场景:订单服务 + 库存服务 + 积分服务。
问题:如何保证要么都成功,要么都失败?

解决方案
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
消息事务流程:
-
发送消息(预提交) -
本地事务执行 -
确认/回滚消息
真实案例
淘宝双 11
2012年双11前夜,阿里技术团队彻夜未眠。
0点一到,流量瞬间冲上100万QPS——是平时的100倍。如果所有请求都直接打到后端数据库,数据库会瞬间挂掉。
他们的方案是”削峰填谷”:
- 限流:只放行10%的请求到核心系统,其余排队
- 异步:下单成功后,订单信息写入消息队列,返回”提交成功”
- 解耦:库存服务、物流服务、通知服务各自从队列消费,互不干扰
背景:
-
2012 年双 11,订单量突破 1 亿 -
峰值 QPS 超过 100 万
效果:
-
系统可用性 99.99% -
用户体验:下单成功,物流通知异步发送
滴滴出行
滴滴的痛点和淘宝不同——他们需要实时。
用户点击”叫车”,系统需要在秒级内匹配到附近司机。这不是简单的下单→支付,而是实时推送→抢单→匹配的复杂流程。
滴滴选择了Kafka + 实时计算:
- 司机位置:每秒更新,经Kafka发往匹配引擎
- 订单分发:司机抢单后,经Kafka同步给乘客
- 日志收集:行程轨迹、计费明细全部入Kafka
背景:
-
每天处理 1 亿次出行请求 -
实时匹配司机和乘客
效果:
-
叫车响应时间 < 3秒 -
日处理消息量 1000 亿+
美团外卖
美团的场景更复杂——他们不仅要实时,还要高可靠。
用户下单 → 商家接单 → 骑手取餐 → 配送 → 完成
每一个环节都不能出错,错了就是客诉。
美团的技术方案:
- RocketMQ:阿里开源的消息队列,经过双11验证
- 顺序消息:同一订单的消息必须有序,不能乱
- 消息回溯:出问题可以从任意时间点重新消费
- 延迟消息:骑手接单后30分钟自动确认,超时自动退款
背景:
-
每天 3000 万订单 -
高峰 QPS 50 万 -
50 万骑手在线
效果:
-
订单处理成功率 99.99% -
骑手配送准时率 95%+
它留下了什么
异步架构思维
消息队列给中国互联网带来的最大改变,不是技术,而是思维方式。
- 同步是特例,异步是常态:不是所有请求都需要即时响应
- 解耦是架构的核心目标:系统之间不应该直接调用
- 消息队列是异步架构的基础:没有MQ,就谈不上微服务
云原生消息队列
2014年后,云服务商开始提供托管消息队列:
- 阿里云 RocketMQ:阿里双11实战验证
- AWS SQS/SNS:云原生的选择
- 消息队列 as a Service:不用自己运维了
现在中小公司基本都用云服务了,不再自建MQ。这是趋势,也是进步。
尾声
2014 年,消息队列成为互联网公司的标配。
几乎所有大厂都在用:阿里用RocketMQ,字节用Kafka,美团用MQ……消息队列从一个”高级技术”变成了”基础设施”。
但带来了新问题:
- 消息重复消费:消费者处理成功了,但没来得及确认,消息被重新投递
- 消息积压:消费者处理太慢,队列堆积,最后内存爆炸
- 系统复杂度增加:MQ成了核心组件,一旦出问题就是全局故障
2015年后,工程师们开始研究”精确一次”语义——如何保证消息不丢失也不重复。这方面的探索,后来催生了事务消息、消息回溯等高级特性。
下一代挑战:如何保证消息的精确一次?如何在保证性能的同时保证可靠性?
总结
2010-2014 年这四年,是中国互联网从”同步到异步”的转变期。
我们学会了用消息队列做系统解耦,学会了用 Kafka 做日志收集,学会了用 RabbitMQ 做业务消息。这些技术让系统吞吐量提升了 10 倍,用户等待时间减少了 80%。
技术选型
- 异步优先:非核心流程异步处理
- 选择合适的:RabbitMQ vs Kafka
- 可靠性:消息不丢是底线
架构设计
- 解耦:生产者消费者无直接依赖
- 削峰:高峰期消息堆积
- 顺序:同一业务消息有序
经验教训:
-
异步是提升性能的关键 -
解耦带来更好的可扩展性 -
没有最好的消息队列,只有最合适的
消息队列是系统解耦的核心。当系统从单机变成多机,同步调用就变成了噩梦。消息队列让”下单”和”发货”不再相互等待。
但消息队列只是解决了异步问题,数据量继续增长怎么办?这就来到了下一章的故事。
夜雨聆风
