跳到主要内容
版本:4.1

可靠性指南

概述

本指南概述了 RabbitMQ 及其(部分)支持的协议中与数据安全和故障处理相关的功能。

它们帮助应用程序开发者和运维人员实现可靠交付,即确保消息始终被传递,即使遇到各种类型的故障。

数据安全是 RabbitMQ 节点、发布者消费者共同的责任。因此,本指南概述了消息传递系统各个部分的重要主题。

本指南主要是一个概述。每个主题都在其各自的专用指南中进行了更详细的讨论。

以下指南更详细地讨论了数据安全和弹性主题

可能发生什么故障?

基于消息传递的系统在定义上是分布式的,可能会以不同的,有时是微妙的方式发生故障。

网络连接问题和拥塞可能是最常见的故障类型。不仅网络可能发生故障,防火墙可能会中断它们认为空闲的连接,而且网络故障需要时间来检测

除了连接性故障外,服务器和客户端应用程序随时都可能遇到硬件故障(或软件崩溃)。此外,即使客户端应用程序持续运行,逻辑错误也可能导致通道连接错误,从而迫使客户端建立新的通道或连接并从问题中恢复。

当然,此故障列表并非详尽无遗。它不包括更微妙的故障,例如遗漏故障(在可预测的时间内未能响应),性能下降,恶意或有缺陷的应用程序耗尽系统资源等等。这些故障可以使用监控、指标和健康检查来检测。

连接故障

如果客户端和 RabbitMQ 节点之间的网络连接发生故障,则客户端需要与 Broker 建立新的连接。先前连接上打开的任何通道都将自动关闭,这些通道也需要重新打开。

通常,当连接失败时,客户端将通过连接抛出异常(或类似的语言构造)来获知。

大多数客户端库都提供自动从连接故障中恢复的功能。对于不适合这种主导恢复的情况,应用程序开发者可以通过定义连接故障事件处理程序来实现自己的恢复。请参阅客户端文档,例如Java.NET 客户端指南,以了解更多信息。

确认和发布者确认

当连接失败时,消息可能正在客户端和服务器之间传输 - 它们可能正在任一侧的解码或编码过程中,位于 TCP 堆栈缓冲区中,或在网络上传输。在这种情况下,正在传输的消息将不会被传递 - 它们需要重新传输。确认让服务器和客户端知道何时执行此操作。

确认可以在两个方向上使用 - 允许消费者向服务器指示它已接收和/或处理交付,并允许服务器向发布者指示相同的事情。它们被称为消费者确认和发布者确认。

虽然 TCP 确保数据包已传递到连接对等方,并将重新传输直到数据包被传递,但这仅处理网络层的故障。确认和发布者确认表明消息已被对等应用程序接收并处理。确认信号既表示消息的接收,又表示所有权的转移,其中接收者承担全部责任。

因此,确认具有语义。消费应用程序不应在完成对消息需要执行的任何操作之前确认消息:将它们记录在数据存储中,转发它们,或执行任何其他操作。一旦这样做,Broker 就可以自由地标记交付以进行删除。

同样,Broker 将在承担消息责任后确认消息。详细信息在确认和发布者确认指南中介绍。

使用确认保证至少一次交付。没有确认,在发布和消费操作期间可能会发生消息丢失,并且仅保证最多一次交付。

使用心跳检测死 TCP 连接

在某些类型的网络故障中,数据包丢失可能意味着操作系统需要相当长的时间(例如,在 Linux 上使用默认配置大约 11 分钟)才能检测到中断的 TCP 连接。AMQP 0-9-1 提供了心跳功能,以确保应用程序层及时发现中断的连接(以及完全无响应的对等方)。心跳还可以防御某些可能终止“空闲”TCP 连接的网络设备。有关详细信息,请参阅关于心跳的指南

RabbitMQ 侧的数据安全

为了避免在 RabbitMQ(相对于应用程序)侧丢失消息,队列和消息必须能够应对 RabbitMQ 节点重启、节点和硬件故障。

使用 RabbitMQ 支持的某些消息传递协议,应用程序控制队列和消息的持久性。因此,至关重要的是,对于重要数据,应使用持久队列(或下面介绍的复制队列类型),并且消息应由发布者发布为持久性消息

集群和队列内容复制

节点集群提供冗余,并且可以容忍单个节点的故障。在 RabbitMQ 集群中,所有定义(交换机、绑定、用户等)都在整个集群中复制。

仲裁队列和超级流(分区流)是复制的数据结构。其中一个节点托管领导者副本,其他副本是追随者。如果领导者发生故障,则将从追随者中选出一个新的领导者。队列状态更改(入队,跟踪交付和确认)发生在领导者副本上,尽管某些操作也可以在追随者上执行。

