订单支付完成后,要发优惠券、发短信、更新积分。如果这些操作全部同步执行,其中任何一个环节变慢,用户都得等着。消息服务的做法是把这些任务拆开,主流程只负责发出通知,其余环节各自按节奏处理。阿里云MNS(Message Service)就是做这件事的托管消息服务,不用自己搭建和维护消息中间件。

MNS的两种模型怎么选
MNS主要有队列(Queue)和主题(Topic)两种模型。它们解决的问题不一样,选错了后面改起来很麻烦,所以动手前要先分清。
队列模型:一条消息只交给一个消费者
队列适合点对点的任务分发。生产者把消息写进队列,消费者主动来取,某个消费者处理成功后,这条消息就会被删除。
拿电商平台举例。用户支付成功后,订单服务往名为 order-paid 的队列里写一条消息,里面有订单号和用户ID。发券服务、积分服务各自轮询这个队列。消费端通常要用订单号做幂等校验,否则同一笔订单可能被处理两次。这样一来,订单服务只关心“已经支付”这件事,不用等发券的结果。
主题模型:一条消息推给多个订阅者
主题适合一对多的事件通知。生产者把消息发到主题,主题再推给所有订阅者。订阅者可以是HTTP回调地址、队列,也可以是邮件或短信这类终端。
同一个平台的用户注册流程就是这么设计的。注册成功后,用户服务向 user-registered 主题发一条消息,主题下挂了三条订阅:
- 推送到风控队列,做新用户反欺诈检测。
- 推送到营销队列,发放新人礼包。
- 通过HTTP推送到数据团队的埋点服务。
以后要加一个新业务方,只需要多加一条订阅,注册服务的代码不用动。这一点是主题相比直接调接口最实在的好处。不过订阅越多,排查问题时要看的链路也越长,这个代价要提前想清楚。
几个常用功能
除了两种模型,MNS还有几项功能,设计阶段就该考虑进去。
- 长轮询:消费者拉取时可以设置等待时间。队列为空时连接会保持等待,而不是频繁返回空结果,能减少无效请求的费用和负载。
- 延迟消息:消息可以设定延迟投递。比如“下单后30分钟未支付就关单”,就适合用延迟消息来做,不必自己写定时任务扫表。
- 死信队列:消息重试超过设定次数仍然处理失败,就转入死信队列。运维可以单独看这些消息,避免一条坏消息反复占用消费资源。
- 消息保留:消息在队列里保存的时长可以配置。消费方临时离线时,消息不会马上丢掉,但保留时间也不是越长越好,要和业务的恢复时间匹配。
案例:秒杀时怎么削峰
某电商平台做秒杀,开抢瞬间每秒下单请求能到几万次,但库存和支付系统每秒只能处理几千次。如果请求直接打到数据库,开抢几秒内就会出现大面积超时和报错。
团队的改造思路是这样的:
- 请求先过网关限流,通过的请求写入秒杀队列,接口马上返回“排队中”,不让用户干等。
- 库存服务按自己能承受的速率从队列取消息,完成库存扣减。速率要压在数据库能扛住的范围内,这一步要靠压测定。
- 扣减成功的订单写入支付超时队列,并设置15分钟延迟投递。用户没有付款的话,关单服务在延迟到期后收到消息,释放库存。
- 处理失败的消息重试三次,仍然失败就进死信队列,由客服人工核对。这类订单通常金额和用户都要人工确认,不适合让程序一直重试。
改完以后,数据库的写入压力回到可控范围,活动期间的接口超时率明显下降。这个方案的代价也很明确:用户看到的是“排队中”,等待时间变长了,但系统没有被冲垮。对秒杀这种场景,这个取舍通常是值得的。
上线前要注意的几件事
- 消费端必须幂等:MNS保证消息至少投递一次,网络抖动时同一条消息可能被投递两次。消费逻辑要能识别重复消息,比如用业务ID做去重记录。
- 消息体尽量小:消息里只放ID和必要字段,详细数据让消费方按ID去查。消息体大了,传输和存储都会变慢。
- 配额以官方文档为准:消息大小、队列数量、单次拉取条数这些限制会随版本调整。上线前请到控制台或官方文档核实,不要凭印象设计。
- 堆积量要提前设告警:队列堆积是最直接的信号。堆积数持续增长,通常说明消费能力跟不上,需要扩容消费端或排查处理逻辑。