笔记-《RabbitMQ实战指南》

目录

    • 1.发到Mq对应的3个参数:Exchange(交换器),RountingKey(路由键),param
    • 2.队列
    • 3.Exchange(交换器)
    • 4.Binding(绑定)
    • 5.交换器类型
    • 6.Connection(连接),Channel(信道)
    • 7. AMQP协议
    • 8. 判断Channel或者Connection关闭状态
    • 9. 交换器和队列的autodelete属性
    • 10.交换器的internal属性
    • 11.队列的exclusive属性
    • 12.性能
    • 13.消费模式
    • 14.重新推给消费者的契机
    • 15.发送的消息丢了怎么办
    • 16.消息的TTL
    • 17.队列的TTL
    • 18.死信队列DLX
    • 19.其他队列
    • 20.持久化
    • 21.生产者确认
    • 22.消费者-消息分发策略
    • 23.消息传输保障
    • 24.多租户
    • 25.RabbitMq定制化
    • 26.RabbitMq集群
    • 27.检测RabbitMq服务是否健康
    • 28.存储机制
    • 29.内存及磁盘告警
    • 30.流控
    • 31.镜像队列
    • 32.网络分区
    • 33.消息追踪
    • 34.负载均衡
    • 99.其他

1.发到Mq对应的3个参数:Exchange(交换器),RountingKey(路由键),param

笔记-《RabbitMQ实战指南》_第1张图片

2.队列

RabbitMq中的消息只能存在队列中,消费者从队列中获取消息并消费。
而Kafka讲消息存在topic中,对应的队列只是topic实际存储文件中的位移标识。

多个消费者订阅同一个队列时,轮询,所以也不支持队列层面的广播(可以二次开发)

3.Exchange(交换器)

RabbitMq内真实情况:
生产者将消息发送给Exchange,由交换器将消息路由到一个或多个队列。若路由不到,则返回生产者,或直接丢弃

4.Binding(绑定)

Rounting key需要与交换器类型和绑定键(BindingKey)联合起来使用。
通过绑定将交换器和队列关联。
生产者将消息发送给交换器时,需求一个RountingKey,当BindingKey和RountingKey相匹配时,消息会被路由到对应的队列中。在绑定多个队列到同一个交换器时,这些绑定允许使用相同的BindingKey。
BindingKey并不是所有的情况都生效,取决于交换器类型。

5.交换器类型

  • fanout
    把发送的消息路由到所有与该交换器绑定的队列中。
  • direct
    RountingKey与BindingKey完全匹配
  • topic
    RountingKey与BindingKey模糊匹配
    “*“用于匹配一个单词,”#”用于匹配多规格单词(可以是零个)
    笔记-《RabbitMQ实战指南》_第2张图片
  • headers
    不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
    性能差,基本上不用。

6.Connection(连接),Channel(信道)

Connection,TCP连接
Channel,AMQP信道,每个信道都会被指派一个唯一 的ID。
笔记-《RabbitMQ实战指南》_第3张图片
引入信道的原因:
多Connection也可以用,但是在多线程情况下,建立多个Connection即建立多个TCP连接,而建立和销毁TCP连接是非常昂贵的,如遇使用高峰,性能也会有瓶颈。RabbitMq采用类似NIO的做法,选择TCP连接复用。

注:NIO,非阻塞IO,包含Channel,Buffer和Selector。NIO基于Channel和Buffer进行操作,数据总是从信道读取数据到缓冲区,或者从缓冲区读取到信道中。Selector用于监听多个信道的事件。因此,单线程可以监听多个数据的信道。

7. AMQP协议

包含三层:

  1. Module Layer:位于协议最高层。定义了一些供客户端调用的命令。
  2. Session Layer:位于中间层。主要负责将客户端的命令发送给服务器,再讲服务器的应答返回给客户端。为客户端和服务器之间的通信提供可靠性同步机制和错误处理。
  3. Transport Layer:位于最底层。主要传输二进制数据流,提供帧的处理,信道复用,错误检测和数据表示等。

8. 判断Channel或者Connection关闭状态

