⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://yangxikun.com/2017/03/22/message-queue.html 「yangxikun」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

消息队列是服务架构中常见的组件,可用于服务间解耦、事件广播、任务异步/延迟处理等,本文对于消息队列的实现如何满足几种消费语义进行了阐述。

消息队列组成

  • 生产者(Producer):负责产生消息
  • 消息代理(Message Broker):负责存储/转发消息(转发分为推和拉两种,拉是指Consumer主动从Message Broker获取消息,推是指Message Broker主动将Consumer感兴趣的消息推送给Consumer)
  • 消费者(Consumer):负责消费消息

img

消息队列的消费语义

  1. 消息至多被消费一次
  2. 消息至少被消费一次
  3. 消息仅被消费一次

为了支持上面3种消费语义,可以分3个阶段考虑消息队列系统中Producer、Message Broker、Consumer需要满足的条件:

1、消息至多被消费一次

该语义是最容易满足的,特点是整个消息队列吞吐量大,实现简单。适合能容忍丢消息,消息重复消费的任务。

  • Producer发送消息到Message Broker阶段:Producer发消息给Message Broker,不要求Message Broker对接收到的消息响应确认,Producer也不用关心Message Broker是否收到消息了。
  • Message Broker存储/转发阶段:对Message Broker的存储不要求持久性,转发消息时也不用关心Consumer是否真的收到了。
  • Consumer消费阶段:Consumer从Message Broker中获取到消息后,可以从Message Broker删除消息,或Message Broker在消息被Consumer拿去消费时删除消息,不用关心Consumer最后对消息的消费情况如何。

2、消息至少被消费一次

适合不能容忍丢消息,允许重复消费的任务。

  • Producer发送消息到Message Broker阶段:Producer发消息给Message Broker,Message Broker必须响应对消息的确认。
  • Message Broker存储/转发阶段:Message Broker必须提供持久性保障,转发消息时,Message Broker需要Consumer通知删除消息,才能将消息删除。
  • Consumer消费阶段:Consumer从Message Broker中获取到消息,必须在消费完成后,Message Broker上的消息才能被删除。

3、消息仅被消费一次

适合对消息消费情况要求非常高的任务,实现较为复杂。

在这里需要考虑一个问题,就是这里的“仅被消费一次”指的是如下哪种场景:

  • Message Broker上存储的消息被Consumer仅消费一次
  • Producer上产生的消息被Consumer仅消费一次

Message Broker上存储的消息被Consumer仅消费一次 场景要求:

  • Producer发送消息到Message Broker阶段:Producer发消息给Message Broker,不要求Message Broker对接收到的消息响应确认,Producer也不用关心Message Broker是否收到消息了。
  • Message Broker存储/转发阶段:Message Broker必须提供持久性保障,并且每条消息在其消费队列里有唯一标识(这个唯一标识可以由Producer产生,也可以由Message Broker产生)。
  • Consumer消费阶段:Consumer从Message Broker中获取到消息后,需要记录下消费的消息标识,以便在后续消费中防止对某个消息重复消费(比如Consumer获取到消息,消费完后,还没来得及从Message Broker删除消息,就挂了,这样Message Broker如果把消息重新加入待消费队列的话,那么这条消息就会被重复消费了)。

Producer上产生的消息被Consumer仅消费一次 场景要求:

  • Producer发送消息到Message Broker阶段:Producer发消息给Message Broker,Message Broker必须响应对消息的确认,并且Producer负责为该消息产生唯一标识,以防止Consumer重复消费(因为Producer发消息给Message Broker后,由于网络问题没收到Message Broker的响应,可能会重发消息给到Message Broker)。
  • Message Broker存储/转发阶段:Message Broker必须提供持久性保障,并且每条消息在其消费队列里有唯一标识(这个唯一标识需要由Producer产生)。
  • Consumer消费阶段:Consumer从Message Broker中获取到消息后,需要记录下消费的消息标识,以便在后续消费中防止对某个消息重复消费(比如Consumer获取到消息,消费完后,还没来得及从Message Broker删除消息,就挂了,这样Message Broker如果把消息重新加入待消费队列的话,那么这条消息就会被重复消费了)。

结语

现在业内已经有许多成熟的消息队列的实现了,对于选择用哪一个实现,可以先根据业务需要支持的消费语义进行初步筛选,之后再根据运维难度、社区活跃度、性能、可用性等综合考虑选择合适的消息队列系统,如何判断一个消息队列实现是否支持某个消费语义,根据本文中阐述的3个阶段去判断即可。

文章目录
  1. 1. 消息队列组成
  2. 2. 消息队列的消费语义
    1. 2.1. 1、消息至多被消费一次
    2. 2.2. 2、消息至少被消费一次
    3. 2.3. 3、消息仅被消费一次
  3. 3. 结语