RabbitMQ实战指南学习

一 AMQP协议

1 协议
在这里插入图片描述

二 消费模式

1 服务端(broker)推送
推模式采用Basic.consume进行消费,可以通过BasicQos设置一次性推送的消息数量。
在这里插入图片描述

2 消费端拉取
拉模式采用Basic.Get进行消费,一次性只能获取一条消息。
在这里插入图片描述

三 消费端的确认与拒绝

1 autoAck
当autoAck设置为true时,rabbitmq会把发送出去的消息自动置为确认,然后从内存或者磁盘上删除。
当autoAck设置为false时,消费的消息分为两种状态,一种是等待投递的消息,一种是发送出去还没有被确认的消息。注意,这里没有被确认的消息只会等到检测到消费者连接已经断开的时候才会重新投递,否则这条消息会一直等到消费者确认之后才被标记删除。目前rabbitmq不会给未被确认的消息设置过期时间。
查看未被确认的消息是通过web页面的Ready(已发送)以及Unackonwledged(未确认)来查看。

2 拒绝消息
拒绝单条消息,basicReject(消息标识,是否重新入队分发);
拒绝多条消息, basicNack(消息标识, 是否只拒收这一条消息(true表示这条消息之前的,本次接受的所有消息都拒收。false表示只拒收这一条消息), 是否重新入队分发)
重发消息,basicRecover(是否让不同的消费者来消费这条消息(false表示还是自己消费))

四 进阶

1 mandatory与immediate参数
首先注意rabbitmq3.0之后取消了对immediate的支持
mandatory设置为true,在消息达到交换机之后,但交换机没有根据自身的类型或者路由键找到对应的队列,此时会通过Basic.Return命令触发生产者的ReturnCallBack。当mandatory设置为false时,会直接丢弃消息。
immediate设置为true, 在经过交换机路由到队列之后,队列本身没有任何消费者,此时会通过Basic.Return命令触发生产者的ReturnCallBack,此时消息不会入队等待消费者。当immediate设置为false时,会存入队列等待消费者。

2 备份交换机
可以理解为简化了mandatory设置为true时的额外操作,当没有队列可达时会触发生产者的ReturnCallBack,这个时候还需要写处理这条消息的逻辑,而设置备份交换机之后,就不会触发ReturnCallBack逻辑了(即使mandatory=true也不会触发ReturnCallBack),而是直接路由到这个备份交换机,之后备份交换机的行为与普通交换机没有任何区别。
路由交换机的声明方式与死信类似,只不过参数为alternate-exchange。因为找不到队列的消息被路由到备份交换机之后的行为与普通交换机没有任何区别,因此一般将备份交换机的类型设置为fanout,以保证肯定能被路由到某个队列中去。
在这里插入图片描述

3 过期时间
设置队列中消息的过期时间:x-message-ttl(设置为0表示需要立刻投递,如果没有消费者或者投不出去则直接丢弃)
在这里插入图片描述

设置单条消息的过期时间:消息属性中设置expiration
在这里插入图片描述

设置队列的过期时间:x-expires,表示多长时间未被使用就被删除,而不是创建过后多长时间被删除。
在这里插入图片描述
在这里插入图片描述

4 死信
消息变成死信的几种情况
①消息被拒绝,并且是否重新入队参数设置为false
②消息过期
③队列达到了最大长度
设置死信队列:x-dead-letter-exchange(设置死信交换机的名字),x-dead-letter-routing-key(设置路由到死信交换机时候的RoutingKey,如果不设置则用原消息的RoutingKey)
在这里插入图片描述

5 优先级队列
优先级体现在消费速度比生产速度慢的时候才有意义,否则生产即被消费优先级就没有意义。
队列优先级设置:x-max-priority 最小为0最大为10
在这里插入图片描述

消息优先级设置:priority属性,最小为0,最大为队列优先级设置的值
在这里插入图片描述

6 RPC
在这里插入图片描述

如图,主要通过两个属性来设置请求ID与响应队列。replayTo(队列名),由客户端提供,可以理解为生产者,指定消费者处理之后发送响应的队列名,一般是临时队列并且是每个生产者客户端独享的。请求ID可以直接用correlationId即可。
客户端:
在这里插入图片描述

服务端:

在这里插入图片描述

