跳至主要内容
版本:3.13

可靠性指南

概述

本指南概述了 RabbitMQ 的功能及其支持的协议(其中一些)在数据安全和故障处理方面的相关内容。

它们帮助应用程序开发人员和运营人员实现**可靠的传递**,也就是说,确保即使遇到各种类型的故障也能始终传递消息。

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

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

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

哪些可能会失败?

基于消息的系统在定义上是分布式的,并且可能会以不同的方式(有时是微妙的方式)失败。

网络连接问题和拥塞可能是最常见的故障类别。网络不仅可能出现故障,防火墙可能会中断它们认为处于空闲状态的连接,并且网络故障需要时间来检测

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

当然,此故障列表远非详尽。它没有涵盖更微妙的故障,例如遗漏故障(未能按可预测的时间量响应)、性能下降、恶意或有错误的应用程序耗尽系统资源等。这些故障可以通过监控、指标和运行状况检查来检测。

连接故障

如果客户端与 RabbitMQ 节点之间的网络连接出现故障,客户端将需要建立与代理的新连接。之前连接上打开的任何通道都会自动关闭,需要重新打开这些通道。

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

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

确认和确认

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

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

虽然 TCP 确保数据包已交付到连接对等方,并且将重新传输直到它们到达,但这只处理网络层级的故障。确认和确认指示消息已由对等应用程序接收**并处理**。确认信号同时表明消息已接收,并且所有权已转移,接收方对消息承担全部责任。

因此,确认具有语义。消费应用程序不应在完成对消息的处理之前确认消息:将它们记录在数据存储中、转发它们或执行任何其他操作。一旦完成这些操作,代理就可以删除已确认的消息。

类似地,代理将在对消息承担责任后确认消息。详细信息请参阅确认和确认指南

使用确认保证**至少一次**传递。如果没有确认,在发布和消费操作期间可能会丢失消息,并且只保证**最多一次**传递。

使用心跳检测死 TCP 连接

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

RabbitMQ 端的数据安全

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

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

集群和队列内容复制

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

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

无论领导者副本位于哪个节点,队列和流始终可见并可从所有节点访问。在领导者重新选举期间,为了仲裁队列,在选出新的领导者之前,将暂停传输中的消息传递。如果领导者选举成功,这对于客户端来说是透明的。

独占队列与其连接的生命周期绑定在一起,因此从不复制,并且在定义上无法在节点重启后幸存。

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

发布者端的数据安全

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

确保消息已路由

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

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

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

消费者端的数据安全

如果发生网络故障(或节点故障),消息可以重新传递,消费者必须做好处理过去已见过的传递的准备。建议消费者实现被设计为幂等的,而不是明确地执行重复数据删除。

如果一条消息被传递给消费者,然后重新排队,无论是自动由RabbitMQ,还是由相同或不同的消费者,RabbitMQ都会在再次传递时设置它的redelivered标志。这是一个提示,表明消费者**可能**已经看到过这条消息。这不是保证的,因为原始的传递可能由于网络或消费者应用程序故障而没有到达任何消费者。

如果redelivered标志没有设置,则保证该消息以前从未被看到过。因此,如果消费者发现对消息进行去重或以幂等方式处理消息更昂贵,它可以仅对具有redelivered标志设置的消息进行此操作。

无法处理的交付

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

消费者取消通知

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

联合和铲子

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

在使用联合或铲子连接集群时,最好确保联合链接和铲子能够从节点故障中恢复,包括永久(**故障停止**)场景。

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

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

监控和运行状况检查

一些故障场景很微妙,难以观察或检测。例如,一个缓慢的连接泄漏会随着时间的推移而累积,就像慢性病一样,在一段时间内不会被注意到。 监控和指标是检测许多类型故障的方法。使用Prometheus等工具收集的长期指标数据可以帮助发现系统行为中的不规则性和问题模式。

除了监控之外,运行状况检查是另一种可以用来检测**特定时间点**问题的工具,即在当前时刻可以观察到的问题。广泛的运行状况检查覆盖率会导致误报,因此更多的检查并不总是更好。

监控和运行状况检查都在专用指南中介绍。