一次讲清消息队列:从削峰填谷到可靠投递

举报
XIANG.FAN 发表于 2026/11/13 15:12:14 2026/11/13
【摘要】 下单、支付、发短信、扣库存,一次请求背后常常串着好几件任务。把这些任务一个接一个串行做完,用户要等很久;任何一个环节变慢,整条链路都会被拖慢。消息队列就是为了解开这种纠缠而出现的:它让生产消息的一方和处理消息的一方不再直接等待彼此,中间多了一个可靠的缓冲层。理解了这个缓冲层,就理解了消息队列的大半价值。 一、消息队列到底解决什么问题第一个问题是解耦。调用方只需要把消息发出去,不用知道谁来处理...

下单、支付、发短信、扣库存,一次请求背后常常串着好几件任务。把这些任务一个接一个串行做完,用户要等很久;任何一个环节变慢,整条链路都会被拖慢。消息队列就是为了解开这种纠缠而出现的:它让生产消息的一方和处理消息的一方不再直接等待彼此,中间多了一个可靠的缓冲层。理解了这个缓冲层,就理解了消息队列的大半价值。

一、消息队列到底解决什么问题

第一个问题是解耦。调用方只需要把消息发出去,不用知道谁来处理、什么时候处理。新增一个处理方时,调用方一行代码都不用改,只要让新的处理方去订阅同一类消息。

第二个问题是异步。用户下单之后,短信通知、积分发放、数据统计这些事都可以慢慢做。主流程只做最关键的几件事:校验、落单、返回结果,其余工作交给队列慢慢消化,接口响应自然变快。

第三个问题是削峰填谷。流量高峰来临时,队列先把请求接下来,攒在那里,再按处理方的能力有节奏地放出去;流量低谷时,攒下的任务继续消化,资源不会闲置。

这三件事合起来,就是消息队列最常见的价值:让系统在面对波动时既稳得住,也快得起来。

二、核心模型:生产者、队列与消费者

消息队列的核心角色只有三个:生产者负责发送消息;队列负责暂存消息;消费者负责取走消息并处理。生产者发完消息就可以继续做自己的事,不用等待消费者。

在此基础上,常见的投递方式有两种。一种是点对点:一条消息只会被一个消费者取走,适合任务分发。另一种是发布订阅:一类消息可以有多个订阅者,每个订阅者都会收到一份,适合事件通知。

还要理解主题这个概念。主题相当于消息的分类标签,消费者按主题订阅自己关心的消息。生产者只管往主题里发,至于是谁在消费,生产者完全不用操心。这种不知情,恰恰是解耦的关键。

三、削峰填谷是怎么实现的

削峰填谷靠的是队列的缓冲能力。假设平时每秒进来一百个请求,促销时突然涨到每秒一千个。如果直接打到处理方,数据库和服务很可能被压垮。有了队列,突发流量先进入队列排队,处理方按每秒两百个的速度匀速消费,峰值被摊平了。

这里有两个要点。第一,队列的容量要够大,能够装下高峰期积压的消息,否则消息无处可放,系统照样会崩。第二,消费速度要可控,可以通过增加消费者数量来提高消费速度,也可以在流量回落后慢慢把积压消化掉。削峰不是让流量消失,而是把同一时间的压力分摊到一段时间里。

还要注意一点:排队本身会带来延迟。不是所有场景都适合排队,比如要求立刻返回结果的强交互请求,就不适合丢进队列里慢慢处理。

四、可靠投递的四道防线

消息最怕的就是丢。想让消息可靠投递,通常要守住四道防线。

第一道在生产端。生产者发完消息之后,要等到队列确认收到才算成功。如果没有收到确认,就要重试或者告警。只发不管,是丢消息最常见的原因。

第二道是持久化。消息写进队列之后,要落到磁盘上保存下来,而不是只留在内存里。这样即使队列服务重启,消息也不会丢。

第三道在消费端。消费者拿到消息之后,要先处理、处理成功后再确认。确认之前消息一直保留在队列里,万一消费者中途崩溃,消息还能被重新取出来交给别人处理。反过来,如果先确认再处理,处理失败消息就丢了。

第四道是重试与死信。处理失败的消息不会立刻消失,而是按策略重试几次。重试几次仍然失败的消息,会被送进死信队列单独存放,等人工介入处理,而不是悄悄丢弃。

这四道防线环环相扣:生产确认保证消息进了队列,持久化保证消息留得住,消费确认保证消息被处理,重试与死信保证异常有处可去。缺少任何一道,可靠性都会打折。

五、顺序性与重复消费

用了消息队列之后,两个问题几乎一定会遇到:顺序和重复。

顺序问题来自于并行消费。同一类消息被多个消费者并行处理时,先发的消息可能后处理完。如果业务要求严格有序,就要把同一类消息固定分到同一个分区或者同一个消费者,代价是牺牲一部分并发能力。是否需要严格有序,要看业务本身:订单状态流转需要有序,日志采集通常不需要。

重复消费来自于确认机制。消费者处理成功但确认消息丢失时,队列会以为消息没处理完,于是重新投递一次,消费者就会收到重复消息。解决办法是让消费逻辑做到幂等:同样一条消息处理一次和处理多次,结果是一样的。常见做法是给每条消息一个唯一编号,处理前先查编号是否已经处理过,处理过就直接跳过。

六、什么时候不该用消息队列

消息队列不是万能的。它引入了新的组件,就意味着更多的运维成本、更多的故障点和更难排查的问题。

如果调用方必须立刻拿到处理结果,就不要用消息队列,直接调用更简单。如果系统规模很小,流量也很平稳,消息队列带来的复杂度可能超过收益。如果消息量极小、一年也产生不了几条消息,用定时任务或者简单的重试机制就够了。

选型之前先想清楚三个问题:消息丢了能不能接受?消息乱序了会不会出事?消息重复消费了会不会出错?这三个问题想清楚了,队列的配置方式、多大容量、要不要重试,答案自然就出来了。

七、小结:一个可落地的检查清单

回顾全文,消息队列的价值可以用两句话概括:用缓冲扛住流量波动,用确认与重试保障消息不丢。落地时可以对照这份清单检查:生产者是否等待队列确认,失败是否重试;队列是否开启持久化,容量是否留出余量;消费者是否先处理后确认,处理失败是否进入重试;重复投递时消费逻辑是否幂等;需要顺序的场景是否做了分区绑定;死信队列是否有人定期查看。

把这几件事做到位,消息队列就能从一个时髦的组件,变成系统里真正可靠的底座。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。