乐于分享
好东西不私藏

软件架构演进史 04:消息队列——异步解耦的诞生(2010-2014)

软件架构演进史 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
吞吐量
万级/秒
百万级/秒
消息持久化
内存+磁盘
磁盘顺序写
消息堆积
一般
很强
路由能力
灵活
简单
生态
一般
完善
运维难度

选型建议

  • 业务消息、实时推送、金融级 → 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
  • 全局有序:所有消息到一个分区
  • 版本号:消息带版本号,消费者按版本处理

分布式事务

分布式事务问题

场景:订单服务 + 库存服务 + 积分服务。

问题:如何保证要么都成功,要么都失败?

解决方案

方案
说明
复杂度
两阶段提交
2PC,协调者统一提交
TCC
Try-Confirm-Cancel
消息事务
最终一致性

消息事务流程

  1. 发送消息(预提交)
  2. 本地事务执行
  3. 确认/回滚消息

真实案例

淘宝双 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%。

技术选型

  1. 异步优先:非核心流程异步处理
  2. 选择合适的:RabbitMQ vs Kafka
  3. 可靠性:消息不丢是底线

架构设计

  1. 解耦:生产者消费者无直接依赖
  2. 削峰:高峰期消息堆积
  3. 顺序:同一业务消息有序

经验教训

  • 异步是提升性能的关键
  • 解耦带来更好的可扩展性
  • 没有最好的消息队列,只有最合适的

消息队列是系统解耦的核心。当系统从单机变成多机,同步调用就变成了噩梦。消息队列让”下单”和”发货”不再相互等待。

但消息队列只是解决了异步问题,数据量继续增长怎么办?这就来到了下一章的故事。


本站文章均为手工撰写未经允许谢绝转载:夜雨聆风 » 软件架构演进史 04:消息队列——异步解耦的诞生(2010-2014)

评论 抢沙发

2 + 3 =
  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
×
订阅图标按钮