跳至主要内容
版本: 4.0

可靠性指南

概述

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

使用联合或铲子连接集群时,最好确保联合链接和铲子可以从节点故障中恢复,包括永久性(故障停止)情况。

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

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

监控和健康检查

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

除了监控之外,健康检查是另一个可以用来检测时间点问题的工具,也就是在当前时刻可以观察到的问题。广泛的健康检查覆盖可能会导致误报,因此更多的检查并不总是更好。

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

© 2024 RabbitMQ. All rights reserved.