队列和流从所有节点保持可见和可访问,无论其领导者副本位于哪个节点。在领导者重新选举期间,仲裁队列的飞行中消息传递将暂停,直到选出新的领导者。在领导者选举成功的情况下,这对客户端来说是透明的。

独占队列与连接的生命周期绑定,因此永远不会被复制,并且根据定义,它们无法在节点重启后幸存下来。

连接到故障节点的消费者将必须像往常一样恢复。当队列的新领导者副本被选出时,连接到不同节点的消费者将由 RabbitMQ 自动重新注册。这些消费者不需要执行恢复(例如,重新连接或重新订阅)。

发布者侧的数据安全

使用发布者确认时,从通道或连接故障中恢复的生产者应重新传输任何未从 Broker 收到确认的消息。这里可能存在消息重复的可能性,因为 Broker 可能已发送了从未到达生产者的确认(由于网络故障等)。因此,消费者应用程序将需要执行重复数据删除或以幂等方式处理传入消息。

确保消息被路由

在某些情况下,生产者确保其消息被路由到队列可能很重要(尽管并非总是如此 - 在发布-订阅系统中,生产者只需发布,如果没有消费者感兴趣,则消息被丢弃是正确的)。

为了确保消息被路由到单个已知队列,生产者可以直接声明目标队列并直接发布到该队列。如果消息可能以更复杂的方式路由,但生产者仍然需要知道它们是否至少到达一个队列,则可以在basic.publish上设置mandatory标志,确保如果没有队列被适当绑定,则将basic.return(包含回复代码和一些文本解释)发送回客户端。有关详细信息,请参阅发布者指南

生产者还应该意识到,当发布到集群节点时,如果绑定到交换机的一个或多个目标队列在集群中具有镜像,则由于副本和队列领导者副本之间的流量控制,在面对节点之间的网络故障时,可能会导致延迟。有关更多详细信息,请参阅节点间心跳指南

消费者侧的数据安全

在发生网络故障(或节点故障)时,消息可能会被重新传递,并且消费者必须准备好处理他们过去看到过的交付。建议将消费者实现设计为幂等的,而不是显式执行重复数据删除。

如果消息被传递给消费者,然后被 RabbitMQ 自动重新入队,或者被相同或不同的消费者重新入队,则 RabbitMQ 将在再次传递时在其上设置redelivered标志。这是一个提示,表明消费者可能以前见过此消息。这不能保证,因为原始交付可能由于网络或消费者应用程序故障而未到达任何消费者。

如果未设置redelivered标志,则保证该消息以前未见过。因此,如果消费者发现重复数据删除消息或以幂等方式处理消息的成本更高,则他们可以仅对设置了redelivered标志的消息执行此操作。

无法处理的交付

如果消费者确定它无法处理消息,则可以使用basic.rejectbasic.nack方法拒绝它,可以要求服务器重新排队它,也可以不要求(在这种情况下,服务器可能会配置为死信它)。

消费者取消通知

当消费者正在消费的队列被删除时,RabbitMQ 将通知消费者。此类消费者必须采取行动来恢复,无论是从不同的队列消费还是在安全和适当的情况下重新声明最初消费的队列。

联邦和 Shovel

RabbitMQ 提供了两个插件来帮助在不可靠的网络(例如广域网)上分发节点:联邦Shovel。两者都将从网络故障中恢复并在必要时重新传输消息。两者默认都使用确认和发布者确认。

当使用联邦或 Shovel 连接集群时,希望确保联邦链接和 Shovel 可以从节点故障中恢复,包括永久性(故障停止)场景。

联邦将自动在下游集群中分发链接,并在下游节点发生故障时迁移它们。为了在上游节点发生故障时连接到新的上游,必须为上游指定多个上游 URI,或者连接必须通过具有足够可用性特征的负载均衡器进行。

Shovel 可以使用多个源和目标端点;将使用第一个可访问的端点。失败的 Shovel 将在可配置的延迟后重新启动并重试。

监控和健康检查

一些故障场景是微妙的,难以观察或检测。例如,缓慢的连接泄漏可能会随着时间的推移而累积,并且像慢性病一样,在一段时间内被忽视。监控和指标是检测多种类型故障的方法。使用诸如Prometheus之类的工具收集的长期指标数据可以帮助发现系统行为中的异常和有问题的模式。

除了监控之外,健康检查是另一种可用于检测时间点问题(即可在当下观察到的问题)的工具。广泛的健康检查覆盖范围可能会导致误报,因此检查次数更多并不总是更好。

监控和健康检查都在专用指南中介绍。

© . All rights reserved.