电商、物流和 SaaS 系统里,订单创建后通常要同时通知库存、积分、短信和数据分析系统。如果订单服务同步调用每个下游,任何一个环节变慢或报错,下单接口都会跟着卡住。阿里云 ONS 做的事情很简单:上游只管把消息发出去,下游各自按自己的节奏消费。

需要提前说明一点:ONS 是阿里云消息队列的早期产品名,现在不少能力已经并入消息队列 RocketMQ 版。控制台入口和计费方式请以官方文档和当前产品页面为准。
消息队列到底拆开了什么
消息队列把调用关系拆成两半。生产者把消息写入主题(Topic),消费者通过消费组(Group)订阅。同一条消息可以被多个消费组各自消费,彼此互不影响。下游某个服务挂了,上游照常下单,消息会留在队列里等它恢复。
先搞清楚四个概念
- 主题 Topic:消息的大类,比如 order_created。
- 消费组 Group:同一业务的多个实例共用一个组。组内每条消息只会被处理一次,扩容时直接多开实例即可。
- 标签 Tag:在主题内做二级过滤,比如 paid、refund。支付成功和退款可以走同一个主题,消费端按标签挑着收。
- 消息键 Key:通常填业务单号。出了问题要查某个订单的消息轨迹时,靠它定位。
单条消息大小、保留时长、每秒发送上限这些配额,会随产品版本和规格变化。上线前以官方文档的最新数值为准,别拿旧文章里的数字直接套用。
一个电商订单的改造过程
假设某中型电商日均 20 万单,大促峰值每秒约 300 单。原来的订单服务同步调用库存、积分、短信三个接口。平均响应 850 毫秒,短信接口偶尔超时 3 秒,大促期间下单失败率升到 1.2%。问题不在某一个接口写得差,而是下单这条链路上,任何一环慢了,用户都得等。
改造后,订单服务在本地事务提交成功后,向 order_created 主题发一条消息,然后直接返回。接口平均响应降到 120 毫秒。库存、积分、短信三个服务各自订阅,各自重试,短信超时只影响短信自己。
具体顺序是这样的:
- 订单服务写入订单表并提交事务。
- 向 ONS 发送消息,消息键填订单号。
- 库存服务消费消息并扣减库存。处理失败时,消费组按策略自动重试。
- 积分服务和短信服务分别消费,各跑各的。
上线两周后,下单失败率降到 0.1% 以下。这些数字是示意场景,你自己的业务要以自己的监控数据为准。
接入时的五个动作
- 在控制台创建主题和消费组。命名用“业务_动作”的格式,比如 order_created 和 inventory_deduct_group,半年后别人接手也能看懂。
- 生产者和消费者引入对应语言的 SDK,配置 AccessKey。密钥走环境变量或密钥管理服务注入,别写进代码,也别打进日志。
- 发送消息时设置消息键,并把返回的消息 ID 记进业务日志。出问题时,日志里能直接对上号。
- 消费端按订单号做幂等处理。重试和网络抖动会带来重复投递,不做这一步,库存可能被扣两次。
- 先在测试主题上灰度,观察堆积量和单条处理耗时。稳定之后再切正式流量,别一步到位。
上线后最容易踩的四个坑
- 消息顺序:全局有序代价很高,多数场景只需要同一订单内有序。用分区键(比如订单号)保证就够了,别为了省事要求全局有序。
- 重复消费:只要有重试,就会有重复。幂等处理不是可选项,是必做项。
- 消息堆积:消费速度跟不上生产速度时,堆积会一直涨。给堆积量配告警,出现堆积先查下游服务,别急着加机器。
- 数据一致性:数据库提交和发消息之间有时间差。如果先提交再发送,进程恰好在两步之间崩溃,消息就丢了。可以用事务消息,或者用本地消息表把两者绑在一起。
什么时候选它,什么时候看别的
如果只是服务之间的异步通知和解耦,ONS 或它的后续产品基本够用。如果场景是高吞吐的日志流或者实时计算,比如每秒几十万条的行为数据,就要同时评估 Kafka 类方案。选型前先确认当前的产品线、规格和计费方式,这些变化比较快。