Rabbitmq消息保存机制&应用案例分析&消息可靠性保证

Rabbitmq 消息保存机制

mandatory参数和immediate参数作用
  1. mandatory:当参数设置为true时,交换器无法根据自身的类型和路由键找到一个符合条件的队列,Rabbitmq会把消息返回给生产者
  2. immediate:当参数设置为true时,如果交换器在将消息路由到队列时发现队列上并不存在任何消费者,那么这条消息将不会存入队列中,当与路由键匹配的所有队列都没有消费者都没有消费者时,该消息会被返回给发送者。

immediate 3.0版本后不支持,可以使用TTL和DLX方法代替。

备份交换机

生产者在发送消息的时候如果不设置mandatory参数,那么消息在未被路由的情况下将被丢失,如果设置了该参数,则发送者需要增加ReturnListener机制,使得发送者代码变得复杂,此时,可以使用备份交换机使得未被路由的消息存储到Rabbitmq中,需要的时候再去处理这些消息。

设置myAe作为normalExchange备份交换机,并设置绑定类型为fanout,则当消息发送到normalExchange并且找不到合适的路由队列时会将消息发送到备份交换机:

在这里插入图片描述

如果备份交换机和mandatory参数一起使用,mandatory参数不生效

Rabbitmq TTL 消息过期时间

设置消息过期时间的两种方式:

  1. 通过队列属性设置,队列中所有消息都有相同的过期时间(消息过期则会被从队列中抹去,因为已过期的消息在队列头部,定期扫描即可)
  2. 对消息本身进行单独设置,每条消息的TTL可以不同,如果两种一起使用,以TTL小的为准(不会立即抹去,而是在投递时进行判断)。
    消息在队列中的生存时间超过设置的TTL值时,就会变成死信,消费者将无法再收到该消息

如果不设置TTL,则表示此消息不会过期,如果设置为0,除非立即将消息投递到消费者,否则该消息将被丢弃。

Rabbitmq DLX 私信队列

概念:DLX全称为死信队列,当消息在一个队列中成为私信之后,它能被重新发送到另一个交换其中,这交换器就是DLX,绑定DLX的队列就称为死信队列。
触发时机:一般由于以下几种情况

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

补充:
Basic.Reject: 消费端告诉Rabbitmq拒绝处理,如果requeue为true则重新投递到消息队列
Basic.Nack:批量拒绝,拒绝时传递deliveryTag(消息编号),拒绝时拒绝掉所有未被当前消费者确认(ACK)的消息。

DLX也是一个正常的交换器,和一般的交换器没有区别,能被绑定到任何队列上,当这个队列存在私信时,rabbitmq就会自动将这个消息重新发布到设置的DLX上去,进而路由到私信队列,可以通过消费者订阅死信队列,进而进行逻辑处理。这个特性与TTL设置为0配合使用,可以替代immediate参数的功能。

示例如下:在这里插入图片描述
原理图:
在这里插入图片描述

Rabbitmq 延迟队列

Rabbitmq不支持延迟队列,但可以通过TTL和DLX机制实现延迟队列功能。
步骤:

  1. 生产者发送消息到normalExchange,进而路由到normalQueue中,消息过期时间设置5,10,30min…,消费者并非订阅该队列
  2. 为normalExchange配置死信队列,当消息过期时,从normalQueue路由到DLXQueue,消费者订阅DLXQueue,进而实现消息延时消费。
    原理图:
    在这里插入图片描述

Rabbitmq 优先级队列

步骤:

  1. 为队列设置最大优先级10
  2. 发送消息时指定消息的优先级
  3. 优先级高的先被消费,最低优先级为0
  4. 当消费者消费速度大于生产者生产速度,优先级队列将毫无意义。
    在这里插入图片描述
    在这里插入图片描述

Rabbitmq 持久化

持久化层级:

  1. 交换器的持久化
  2. 队列的持久化
  3. 消息的持久化
交换器的持久化

通过在声明交换器时将durable设为true,如果没有设置持久化,rabbitmq重启后,相关的交换器元数据会丢失,但消息不会丢失,只是生产者无法再将消息发送到这个交换器中。

队列的持久化

声明队列时将durable设为true,如果队列不设置持久化,那么rabbitmq重启后,相关队列的元数据会丢失,此时数据也会丢失。队列持久化,可以保证本身的元数据不会丢失,但无法保证内部的消息不会丢失。

消息的持久化

消息的持久化可以保证消息不会丢失,通过将消息的投递模式deliveryMode设为2实现消息的持久化。

当设置了队列持久化和消息的持久化,当Rabbitmq服务重启,消息依旧存在,单单设置队列持久化,重启之后消息会丢失,只设置消息的持久化,重启队列之后,队列会丢失进而消息也会丢失。

注意:
可以将所有消息都设置为持久化,但是会严重影响Rabbitmq性能,写入磁盘速度远远小于写入内存。因此,在选择持久化时,需要在可靠性和吞吐量之间做一个权衡。

Rabbitmq消息 可靠性保证

消息持久化保证

设置了交换器,队列,消息持久化机制后,仍无法保证消息不会丢失。因为在持久化的消息存入磁盘之中仍需要一段时间,因为Rabbitmq不会为每条消息进行同步刷盘(调用内核的fsync),可能仅仅将消息保存到操作系统的缓存中,而不是物理磁盘,如果此时Rabbitmq服务器宕机,消息会丢失。
解决方案:

引入Rabbitmq镜像队列,相当于配置了副本,此时master宕机,仍然可以自动切换到从节点。

生产者确认

消息发送出去,可能未正确到达Rabbitmq服务器。
解决方案:

  1. 通过事务机制实现
  2. 通过发送方确认机制实现。
通过事务机制

调用txSelect将当前通道设置成事务模式,此时便可以将消息发送到rabbitmq,调用txCommit提交事务如果提交成功则消息一定到达了Rabbitmq,如果出现异常则可以调用txRollback将事务回滚。
在这里插入图片描述

整个提交流程中客户端和服务端增加了四个步骤

  1. tx.select将信道设为事务模式
  2. Broker回复selectOk,确认信道已设为事务模式
  3. tx.commit提交事务
  4. Broker回复commitOk,确认事务提交。
    因此,使用事务机制会极大程度影响Rabbitmq的性能。
发送方确认

生产者将信道设置为confirm模式,一旦信道进入confirm模式,所有在该信道上发布的消息都会被指派一个唯一的id,一旦消息被投递到所有匹配的队列之后,Rabbitmq就会发送一个确认(Basc.Ack)给生产者,这就使得生产者知道消息已经正确到达目的地,如果消息和队列是可持久化的,则消息会被写入磁盘后再发送ACK。此外,如果设置basicAck中的multiple参数为true,则表示序号之前的消息都已经得到了处理。在这里插入图片描述
事务机制在发送完一条消息之后,就会使得发送端阻塞,之后才能继续发送下一条消息,相比之下,发送方确认机制最大好处是一步的,一旦发送一条消息,生产者就可以在等待信道返回确认的同时继续发送下一条消息,如果Rabbitmq内部错误则会返回一条NACK,发送到注册回调监听nack即可。

批量confirm

批量confirm模式中,客户端程序需要定期或者定量的调用channel.waitForConfirms来等待Rabbitmq确认返回,问题在于出现返回Basic.Nack或者超时情况时,客户端需要将这个批次的消息全部重发,会带来消息的重复消息数量,并且在经常发生消息丢失时,批量confirm性能反而会下降。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值