Channel或Connection中有个isOpen方法,但是有可能会产生竞争,所以并不可靠。
正确的是,在使用Channel的时候处于关闭状态的时候,会抛出ShutdownSignalException异常;Connection关闭的时候,会抛出SocketException或IOException异常。捕捉异常即可。

9. 交换器和队列的autodelete属性

交换器:当属性值设置为true时,当所有的队列断开于交换器的绑定,那么交换器会自动删除。如果从未被绑定过,则不会被删除。
队列:当所有的相关消费者断开连接时,队列将会被删除
autodelete属性针对的是曾经有过但后来没有的事物。

10.交换器的internal属性

设置是否是内置的。如果设置为true,表示是内置的交换器。客户端程序无法直接发送消息到这个交换器中,只能通过交换器路由到交换器这种方式。

11.队列的exclusive属性

设置是否排他。为true则设置队列是排他的,则队列仅对首次声明它的连接(Connection)可见,并在断开连接时自动删除。
同一个Connection中的Channel可以同时访问同一连接创建的排他队列。
首次是指,如果一个连接已声明一个排他队列,则其他连接不允许创建同名的排他队列。
与普通队列不同,一旦连接关闭或客户端退出,该排他队列都会被自动删除。
这种队列适用于一个客户端同时发送和读取消息的应用场景。

12.性能

RabbitMq的消息存储在队列中,因此交换器的使用并不会真正消耗服务器的性能,而队列会。
如果要衡量RabbitMq的QPS只需要看队列即可。

13.消费模式

分为两种:推(Push)模式和拉(Pull)模式。推模式采用Basic.Consume进行消费,拉模式采用Basic.Get进行消费。
推:持续订阅

14.重新推给消费者的契机

RabbitMq不会为未确认(即autoack为false时,消费者还未返回ack)的消息设置过期时间,判断的唯一依据是该消息的消费者连接是否已经断开。

15.发送的消息丢了怎么办

两个参数:
mandatory:为true时,交换器无法根据自身的类型和路由键找到符合的队列,那么RabbitMq会调用Basic.Return命令将消息返回给生产者;为false,则消息直接丢弃。
immediate(RabbitMq现已不支持该参数的维护):为true,如果交换器在将消费路由到队列时发现队列上并不存在任何消费者,那么消息不会存入该队列。所有与路由匹配的队列都没有消费者时,会通过Basic.Return返回给生产者。

16.消息的TTL

  1. 设置队列属性,即队列中所有消息都有相同的过期时间。
    消息一旦过期,立马会从队列中抹去。队列中已过期的消息肯定在队列头部,RabbitMq只要定期从队头开始扫描是否有过期的消息即可。
  2. 对消息本身单独设置。
    即使消息过期,也不会立马从队列中抹去。每条消息的过期时间不一致,如果要删除只能扫描整个队列,所以会等到此消息即将被消费时才会判断是否过期及删除。

两种一起使用,则以两者较小的那个数值为准。
消息在队列中的时间超过TTL,则变成“死信”,消费者无法再接收(不绝对)。
不设置TTL代表消息永不过期;设置为0,代表除非此时可以直接将消息投递给消费者,否则直接丢弃。

17.队列的TTL

x-expires(单位:毫秒)参数可以控制队列被自动删除前处于未使用状态的时间。未使用的意思是队列上没有任何的消费者,也没有被重新声明,并且在过期时间段内也未调用过Basic.Get命令。
会确保在过期时间到达后将队列删除,但不保障删除的动作的及时性。在RabbitMq重启后,持久化的队列的过期时间会被重新计算。

18.死信队列DLX

也叫做死信交换器或死信邮箱。
当一个消息在一个队列中变成死信后,它能被重新发送到另一个交换器中,这个交换器就是DLX,绑定DLX的队列就称之为死信队列。
消息变成死信的几种情况:

  1. 消息被拒绝(Basic.Rejext/Basic.Nack),并且设置requeue参数为false;
  2. 消息过期;
  3. 队列达到最大长度。

19.其他队列

延迟队列:存储的对象是对应的延迟消息。
优先级队列:默认最低为0。

