乐趣区

关于后端开发:RabbitMQ-基础概念进阶

上一篇 RabbitMQ 入门之根底概念 介绍了 RabbitMQ 的一些根底概念,本文再来介绍其中的一些细节和其它的进阶的概念。

一、音讯生产者发送的音讯不可达时如何解决

RabbitMQ 提供了音讯在传递过程中无奈发送到一个队列(比方依据本人的类型和路由键没有找到匹配的队列)时将音讯回传给音讯发送方的性能,应用 RabbitMQ 的客户端提供 channel.basicPublish 办法的两个参数 mandatory 和 immediate (RabbitMQ 3.0 以下版本),除此之外还提供了一个备份交换器能够将无奈发送的音讯存储起来解决,不必从新传回给发送方。

1.1 mandatory 参数

mandatory 被定义在 RabbitMQ 提供的客户端的 channel.basicPublish 办法中,如下所示:

当把办法的 mandatory 参数设置为 true 时,那么会在交换器无奈依据本身的类型和路由键找到一个符合要求的队列时,RabbitMQ 会主动调用 Basic.Return 把该音讯回传给发送方也就是咱们的音讯生产者。反之,如果设置为 false 的话,音讯就会被间接抛弃掉。那么问题来了,咱们要如何去获取这些没有被发送进来的音讯呢?RabbitMQ 给咱们提供了事件监听机制来获取这种音讯,能够通过 addReturnListener 办法增加一个 ReturnListener 来获取这种未发送到队列的音讯,如下所示:

通过查看 ReturnListener 接口的源码能够看到,该接口只有一个办法,如果是 JDK8+ 的版本的话能够应用 Lambda 表达式来简化一些代码。

能够看出,当设置了 mandatory 参数时,还必须为生产者同时增加 ReturnListener 监听器的编程逻辑,这样就会使得生产者的代码变得更加简单了,为了解决这种状况,RabbitMQ 提供了 ` 备份交换器 ` 来将没有胜利路由进来的音讯存储起来,当咱们须要的时候再去解决即可。

1.2 immediate 参数

该的参数同样也是在channel.basicPublish 办法中定义的,其官网形容如下:

This flag tells the server how to react if the message cannot be routed to a queue consumer immediately. If this flag is set, the server will return an undeliverable message with a Return method. If this flag is zero, the server will queue the message, but with no guarantee that it will ever be consumed.

当把 immediate 参数设置为 true 时,如果交换器依据其类型和路由键找到符合要求的队列时,发现所有队列上没有任何消费者,则该音讯并不会存入到队列中,会通过 Basic.Return 命令把音讯回传给生产者。简而言之也就是说,当设置了 immediate 参数时,该音讯关联的队列上存在消费者时,会立刻发送音讯到该队列中,反之如果匹配的队列上不存在任何消费者,则间接把音讯回传给生产者。这里有一点须要留神的是:从 RabbitMQ 3.0 + 曾经去除了该参数。

二、如何对音讯和队列设置过期工夫(TTL)

TTL 是 time to live 首字母的简称,RabbitMQ 中能够设置音讯和队列的过期工夫,咱们先来看看要如何设置音讯的过期工夫。

1.1 音讯 TTL 设置

RabbitMQ 提供了两种设置音讯的过期工夫,第一种是通过队列的属性设置,该形式的特点就是队列中所有音讯的过期工夫都统一。还有一种是更小粒度的设置,就是对每条音讯独自设置过期工夫,这种形式更加灵便,每条音讯的过期工夫都能够不一样。这是你可能会问,如果同时设置了队列的过期属性和音讯自身的过期属性,最终以哪个为准呢?后果是 RabbitMQ 会比拟这两个 TTL 的值大小,以较小的那个为准。很容易想到,通过队列的属性的形式设置过期工夫的话是在申明队列的时候指定,对应到客户端就是其提供的 channel.queueDeclare 办法的参数 arguments 指定,示例代码如下:

须要留神的是 x-message-ttl 参数的单位是毫秒。如果不设置 TLL,则示意该音讯不会过期,如果将 TTL 设置为 0,示意除非此时能够把音讯间接发送投递到消费者端去,否则就会间接抛弃该音讯。

准对每条音讯设置 TTL 的办法是在发送音讯的时候设置的,对应到客户端办法是 channel.basicPublish 的 expiration 属性参数,具体设置代码如下:

这种设置形式,即便队列过期也不会立刻从队列中移除,因为每条音讯是否过期的断定是在发送到消费者是才进行的,如果此时发现曾经过期才会删除音讯。而对于第一种形式则会把曾经过期的音讯移到队列头部,而后 RabbitMQ 只有定期的从头开始扫描是否存在过期的音讯即可。

1.2 队列 TTL 设置

设置队列的过期工夫应用的是客户端的 channel.queueDeclare 办法参数中的 x-expires 参数,其单位同样也是毫秒,不过须要留神的是它不能设置为 0。设置队列过期的代码如下所示:

