RabbitMQ整体架构

AMQP协议

AMQP(Advanced Message Queuing Protocol)是一种协议标准,RabbitMQ也是要支持他的。
协议中框架和消息流向如下图:


image.png
AMQP中定义的角色

Publisher:消息发送者,将消息发送到Exchange并指定RoutingKey,以便queue可以接收到指定的消息。
Consumer:消息消费者,从queue获取消息,一个Consumer可以订阅多个queue以从多个queue中接收消息。
Server:一个具体的MQ服务实例,也称为Broker。
Virtual host:虚拟主机,一个Server下可以有多个虚拟主机,用于隔离不同项目,一个Virtual host通常包含多个Exchange、Message Queue。
Exchange:交换器,接收Producer发送来的消息,把消息转发到对应的Message Queue中。
Routing key:路由键,用于指定消息路由规则(Exchange将消息路由到具体的queue中),通常需要和具体的Exchange类型、Binding的Routing key结合起来使用。
Bindings:指定了Exchange和Queue之间的绑定关系。Exchange根据消息的Routing key和Binding配置(绑定关系、Binding、Routing key等)来决定把消息分派到哪些具体的queue中。这依赖于Exchange类型。
Message Queue:实际存储消息的容器,并把消息传递给最终的Consumer。


image.png

RabbitMQ架构图

如下图,生产者和消费者通过交换器绑定,消息从生产者到达交换器后按照交换器指定的规则发送的特定的队列中,消费者再去队列中消费。


image.png

Exchange(交换器)类型介绍:

RabbitMQ常用的交换器类型有: fanout 、direct 、topic 、headers 四种。

Fanout

会把所有发送到该交换器的消息路由到所有与该交换器绑定的队列中,就像风扇一样,把消息“吹到”所有地方。

Direct

direct类型的交换器路由规则很简单,它会把消息路由到那些BindingKey和RoutingKey完全匹配的队列中。

Topic

topic类型的交换器在direct匹配规则上进行了扩展,也是将消息路由到BindingKey和RoutingKey相匹配的队列中,这里的匹配规则稍微不同,它约定:
BindingKey和RoutingKey一样都是由"."分隔的字符串;BindingKey中可以存在两种特殊字符“”和“#”,用于模糊匹配,其中""用于匹配一个单词,"#"用于匹配多个单词(可以是0个)。

Headers

headers类型的交换器不依赖于路由键的匹配规则来路由信息,而是根据发送的消息内容中的headers属性进行匹配。这种类型不建议在生产环境中使用,只需要知道有这种类型就可以了。

RabbitMQ数据存储

RabbitMQ消息有两种类型,持久化消息和非持久化消息,两种消息都会被写入磁盘。
持久化消息在到达队列时写入磁盘,同时会内存中保存一份备份,当内存吃紧时,消息从内存中清除。这会提高一定的性能。
非持久化消息一般只存于内存中,当内存压力大时数据刷盘处理,以节省内存空间。
RabbitMQ存储层包含两个部分,队列索引和消息存储,如下图所示:


image.png
队列索引:rabbit_queue_index

索引维护队列的落盘消息的信息,如存储地点、是否已被给消费者接收、是否已被消费者ack等。每个队列都有相对应的索引。
索引使用顺序的段文件来存储,后缀为.idx,文件名从0开始累加,每个段文件中包含固定的segment_entry_count 条记录,默认值是16384。每个index从磁盘中读取消息的时候,至少要在内存中维护一个段文件,所以设置queue_index_embed_msgs_below 值得时候要格外谨慎,一点点增大也可能会引起内存爆炸式增长。

消息存储:rabbit_msg_store

消息以键值对的形式存储到文件中,一个虚拟主机上的所有队列使用同一块存储,每个节点只有一个。存储分为持久化存储(msg_store_persistent)和短暂存储(msg_store_transient)。持久化存储的内容在broker重启后不会丢失,短暂存储的内容在broker重启后丢失。
store使用文件来存储,后缀为.rdq,经过store处理的所有消息都会以追加的方式写入到该文件中,当该文件的大小超过指定的限制(file_size_limit)后,将会关闭该文件并创建一个新的文件以供新的消息写入。文件名从0开始进行累加。在进行消息的存储时,RabbitMQ会在ETS(Erlang TermStorage)表中记录消息在文件中的位置映射和文件的相关信息。
消息(包括消息头、消息体、属性)可以直接存储在index中,也可以存储在store中。最佳的方式是较小的消息存在index中,而较大的消息存在store中。这个消息大小的界定可以通过queue_index_embed_msgs_below 来配置,默认值为4096B。当一个消息小于设定的大小阈值时,就可以存储在index中,这样性能上可以得到优化。一个完整的消息大小小于这个值,就放到索引中,否则放到持久化消息文件中。
如果消息小于这个值,就在索引中存储,也就是存储于<num>.idx索引文件中,如果消息大于这个值就在store中存储,也就是存储在msg_store_persistent目录中的<num>.rdq文件中,小于这个值消息存储于<num>.idx索引文件中。

消息堆积带来性能下降

系统负载高的时候,消息没有被消费掉,这样消息会进入很深的队列中。这样会花费更多的时间处理堆积消息,所以每个消息平均开销会增大,会导致系统处理性能下降。

  1. 增加prefetch_count的值,即一次发送多条消息给消费者,加快消息被消费的速度。
  2. 采用multiple ack,降低处理 ack 带来的开销。
  3. 流量控制。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • RabbitMQ 主要处理的问题 限流(削峰) 解耦 异步 RabbitMq 常用的交换器类型 fanout (分...
    布衣码农阅读 9,568评论 0 0
  • RabbitMQ 简介 1. RabbitMQ 介绍 行业还是传统行业都广泛使用(最早是为了解决电信行业系统之间的...
    左师兄zuosx阅读 2,350评论 0 1
  • 一、概述 RabbitMQ,俗称“兔子MQ”(可见其轻巧,敏捷),是目前非常热门的一款开源消息中间件,不管是互联网...
    zephyrlai阅读 4,425评论 1 0
  • RabbitMQ是采用Erlang语言实现AMQP(Advanced Message Queuing Protoc...
    陈晨_软件五千言阅读 6,225评论 0 5
  • 序言: 文章内容输出来源:拉勾教育Java高薪训练营。本篇文章是学习课程中的一部分课后笔记 一、RabbitMQ介...
    西西弗斯XD阅读 2,507评论 0 0