7 持久化
rabbitmq持久化分为三块(交换机与队列的持久化只会持久化本身的元数据,并不会对消息进行持久化):
①交换机的持久化,声明交换机时通过durable属性设置
②队列的持久化,声明队列时通过durable属性设置
③消息的持久化,将投递消息时候的BasicProperties中的DeliveryMode设置为2即可实现消息的持久化,但并不建议所有的消息都持久化,原因就是磁盘与内存的差距(springboot默认消息持久化的)。

8 事务
在这里插入图片描述

9 发送方确认
同步确认其实与事务模式没有特别大的区别,因为发送之后都需要等待数据落盘之后才会返回,区别在于事务需要commit与commitOK,而消息确认只需要一个ACK或者NACK。因此要想提升QPS就需要采用异步确认消息。即spring提供的confirmCallBack方法。

在这里插入图片描述

10 消费端注意
默认是采用消息轮询的机制来分发消息,但是在消费端配置不均衡的情况下会产生消息堆积,因此可以设置消费端的消息上限
basicQos(int prefetchSize(消息总大小,单位B), int prefetchCount(消息总条数), boolean global(默认false即可)) throws IOException;

在这里插入图片描述

11 消息传输的保证

在这里插入图片描述
在这里插入图片描述

五 集群

1 普通集群
这种集群队列交换机什么的都是各个节点单独的,没有数据的互相备份,并且只建议在内网环境搭建,对延迟较敏感。通过将第一个机器的erlang.cookie中的值复制到其他机器下,然后分别启动各个节点,通过rabbitmqctl命令来操作集群的加入,注意:集群所有节点重启时,需要先重启最后一个停止的节点,否则会出错,解决方法就是重置集群然后重新挨个加入集群。

2 Federation
目的在于让消息可以在不同的broker之间传递而无需建立集群,主要是模拟建立一个本地(不是用户客户端,而是broker)的交换机或者队列,然后在这个交换机或者队列中建立一个针对远端broker的连接。业务所有的处理都在本地进行,之后再同步到远端的broker。
在这里插入图片描述
在这里插入图片描述

3 Shovel
简单来讲类似一个铲子,将一个队列的数据源源不断地发送到另一台broker的交换机。可以利用它来实现某个集群中消息堆积队列的数据按配置转移到另一个集群中。

在这里插入图片描述

六 高阶

1 存储机制
首先明确,rabbitmq消息设置持久化会被持久化到磁盘,但是消息没有设置持久化也会可能由于内存不足的原因持久化到磁盘,区别在于重启之后设置持久化的消息不会丢失,而没有设置持久化的消息即使被持久化了依然会丢失。
在逻辑上来讲,消息分为两个部分,一个是索引即rabbit_queue_index(每个队列单独维护,包括数据的存储位置,是否被发送给消费者,是否ACK,是否落盘等),另一个是消息本身即rabbit_msg_store(由每个broker统一维护)。rabbit_msg_store从技术上又分为两部分,分别对应上面持久化持久化消息的msg_store_persistent,以及持久化非持久化消息的msg_store_transient。
消息可以存储在rabbit_msg_store,也可以直接存储在rabbit_queue_index中。当消息大小小于queue_index_embed_msgs_below(默认为4096B,包括消息属性以及headers的总大小)时,存放在rabbit_queue_index中,在性能上得到优化。

2 rabbit_queue_index
每个rabbit_queue_index以顺序的段文件(从0开始的.idx文件)保存,每个段文件中包含固定数量SEGMRNT_ENTRY_COUNT(默认16384)条数据,并且每个队列都至少在内存中维护一个rabbit_queue_index段。

3 rabbit_msg_store
每个rabbit_msg_store也是以顺序的文件进行保存(从0开始的.rdq),每个文件最大大小由file_size_limit控制,在消息映射的时候,会在ETS(erlang term storge)表中映射index以及文件的相关信息。
在读取消息的时候,会根据消息的mag_id找到对应的存储文件,如果文件存在并且没有被锁住,则直接打开读取,否则不存在或者被锁住则由rabbit_msg_store处理。
消息的删除是在ETS上面删除消息的相关信息,并不会在文件中实际删除,当一个文件中都被标记删除之后这个文件就可以真正删除了。否则当检测到逻辑上相邻的两个文件可以合并在一个文件中,并且所有(这里指所有的消息)被标记删除的数量值与总的消息数量比达到阈值GARBAGE_FRACTION(默认0.5)之后才会将这两个文件进行合并。合并时先锁定这两个文件,然后清理第一个文件的垃圾,然后把第二个文件的有效数据写入第一个文件,最后再删除第二个文件。

