笔记-《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集群
- 99.其他
1.发到Mq对应的3个参数:Exchange(交换器),RountingKey(路由键),param
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模糊匹配
“*“用于匹配一个单词,”#”用于匹配多规格单词(可以是零个)
- headers
不依赖于路由键的匹配规则来路由消息,而是根据发送的消息内容中的headers属性进行匹配。
性能差,基本上不用。
6.Connection(连接),Channel(信道)
Connection,TCP连接
Channel,AMQP信道,每个信道都会被指派一个唯一 的ID。
引入信道的原因:
多Connection也可以用,但是在多线程情况下,建立多个Connection即建立多个TCP连接,而建立和销毁TCP连接是非常昂贵的,如遇使用高峰,性能也会有瓶颈。RabbitMq采用类似NIO的做法,选择TCP连接复用。
注:NIO,非阻塞IO,包含Channel,Buffer和Selector。NIO基于Channel和Buffer进行操作,数据总是从信道读取数据到缓冲区,或者从缓冲区读取到信道中。Selector用于监听多个信道的事件。因此,单线程可以监听多个数据的信道。
7. AMQP协议
包含三层:
- Module Layer:位于协议最高层。定义了一些供客户端调用的命令。
- Session Layer:位于中间层。主要负责将客户端的命令发送给服务器,再讲服务器的应答返回给客户端。为客户端和服务器之间的通信提供可靠性同步机制和错误处理。
- 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
- 设置队列属性,即队列中所有消息都有相同的过期时间。
消息一旦过期,立马会从队列中抹去。队列中已过期的消息肯定在队列头部,RabbitMq只要定期从队头开始扫描是否有过期的消息即可。 - 对消息本身单独设置。
即使消息过期,也不会立马从队列中抹去。每条消息的过期时间不一致,如果要删除只能扫描整个队列,所以会等到此消息即将被消费时才会判断是否过期及删除。
两种一起使用,则以两者较小的那个数值为准。
消息在队列中的时间超过TTL,则变成“死信”,消费者无法再接收(不绝对)。
不设置TTL代表消息永不过期;设置为0,代表除非此时可以直接将消息投递给消费者,否则直接丢弃。
17.队列的TTL
x-expires(单位:毫秒)参数可以控制队列被自动删除前处于未使用状态的时间。未使用的意思是队列上没有任何的消费者,也没有被重新声明,并且在过期时间段内也未调用过Basic.Get命令。
会确保在过期时间到达后将队列删除,但不保障删除的动作的及时性。在RabbitMq重启后,持久化的队列的过期时间会被重新计算。
18.死信队列DLX
也叫做死信交换器或死信邮箱。
当一个消息在一个队列中变成死信后,它能被重新发送到另一个交换器中,这个交换器就是DLX,绑定DLX的队列就称之为死信队列。
消息变成死信的几种情况:
- 消息被拒绝(Basic.Rejext/Basic.Nack),并且设置requeue参数为false;
- 消息过期;
- 队列达到最大长度。
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.消息传输保障
一般消息中间件的消息传输保障分为三个层级
- At most once:最多一次。消息可能会丢失,但绝不会重复传输。
- At least once:最少一次。消息绝不会丢失,但可能会重复传输。
- Exactly once:恰好一次。每条消息肯定会被传输一次且仅传输一次。
RabbitMq支持”最多一次“和”最少一次“
24.多租户
虚拟主机(vhost):每一个RabbitMq服务器都能创建虚拟的消息服务器。每一个vhost本质上是一个独立的小型RabbitMq服务器,拥有自己独立的队列,交换器及绑定关系等,并且它拥有自己独立的权限。
RabbitMq里,权限规则是以vhost为单位的。
25.RabbitMq定制化
RabbitMq提供了三种方式来定制化服务
- 环境变量:shell环境中设置,或rabbitmq-env.conf配置文件
- 配置文件:rabbitmq.config
配置加密,默认的Hash算法是SHA512 - 运行时参数和策略
RabbitMq中一共有两种类型的Parameter:vhost级别的Parameter和global级别的Parameter。
26.RabbitMq集群
集群的所有节点都会备份所有的元数据信息:
- 队列元数据:队列的名称及属性
- 交换器:交换器的名称及属性
- 绑定关系元数据:交换器与队列或者交换器与交换器之间的绑定关系
- vhost元数据:为vhost内的队列、交换器和绑定提供命名空间及安全属性
99.其他
优化网络配置的一个重要目标就是提高吞吐量,比如禁用Nagle算法(主要用于减少延迟)、增大TCP缓冲区的大小。每个TCP连接都分配了缓冲区。一般来说,缓冲区越大,吞吐量也会越高,但是每个连接上耗费的内存也就越多,从而使总体服务的内存增大,这是一个权衡的问题。