20.持久化

  • 交换器的持久化:声明交换器时设置durable参数为true;
    若不设置持久化,则相关的交换器元数据会丢失,消息不会丢失,只是不能将消息发送到这个交换器中了。
  • 队列的持久化:声明队列时设置durable参数为true;
    若不设置持久化,则相关的队列元数据会丢失,消息也会丢失。
    队列的持久化能保证本身的元数据不会因异常情况丢失,但不能保证内部存储的消息不丢失。要确保消息不丢失,需要消息的持久化。
  • 消息的持久化。
    将投递模式deliveryMode属性设置为2即可实现消息的持久化。

21.生产者确认

  • 事务(重量级,带来性能损耗)
    RabbitMq客户端与事务机制相关的三个方法:
    1 . channel.txSelect:用于将当前信道设置为事务模式
    2 . channel.txCommit:提交事务
    3 . channel.txRollback:回滚事务
  • 发送方确认(publisher confirm)机制实现
    生产者将信道设置成confirm(确认)模式,一旦信道进入confirm模式,所有在该信道上发布的消息都会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列,RabbitMq就会发送一个确认(Basic.Ack)给生产者(包含消息的唯一ID)。
    如果消息和队列是持久化的,那确认消息会在消息写入磁盘后发出。

事务机制和confirm机制的QPS差不多,confirm机制略胜一点点。因为confirm机制也是每发送一条消息就需要等待服务端的确认,实际上是一种串行同步等待的方式。事务机制也一样,发送消息后等待服务端确认,之后再发送消息。两者的存储确认原理相同,尤其对于持久化的消息来说,两者都需要等待消息确认落盘之后才会返回。
事务机制和confirm机制是互斥的,不能共存。
事务机制和confirm机制确保的是消息能够正确的发送到RabbitMq,这里是指发动到交换器,如果此交换器没有匹配的队列,那么消息也会丢失。

优化:批量或异步。

22.消费者-消息分发策略

默认:轮询
有可能会造成整体吞吐量下降
优化:计数,每发一条消息,计数+1,消费完一条消息,计数-1。设置一个计数上限。类似于TCP/IP的滑动窗口。(对于拉模式的消费方式无效)

23.消息传输保障

一般消息中间件的消息传输保障分为三个层级

  1. At most once:最多一次。消息可能会丢失,但绝不会重复传输。
  2. At least once:最少一次。消息绝不会丢失,但可能会重复传输。
  3. Exactly once:恰好一次。每条消息肯定会被传输一次且仅传输一次。

RabbitMq支持”最多一次“和”最少一次“

24.多租户

虚拟主机(vhost):每一个RabbitMq服务器都能创建虚拟的消息服务器。每一个vhost本质上是一个独立的小型RabbitMq服务器,拥有自己独立的队列,交换器及绑定关系等,并且它拥有自己独立的权限。
RabbitMq里,权限规则是以vhost为单位的。

25.RabbitMq定制化

RabbitMq提供了三种方式来定制化服务

  1. 环境变量:shell环境中设置,或rabbitmq-env.conf配置文件
  2. 配置文件:rabbitmq.config
    配置加密,默认的Hash算法是SHA512
  3. 运行时参数和策略
    RabbitMq中一共有两种类型的Parameter:vhost级别的Parameter和global级别的Parameter。

26.RabbitMq集群

集群的所有节点都会备份所有的元数据信息:

  1. 队列元数据:队列的名称及属性
  2. 交换器:交换器的名称及属性
  3. 绑定关系元数据:交换器与队列或者交换器与交换器之间的绑定关系
  4. vhost元数据:为vhost内的队列、交换器和绑定提供命名空间及安全属性

如果关闭了集群中的所有节点,则需要确保在启动的时候最后关闭的那个节点是第一个启动的。若第一个启动的不是最后关闭的节点,那么这个节点会等待最后关闭的节点启动。这个等待时间是30秒,如果没有等到,那么这个先启动的节点也会失败。在最新的版本中会有重试机制,默认重试10次30秒以等待最后关闭的节点启动。
在重试失败之后,当前节点也会因失败而关闭自身的应用。