下面代码创立了一个过期工夫为 15 分钟的队列。

三、死信队列介绍

死信交换器(DLX)的全称是 Dead-Letter-Exchange,也称之为死信邮箱。简略来说就是当一个音讯因为 音讯被回绝 音讯过期 队列达到最大长度 时,变成死信(dead message)之后,会被从新发送到一个交换器中,这个交换器就是死信交换器,绑定在这个交换器上的队列就称之为死信队列。死信交换器实际上就是平时的交换器,能够在任何队列上指定,当在一个队列上设置死信交换器后,如果该队列呈现死信时就会被 RabbitMQ 把死信音讯从新发送到死信交换器下来,而后路由到死信队列中,咱们能够监听这个队列来解决那些死信音讯。为一个队列设置死信交换器是在生产者的申明队列的办法中设置 x-dead-letter-message 参数来实现的,如下所示:

同时也能够通过 x-dead-letter-routing-key 参数设置死信交互器的路由键,不设置默认应用原始度列的路由键。能够到 RabbitMQ 的后盾治理界面,有 DLX 标记的就是死信队列。

RabbitMQ 提供的 DLX 是个比拟实用的性能个性,它能够在咱们音讯不能被消费者正确生产的状况下放入到死信队列,后续咱们能够通过这个死信队列的内容来查看异常情况来革新和优化零碎。

四、提早队列介绍

顾名思义,提早队列存储的是哪些须要期待指定工夫后能力拿到的提早音讯,一个比拟典型的场景就是订单 30 分钟后未领取勾销订单。这里须要留神的是,在 RabbitMQ 中并没有间接提供提早队列的性能,而是须要通过下面介绍的过期工夫(TTL)和死信队列一起来实现,比方超时勾销订单这个场景,咱们能够让消费者订阅死信队列,设置失常的那个队列的超时工夫为 30 分钟并绑定到该死信队列上,当音讯超过 30 分钟未被解决后音讯就会把发送到死信队列中,而后死信队列的消费者就能够在 30 分钟后胜利的生产到该音讯了。

同时当咱们有其它的超时配置需要时也很不便扩大,比方能够在生产者发送音讯的时候通过设置不同的路由键,通过路由键来将音讯发送到与交换器绑定的不同队列中,而后这些队列别离设置不同的过期工夫和与之绝对应的死信队列,当音讯过期时就会被 RabbitMQ 转发到相应的死信队列中,这样就能够去订阅相应的死信队列即可。

五、交换器、音讯和队列长久化

长久化能够进步可靠性,能够避免宕机或者重启等异样下数据的失落,RabbitMQ 的长久化从组成构造上能够分为三个局部,即交换器长久化、音讯长久化和队列长久化。

1.1 交换器长久化

交换器长久化是在申明交换器时将 durable 参数设置为 true 来实现的。如果不设置长久化属性的话,当 RabbitMQ 服务重启后交换器的数据就会失落,须要留神的是,是交换器的数据失落,音讯不会失落,只是不能将音讯发送到这个交换器中了,个别生产环境应用都会把该属性设置为长久化。

1.2 音讯长久化

交换器的长久化仅仅只是保障了交换器自身的元数据不会失落,无奈保障其存储的音讯不会失落,如果须要其外部存储的音讯不失落,则须要设置音讯的长久化,通过将音讯的投递模式 (deliveryMode) 设置为 2 即可实现音讯的长久化,如下所示:

须要音讯长久化的前提是其所在的队列也要设置长久化,如果仅仅只设置音讯的长久化的话,RabbitMQ 重启之后队列隐没,而后音讯也会失落。这里有点须要留神一下,尽管长久化能够进步可靠性,然而长久化是将数据存储到硬盘上,比间接操作内存要慢很多,所以对于哪些可靠性要求不高的业务不须要进行长久化。

1.3 队列长久化

队列的长久化的设置和交换器长久化相似,同样也是在申明的时候通过 durable 参数设置为 true 实现的,如果不设置,当 RabbitMQ 重启后,相干的队列元数据也会失落,相应的其存储的音讯也会随之失落掉。

将交换器、队列、音讯都设置了长久化之后就能百分之百保证数据不失落了吗?其实无奈保障百分之百数据不失落。比方消费者在订阅生产队列时将自动应答(autoAck)参数设置为 true 的话,在接管到音讯后还没来得及解决就挂了,这时须要把自动应答设置 false,进行手动 ack 应答即可。还有一个就是因为不是实时长久化存盘,当音讯存盘的过程中 RabbitMQ 宕机了,此时也会产生数据失落,此时须要通过 RabbitMQ 的 镜像队列机制 来解决了。

五、总结

本文次要介绍了一些参数具体应用时的设置细节和死信队列、提早队列以及长久化等,还有一些比拟重要的点没有波及到,比方音讯确认机制。“纸上得来终觉浅,绝知此事要躬行”,在理解一些根底的概念之后还是须要通过具体编码实际能力对其更加了解粗浅。

退出移动版