4 队列的结构
队列由两部分组成,一部分rabbit_amqqueue_process(负责处理协议的相关消息,包括接收消息,发送消息,消息的确认等等),另一部分是backing_queue(消息的实际存储引擎,向rabbit_amqqueue_process提供接口调用)。
如果投递的目标队列是空的并且有消费者订阅了这个队列,那么消息会被立刻转到消费者那里,并不会进入队列存储。否则则需要暂存队列等待处理,消息在队列中一般有四种状态:
在这里插入图片描述

对于持久化的消息,消息内容和索引都必须先存储到磁盘中,然后才有上面的四种状态中的一种,gamma消息是只有持久化的消息才有的状态。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5 惰性队列
惰性队列会将消息直接持久化到磁盘,不会占用内存。适用于消息长时间得不到消费的情况。
通过x_queue_mode来设置,默认是default,可以设置为lazy开启惰性队列。
在这里插入图片描述

6 磁盘内存警告
内存:
使用内存占总内存的百分比vm_memory_high_watermark (配置fraction默认0.4)超出后会阻断所有生产者的操作,使用内存总量vm_memory_high_watermark (配置absolute单位可以自定义)超出后会阻断所有生产者的操作。设置为0则表指禁止生产者发送消息。内存使用降低后阻塞解除。
在磁盘或者内存预警时,会阻塞connection上的所有操作,因此应该尽量将消费者与生产者分开,使用不同的connection进行操作,当阻塞时,消费者的connection是可以正常操作的。
当内存使用达到memory_high_watermark_paging_ratio时(默认0.5,表示达到设置内存最高值的0.5倍,假设总内存是4G, vm_memory_high_watermark=0.4,那么这个值的计算结果就是4GB0.40.5 = 800MB),会产生内存换页动作,即刷盘。
磁盘:
磁盘耗尽也会使生产者阻塞,通过disk_free_limit,可以直接设置固定的值,例如1G,也可以设置与内存的比例值,例如disk_free_limit:mem_relative:1.8,当磁盘还有总内存*1.8的大小之后告警。

7 流控
除了设置内存磁盘的空间之外,还可以提前通过流控来处理生产消费速率。erlang的每个进程都有一个进程邮箱,进程间的通信就是往邮箱里发信息,当消费速度过慢时邮箱越来越大,导致素色,从而影响上游进程的邮箱最终导致整个系统阻塞。
流控采用的是信用证算法。即每个进程保存两个credit,一个是发给上游进程的凭证,一个是下游进程给自己发送的凭证。例如B发给C一个消息,则内部的credit_fromC减1,当为0时则不能再给C发消息,也不能接受A传过来的消息。credit_toA表示再接收多少条消息就给A发送增加credit的消息,此时A会增加自己的credit_fromB的值,当credit_fromB>0时,就可以给B发送消息了。
在这里插入图片描述

当流控产生的时候,connection被标记为flow,表示发送受限。流控不光再connection体现,只在channel以及队列上同样体现。当其中一块阻塞之后,上游的必定全部阻塞,因此可以通过这个找到性能交叉的那些地方,几个关键点如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8 打破队列的瓶颈
首先注意设置内存值与磁盘剩余量,然后一般情况下最容易在队列也就是rabbit_qmqqueue_process模块出现瓶颈,最方便的就是增加队列的数量,但不是类似于fanout的那种群发队列。而是direct交换机声明多个队列,然后根据不同的bindingkey绑定到不同的交换机上。在发送数据的时候随机bindingkey进行发送。消费者消费的时候监听这多个queue即可。这样可以实现消息队列的真正负载。但是消息是无序的。

9 镜像队列(可以看其他资料重点了解,这里只简单记录)
rabbit集群中各个队列还是只有一份数据,为了保证数据冗余可以开启镜像队列,会将队列的数据荣誉到其他broker上。如果客户端与slave建立连接,那slave会将存储或者消费的命令发给master,然后再由master执行完成之后返回给slave,slave在返回给客户端。这里slave不直接处理是因为master是针对单个队列存在的而不针对于整个broker,所以其本身其实已经起到了负载的功能。master宕机之后存活时间最长的slave将被选举为master。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值