RabbitMq可通过3种方式实现分布式部署:集群(只能部署在局域网)、Federation和Shovel。3种方式不互斥,可选择一种或多种方式的组合进行部署。
Federation(AMQP协议):该插件的设计目的是使RabbitMq在不同的broker节点之间进行消息传递而无须建立集群。可以让多个交换器或者多个队列进行联邦。一个联邦交换器或一个联邦队列接收上游(指位于其他broker上的交换器或队列)的消息。联邦交换器能够将原本发送给上游交换器的消息路由到本地的某个队列中;联邦队列则允许一个本地消费者接收到来自上游队列的消息。
笔记-《RabbitMQ实战指南》_第4张图片
Shovel(也是基于AMQP协议)优势:松耦合,支持广域网,高度定制。


Federation从一个交换器中转发消息到另一个交换器,Shovel只是简单从某个broker上的队列中消费消息,然后转发消息到另一个broker上的交换器。

27.检测RabbitMq服务是否健康

需要使用AMQP协议构建一个类似于TCP协议中的Ping的检测程序。

  1. 可以定时调用AMQPPing.checkAMQPPing()方法获取检测信息。
  2. AMQPPing可以检测是否能够接收新的请求和构造AMQP信道,但是无法检测RabbitMq服务是否健康。采用aliveness-test方式。运行在Erlang虚拟机内部,因此不受网络问题影响。即创建一个队列(aliveness-test)接收测试消息。

28.存储机制

不管是持久化的消息还是非持久化的消息都可以被写入到磁盘。
持久化的消息在到达队列时就被写入到磁盘,并且如果可以,持久化的消息也会在内存中保存一份备份,当内存吃紧的时候会从内存中清除。
非持久化的消息一般只保存在内存中,在内存吃紧的时候会被换入到磁盘中。
这两种类型的消息的落盘处理都在RabbitMq的“持久层”只完成。

持久层包含两个部分:队列索引和消息存储。消息可以直接存储在队列索引中,也可以被保存在消息存储中。最佳的配备时较小的消息存在队列索引中,较大的存在消息存储中。
消息的删除只是从ETS表删除指定消息的相关信息,同时更新消息对应的存储文件的相关信息。执行消息删除操作时,并不立即对在文件中的消息进行删除,也就是说消息依然在文件中,仅仅是标识为垃圾数据而已。当一个文件中都是垃圾数据时可以将这个文件删除。也可以将逻辑上相邻的两个文件中的有效数据进行整理合并。合并的时候会锁定两个文件。

如果消息投递的目的队列是空的,并且有消费者订阅了这个队列,那么消息就会直接发送给消费者,不会经过队列这一步。消息存入队列后,不是固定不变的。
RabbitMq中的队列消息有四种状态:

  1. alpha:消息内容和消息索引都存储在内存中。
  2. beta:消息内容保存在磁盘中,消息索引保存在内存中。
  3. gamma:消息内容保存在磁盘中,消息索引在磁盘和内存中都有。
  4. delta:消息内容和索引都在磁盘中。

对于持久化的消息,消息内容和消息索引都必须先保存在磁盘上,才会处于上述状态中的一种,而gamma状态的消息是只有持久化的消息才会有的状态。

队列具备两种模式:default和lazy。默认为default。
惰性队列:会尽可能地将消息存入磁盘中,而在消费者消费到对应的消息时才会被加载到内存中,它的一个重要的设计目标是能够支持更长的队列,即支持更多的消息存储。

29.内存及磁盘告警

当内存使用超过配置的阈值或磁盘剩余空间低于配置的阈值时,RabbitMq都会暂时阻塞客户端的连接并停止接收从客户端发来的消息,以此避免服务崩溃。与此同时,客户端与服务端的心跳检测也会失效。

30.流控

流控机制是用来避免消息的发送速率过快而导致服务器难以支撑的情形。内存和磁盘告警相当于全局的流控,一旦出发会阻塞集群中所有的Connection,而流控是针对单个Connection的。

31.镜像队列

