当设计消息队列时我们关心什么

简介: 在开发中应用过ActiveMQ,kafka等mq,不过对消息队列背后的实现原理关注不多,其实了解消息队列背后的实现特别重要,比如对一致性等实现的关注,可以帮助我们在开发中避免踩坑,规避问题的出现。这篇文章简单探讨下当设计和实现一个消息队列时,我们需要关心哪些地方。

应用消息队列可以对系统进行解耦,流量削峰,在分布式系统设计中,消息队列是重要的组件之一。

在开发中应用过ActiveMQ,kafka等mq,不过对消息队列背后的实现原理关注不多,其实了解消息队列背后的实现特别重要,

比如对一致性等实现的关注,可以帮助我们在开发中避免踩坑,规避问题的出现。这篇文章简单探讨下当设计和实现一个消息队列时,我们需要关心哪些地方。

 

消息队列功能和特性

一个传统意义上的消息队列,需要支持消息的发送,接受和消息暂存的功能。

在实际应用中,对消息队列的要求远不止于此,在不同的业务场景中,需要消息队列提供如顺序消息,消息可靠性,消息持久化等需求。

 

1.即时通信和消息队列

从消息能否会被即时接受和处理的角度,可以把消息传递的方式分为两种。

一种是即时消息通讯,也就是说消息从发送者一端发出后立即就可以达到接收者一端;

另一种方式称为延迟消息通讯,即消息从某一端发出后,首先进入一个容器进行临时存储,当达到某种条件后,再由这个容器发送给另一端。

延迟消息通讯的容器实现就是消息队列。

2.消息队列基础功能

消息队列需要支持消息的发送,消息暂存,和消息的异步消费,

3.消息队列需要支持的特性

除了基本功能以外,消息队列在某些特殊的场景还需要支持事务,消息重试等功能。

  • 消息的顺序
  • 投递可靠性保证
  • 消息持久化
  • 支持不同消息模型
  • 多实例集群功能
  • 分布式环境下的负载均衡

 

消息队列的基础设计

为了实现消息队列的基础功能,即消息的传输,存储和消费,

需要从以下几个维度去进行设计:

  • 通信协议
  • 存储选择
  • 消费关系维护

1.通信协议

消息既是信息的载体,消息发送者需要知道如何构造消息,消息接收者需要知道如何解析消息,它们需要按照一种统一的格式描述消息,这种统一的格式称之为消息协议。没有格式的消息是没有意义的。

传统的通信协议标准有XMPP和AMQP协议等,现在更多的消息队列从性能的角度出发使用自己设计实现的通信协议。

(1)AMQP规范和JMS规范

AMQP 是 Advanced Message Queuing Protocol,即高级消息队列协议。AMQP不是一个具体的消息队列实现,而 是一个标准化的消息中间件协议。目标是让不同语言,不同系统的应用互相通信,并提供一个简单统一的模型和编程接口。 目前主流的ActiveMQ和RabbitMQ都支持AMQP协议。

JMS是Java平台的一部分,是一种应用于异步消息传递的标准API,JMS可以允许不同应用、不同模块之间实现可靠、异步数据通信。

在JMS中,支持两种消息模型,点对点(Point-to-point)和发布-订阅(Publish and subscribe), 这两种模式分别对应于JMS中的两种消息目标(Message Destination):队列及主题(queue/topic)。

(2)Kafka的通信协议

Kafka的Producer、Broker和Consumer之间采用的是一套自行设计的基于TCP层的协议。Kafka的这套协议完全是为了Kafka自身的业务需求而定制的,而非要实现一套类似于Protocol Buffer的通用协议。

2.消息存储

消息队列常常保存在链表结构中,拥有权限的进程可以向消息队列中写入或读取消息。

对于分布式系统,消息存储的选择有以下几种:

  • 内存
  • 本地文件系统
  • 分布式文件系统
  • 关系型数据库
  • NoSQL数据库

从速度上内存显然是最快的,对于允许消息丢失,消息堆积能力要求不高的场景(例如日志),内存会是比较好的选择。关系型数据库则是最简单的实现可靠存储的方案,很适合用在可靠性要求很高,最终一致性的场景(例如交易消息)。

对于不需要100%保证数据完整性的场景,要求性能和消息堆积的场景,hbase也是一个很好的选择,典型的比如 kafka的消息落地可以使用hadoop。

 

3.消费关系维护

消息队列需要支持点对点和发布/订阅模式的消费模型, 消费端的消费进度也需要记录,典型的如消费端重连的处理,参考Kafka对每个Consumer提供一个偏移量的支持。

另外消息队列选择Pull还是Push模型进行实现也非常重要。在消费端,ActiveMQ使用PUSH模型,而Kafka使用PULL模型,两者各有利弊。对于PUSH,broker很难控制数据发送给不同消费者的速度,而PULL可以由消费者自己控制,但是PULL模型可能造成消费者在没有消息的情况下盲等,这种情况下可以通过long polling机制缓解。对于几乎每时每刻都有消息传递的流式系统,使用Pull模型更合适。

 

消息队列高级特性实现

1.消息有序支持

消息队列中消息的有序性直接依赖与存储的选择,并且和存储的分布式部署以及消费端的并发情况密切相关。

消息的有序可以使用存储的顺序性来支持,比如Kafka,在一个partition上是一段连续的存储,可以保证这一段连续的消息有序。