如果消费者与slave建立连接并消费,实质上会从master上获取消息。
所有对master的操作都会通过组播GM的方式同步到各个slave中。
GM模块实现的事一种可靠的组播通信协议,该协议能够保证组播消息的原子性,即保证组中活着的节点要么都收到消息要么都收不到。它的实现大概为:将所有的节点形成一个循环链表,每个节点都会监控位于自己左右两边的节点,当有节点新增时,相邻的节点保证当前广播的消息会复制到新的节点上;当有节点失效时,相邻的节点会接管以保证本次广播的消息会复制到所有节点。

32.网络分区

RabbitMq集群节点内部通信端口默认为25672,两两节点之间都会有信息交互。如果某节点出现网络故障,或者是端口不通,则会致使与此节点的交互出现中断,这里就会有个超时判定机制,继而判定网络分区。

RabbitMq提供了三种方法自动地处理网络分区:pause-minority模式、pauser-if-all-down模式和autoheal模式。默认为ignore模式,即不自动处理网络分区,需要人工介入。
pause-minority模式:当发生网络分区时,集群中的节点在观察到某些节点“down”的时候,会自动检测其自身是否处于“少数派”,RabbitMq会自动关闭这些节点的运作。这里的关闭指的是RabbitMq应用的关闭,而Erlang虚拟机并不关闭。
pauser-if-all-down模式:集群中的节点在和所配置的列表中的任何节点不能交互时才会关闭。
autoheal模式:当认为发生网络分区时,RabbieMQ 会自动决定一个获胜 (winning)的分区,然后重启不在这个分区中的节点来从网络分区中恢复。一个获胜的分区是指客户端连接最多的分区,如果产生一个平局,即有两个或者多个分区的客户端连接数一样多,那么节点数最多的一个分区就是获胜分区。如果此时节点数也一样多,将以节点名称的宇典序来挑选获胜分区。

  • ignore模式:发生网络分区时,不做任何动作,需要人工介入。
  • pause-minority 模式:对于对等分区的处理不够优雅,可能会关闭所有的节点。一般情况下,可应用于非跨机架、奇数节点数的集群中。
  • pause-if-all-down 模式:对于受信节点的选择尤为考究,尤其是在集群中所有节点硬件配置相同的情况下。此种模式可以处理对等分区的情形。
  • autoheal 模式:可以处于各个情形下的网络分区。但是如果集群中有节点处于非运行状态,则此种模式会失效。

33.消息追踪

  1. Firehose:可以记录每一次发送或者消费消息的记录。原理是将生产者投递给RabbitMq的消息,或者RabbitMq投递给消费者的消息按照指定的格式发送到默认的服务器上。这个默认的交换器的名称为amq.rabbitmq.trace,它是一个topic类型的交换器。需要用命令开启,默认情况是关闭状态,Firehose的状态是非持久化的。
  2. rabbitmq_tracing插件:相当于Firehose的GUI版本。会对流入流出的消息进行封装,然后将封装后的消息日志存入相应的trace文件中。需要用命令启动插件,启动后在管理页面可见。

34.负载均衡

  1. 客户端内部实现负载均衡:在客户端连接时简单的使用负载均衡算法来实现负载均衡,如轮询法,加权轮询法,随机法,加权随机法,源地址哈希法(对IP地址),最小连接数法。
  2. 使用HAProxy实现负载均衡:提供高可用性、负载均衡及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。
  3. 使用Keepalived实现高可靠负载均衡:采用VRRP(虚拟路由冗余协议),以软件的形式实现服务的热备功能。
  4. 使用Keepalived+LVS实现负载均衡:LVS(Linux虚拟服务器)支持TCP/UDP的负载均衡。在这里,Keepalived的主要工作是提供LVS控制器的一个冗余,并且对RealServer进行健康检查,发现不健康的RealServer就把它从LVS集群中剔除,RealServer只负责提供服务。

99.其他

优化网络配置的一个重要目标就是提高吞吐量,比如禁用Nagle算法(主要用于减少延迟)、增大TCP缓冲区的大小。每个TCP连接都分配了缓冲区。一般来说,缓冲区越大,吞吐量也会越高,但是每个连接上耗费的内存也就越多,从而使总体服务的内存增大,这是一个权衡的问题。

你可能感兴趣的:(读书笔记,笔记,rabbitmq)