使用Redis可以实现一个简单的消息队列,保证生产端和消费端都是单线程的生产和消费,因为底层数据机构有序,就可以实现消息的有序。

2.投递可靠性支持

消息投递的可靠性涉及到分布式数据一致性的话题,比如如何保证不丢数据,消息的幂等此类的问题。

RabbitMQ的设计是,当从队列当中取出一个消息的时候,RabbitMQ需要应用显式地回馈说已经获取到了该消息。如果一段时间内不回馈,RabbitMQ会将该消息重新分配给另外一个绑定在该队列上的消费者。另一种情况是消费者断开连接,但是获取到的消息没有回馈,则RabbitMQ同样重新分配。

投递的可靠性需要消费端和生产端一些约定的规则进行约束,保证投递的可靠性,肯定会影响性能,需要一些额外的工作来记录消息的状态等。

3.消息确认机制

消息确认机制可以给消息一致性提供支持,包括发送端的确认和消费端的确认,AMQP 协议本身使用的是事务机制进行消息确认,但是事务机制性能较差,并且容易发生阻塞。

Kafka应用的是ACK机制,RabbitMQ也设计了单独的消息确认机制。

4.消息发送和投递方式

消息队列支持不同的投递语义,以Kafka为例,提供三种不同的语义:

  • At most once 消息可能会丢,但绝不会重复传输
  • At least one 消息绝不会丢,但可能会重复传输
  • Exactly once 每条消息肯定会被传输一次且仅传输一次

类似的有阿里巴巴的MQ中间件,发送普通消息有三种实现方式:可靠同步发送、可靠异步发送、单向(Oneway)发送。

 

  • 可靠同步发送:

  

  • 可靠异步发送:

 

  • 单向(Oneway)发送

 
除了上面列出的这些,在设计消息队列时还要结合自己实际的业务场景,开源的MQ实现常常不能满足需求,
这也是为什么大的互联网公司都有自己的消息队列,并且不止一种,比如阿里巴巴的MetaQ,RocketMQ和notify等。
 

目录
相关文章
|
7天前
|
消息中间件 存储 监控
消息队列通信的优缺点
【10月更文挑战第29天】消息队列通信具有诸多优点,如解耦性强、异步通信、缓冲削峰等,能够有效地提高系统的灵活性、可扩展性和稳定性。但同时也存在一些缺点,如系统复杂性增加、性能开销、数据一致性挑战和实时性受限等。在实际应用中,需要根据具体的业务需求和场景,权衡其优缺点,合理地选择和使用消息队列通信机制,以实现系统的高效运行和优化。
|
5月前
|
消息中间件 存储 安全
【消息队列开发】 实现ConsumerManager类——消费消息的核心逻辑
【消息队列开发】 实现ConsumerManager类——消费消息的核心逻辑
|
1月前
|
消息中间件 存储 监控
消息队列系统中的确认机制在分布式系统中如何实现
消息队列系统中的确认机制在分布式系统中如何实现
|
24天前
|
消息中间件 存储 监控
消息队列系统中的确认机制在分布式系统中如何实现?
消息队列系统中的确认机制在分布式系统中如何实现?
|
3月前
|
消息中间件 存储 Java
【揭秘】RocketMQ内部运作大揭秘:一探究竟,原来消息队列是这样工作的!
【8月更文挑战第19天】RocketMQ是一款高性能、高可用的消息中间件,在分布式系统中至关重要。它采用发布/订阅模式,支持高吞吐量的消息传递。核心组件包括管理元数据的NameServer、存储消息的Broker以及Producer和Consumer。RocketMQ支持发布/订阅与点对点两种模型,并具备复杂的消息持久化和路由机制。通过Java API示例,可轻松实现消息的发送与接收。RocketMQ凭借其出色的特性和可靠性,成为大型分布式系统首选的消息解决方案。
72 5
|
5月前
|
消息中间件 JavaScript Java
消息队列 MQ产品使用合集之如何动态增加consumerquque
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
4月前
|
消息中间件 存储 RocketMQ
MetaQ/RocketMQ 原理问题之在解耦场景中,消息队列工作的问题如何解决
MetaQ/RocketMQ 原理问题之在解耦场景中,消息队列工作的问题如何解决
|
5月前
|
消息中间件 中间件 API
中间件消息队列的优势解耦
【6月更文挑战第7天】
52 3
|
6月前
|
消息中间件 缓存 API
【后端面经】【消息队列】22 | 消息队列:消息队列可以用来解决什么问题?-03 扩展性+可用性+事件驱动思想
【5月更文挑战第8天】 本文探讨了扩展性、可用性和事件驱动的概念。扩展性方面,消息队列简化了新下游的接入,而同步调用需要复杂的协调。在保证高可扩展性和研发效率的设计中,若无法使用消息队列,可以提供一致性抽象来减轻接入负担。可用性上,消息队列只需确保消息发送,而同步调用需保证所有下游成功,更易出错。事件驱动是一种通过事件进行组件间通信的架构模式,具有低耦合、高扩展性和高可用性,适合处理复杂流程。结合SAGA的事件驱动方案能实现高级分布式事务管理,即使实时性稍弱,但能保证事务的异步和高效执行。
51 1
|
5月前
|
消息中间件 Java 数据库
【消息队列开发】 实现DataBaseManager类
【消息队列开发】 实现DataBaseManager类
下一篇
无影云桌面