rabbit mq Consumer Acknowledgements and Publisher Confirms 翻译

原文地址

Consumer Acknowledgements and Publisher Confirms

消费者消息的Ack机制和生产者发布消息的确认机制

Overview

This guide covers two related features related to data safety, consumer Acknowledgements and publisher confirms:

and more. Acknowledgements on both consumer and publisher side are important for data safety in applications that use messaging.

本指南涵盖了与数据安全相关的两个相关功能:消费者确认和发布者确认:

  • 为什么会有ack机制
  • 手动和自动确认模式
  • Acknowledgement API, 包括 multi-acks 和 重入队列机制
  • 连接丢失或信道关闭时消息自动重入队列
  • 信道预取及其对吞吐量的影响
  • 最常见的客户端错误
  • 发布者确认和相关的发布者数据安全主题
     

More related topics are covered in the Publisher and Consumer guides.

The Basics

Systems that use a messaging broker such as RabbitMQ are by definition distributed. Since protocol methods (messages) sent are not guaranteed to reach the peer or be successfully processed by it, both publishers and consumers need a mechanism for delivery and processing confirmation. Several messaging protocols supported by RabbitMQ provide such features. This guide covers the features in AMQP 0-9-1 but the idea is largely the same in other supported protocols.

使用消息传递broker(如RabbitMQ)的系统根据定义是分布式的。由于不能保证发送的协议方法(消息)到达对等方或被对等方成功处理,发布者和使用者都需要一种传递和处理确认机制。RabbitMQ支持的几个消息传递协议提供了这样的特性。本指南涵盖了AMQP 0-9-1中的特性,但其思想在其他受支持的协议中基本相同。

Delivery processing acknowledgements from consumers to RabbitMQ are known as acknowledgements in messaging protocols; broker acknowledgements to publishers are a protocol extension called publisher confirms. Both features build on the same idea and are inspired by TCP.

从consumers 到RabbitMQ的交付处理在消息传递协议中称为 acknowledgements;

对发布者的broker确认是一个称为 publisher confirms 的协议扩展。

这两个特性都基于相同的思想,并受到TCP的启发。

They are essential for reliable delivery both from publishers to RabbitMQ nodes and from RabbitMQ nodes to consumers. In other words, they are essential for data safety, for which applications are responsible as much as RabbitMQ nodes are.

它们对于从发布者到RabbitMQ节点以及从RabbitMQ节点到使用者的可靠交付都是必不可少的。换句话说,它们对于数据安全至关重要,而应用程序对数据安全的责任与RabbitMQ节点一样大。

(Consumer) Delivery Acknowledgements

When RabbitMQ delivers a message to a consumer, it needs to know when to consider the message to be successfully sent. What kind of logic is optimal depends on the system. It is therefore primarily an application decision. In AMQP 0-9-1 it is made when a consumer is registered using the basic.consume method or a message is fetched on demand with the basic.get method.

当RabbitMQ将消息传递给消费者时,它需要知道什么时候考虑消息被成功发送。什么样的逻辑是最优的取决于系统。因此,它主要是一个应用程序决定。在AMQP 0-9-1中,当consumer 使用basic.consumer 方法注册时 或者使用basic.get方法获取消息,就会产生这种情况。

If you prefer a more example-oriented and step-by-step material, consumer acknowledgements are also covered in RabbitMQ tutorial #2.

Delivery Identifiers: Delivery Tags

Before we proceed to discuss other topics it is important to explain how deliveries are identified (and acknowledgements indicate their respective deliveries). When a consumer (subscription) is registered, messages will be delivered (pushed) by RabbitMQ using the basic.deliver method. The method carries a delivery tag, which uniquely identifies the delivery on a channel. Delivery tags are therefore scoped per channel.

在我们继续讨论其他主题之前,解释如何识别交付是很重要的(确认表示它们各自的交付)。当注册了使用者(订阅)时,RabbitMQ将使用basic.deliver方法传递(pushed)消息。该方法携带一个delivery tag,它唯一地标识通道上的传递。因此,delivery tag 的作用域为每个通道。

Delivery tags are monotonically growing positive integers and are presented as such by client libraries. Client library methods that acknowledge deliveries take a delivery tag as an argument.

传递标记是单调增长的正整数,由客户端库表示。确认传递的客户端库方法将delivery tag 作为参数。

Because delivery tags are scoped per channel, deliveries must be acknowledged on the same channel they were received on. Acknowledging on a different channel will result in an "unknown delivery tag" protocol exception and close the channel.

因为delivery tags 是按通道确定范围的,所以必须在接收它们的同一通道上确认传递。在一个不同的通道上确认将会导致一个“未知的传递标签”协议异常并关闭通道。

Consumer Acknowledgement Modes and Data Safety Considerations

消费者确认模式和数据安全注意事项

When a node delivers a message to a consumer, it has to decide whether the message should be considered handled (or at least received) by the consumer. Since multiple things (client connections, consumer apps, and so on) can fail, this decision is a data safety concern. Messaging protocols usually provide a confirmation mechanism that allows consumers to acknowledge deliveries to the node they are connected to. Whether the mechanism is used is decided at the time consumer subscribes.

当一个节点向使用者传递消息时,该节点必须决定该消息是否应该被视为由使用者处理(或至少是接收)。由于很多不用的原因(客户端连接、消费者应用程序等)可能会失败,所以这个决定是一个数据安全问题。消息传递协议通常提供一种确认机制,允许使用者确认到所连接节点的传递。是否使用该机制是在消费者订阅时决定的。

 

Depending on the acknowledgement mode used, RabbitMQ can consider a message to be successfully delivered either immediately after it is sent out (written to a TCP socket) or when an explicit ("manual") client acknowledgement is received. Manually sent acknowledgements can be positive or negative and use one of the following protocol methods:

  • basic.ack is used for positive acknowledgements
  • basic.nack is used for negative acknowledgements (note: this is a RabbitMQ extension to AMQP 0-9-1)
  • basic.reject is used for negative acknowledgements but has one limitation compared to basic.nack

 

根据所使用的确认模式,RabbitMQ可以考虑在消息发出(写入TCP套接字)后立即或在收到显式(“手动”)客户端确认时成功地传递消息。手动发送的确认可以是肯定的或否定的,并使用以下协议方法之一:

  • basic.ack用于肯定确认
  • basic.nack用于否定确认
  • basic.reject用户已否定确认,但与basic.nack想比较有一个限制

How these methods are exposed in client library APIs will be discussed below.

下面将讨论如何在客户端库API中公开这些方法。

Positive acknowledgements simply instruct RabbitMQ to record a message as delivered and can be discarded. Negative acknowledgements with basic.reject have the same effect. The difference is primarily in the semantics: positive acknowledgements assume a message was successfully processed while their negative counterpart suggests that a delivery wasn't processed but still should be deleted.

肯定的ack只是指示RabbitMQ在发送时记录一条消息并可以丢弃。

否定确认与basic.reject也有同样的效果。区别主要在于语义上:肯定的确认假定消息已成功处理,而否定的确认则暗示未处理传递但仍应删除。

In automatic acknowledgement mode, a message is considered to be successfully delivered immediately after it is sent. This mode trades off higher throughput (as long as the consumers can keep up) for reduced safety of delivery and consumer processing. This mode is often referred to as "fire-and-forget". Unlike with manual acknowledgement model, if consumers's TCP connection or channel is closed before successful delivery, the message sent by the server will be lost. Therefore, automatic message acknowledgement should be considered unsafe and not suitable for all workloads.

 

在自动确认模式中,消息在发送后立即被认为成功发送。此模式可处理更高的吞吐量(只要消费者能夠跟上),降低交付安全和消费者处理。这种模式通常被称为“fire-and-forget”。与手动确认模型不同,如果在成功传递之前关闭了用户的TCP连接或通道,则服务器发送的消息将丢失。因此,应该认为自动消息确认是不安全的,不适合所有工作负载。

Another thing that's important to consider when using automatic acknowledgement mode is consumer overload. Manual acknowledgement mode is typically used with a bounded channel prefetch which limits the number of outstanding ("in progress") deliveries on a channel. With automatic acknowledgements, however, there is no such limit by definition. Consumers therefore can be overwhelmed by the rate of deliveries, potentially accumulating a backlog in memory and running out of heap or getting their process terminated by the OS. Some client libraries will apply TCP back pressure (stop reading from the socket until the backlog of unprocessed deliveries drops beyond a certain limit). Automatic acknowledgement mode is therefore only recommended for consumers that can process deliveries efficiently and at a steady rate.

在使用自动确认模式时,另一个需要考虑的重要问题是用户过载。

手动确认模式通常与有界信道预取一起使用,该预取限制了信道上未完成(“正在进行中”)传输的数量。然而,对于自动确认,并没有这样的定义限制。因此,用户可能会被交付的速度所压倒,可能会在内存中积累积压,耗尽堆,或者让操作系统终止其进程。一些客户端库将应用TCP back pressure(停止从套接字读取数据,直到未处理的交付的积压量下降到某个限制之外)。因此,自动确认模式只推荐给能够以稳定的速度高效处理交付的消费者

Positively Acknowledging Deliveries

API methods used for delivery acknowledgement are usually exposed as operations on a channel in client libraries. Java client users will use Channel#basicAck and Channel#basicNack to perform a basic.ack and basic.nack, respectively. Here's a Java client examples that demonstrates a positive acknowledgement:

// this example assumes an existing channel instance

boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "a-consumer-tag",
     new DefaultConsumer(channel) {
         @Override
         public void handleDelivery(String consumerTag,
                                    Envelope envelope,
                                    AMQP.BasicProperties properties,
                                    byte[] body)
             throws IOException
         {
             long deliveryTag = envelope.getDeliveryTag();
             // positively acknowledge a single delivery, the message will
             // be discarded
             channel.basicAck(deliveryTag, false);
         }
     });

 

 

Acknowledging Multiple Deliveries at Once

Manual acknowledgements can be batched to reduce network traffic. This is done by setting the multiple field of acknowledgement methods (see above) to true. Note that basic.reject doesn't historically have the field and that's why basic.nack was introduced by RabbitMQ as a protocol extension.

可以批量处理手动确认以减少网络流量。这是通过将确认方法的多个字段(见上面)设置为true来实现的。注意,basic.reject在历史上没有这个字段,这就是basic.nack是由RabbitMQ作为协议扩展引入的原因。

When the multiple field is set to true, RabbitMQ will acknowledge all outstanding delivery tags up to and including the tag specified in the acknowledgement. Like everything else related to acknowledgements, this is scoped per channel. For example, given that there are delivery tags 5, 6, 7, and 8 unacknowledged on channel Ch, when an acknowledgement frame arrives on that channel with delivery_tag set to 8 and multiple set to true, all tags from 5 to 8 will be acknowledged. If multiple was set to false, deliveries 5, 6, and 7 would still be unacknowledged.

当multiple字段设置为true时,RabbitMQ将确认所有未完成的交付标记,直到并包括确认中指定的标记。与所有与确认相关的内容一样,这是按通道划分范围的。与所有与确认相关的内容一样,这是按通道确定的范围。

例如,给定通道Ch上有未被承认的传递标签5、6、7和8,当一个确认帧到达该通道时,delivery_tag被设置为8,multiple被设置为true,从5到8的所有标签都将被确认。如果multiple被设置为false,投递5、6和7仍然是未确认的。

To acknowledge multiple deliveries with RabbitMQ Java client, pass true for the multiple parameter to Channel#basicAck:

// this example assumes an existing channel instance

boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "a-consumer-tag",
     new DefaultConsumer(channel) {
         @Override
         public void handleDelivery(String consumerTag,
                                    Envelope envelope,
                                    AMQP.BasicProperties properties,
                                    byte[] body)
             throws IOException
         {
             long deliveryTag = envelope.getDeliveryTag();
             // positively acknowledge all deliveries up to
             // this delivery tag
             channel.basicAck(deliveryTag, true);
         }
     });

Negative Acknowledgement and Requeuing of Deliveries

Sometimes a consumer cannot process a delivery immediately but other instances might be able to. In this case it may be desired to requeue it and let another consumer receive and handle it. basic.reject and basic.nack are two protocol methods that are used for that.

消费者有时可能无法立即传递其他实例。在这种情况下,可能需要重新排队,让另一个消费者接收和处理它.basic.reject and basic.nack是两种协议方法。

The methods are generally used to negatively acknowledge a delivery. Such deliveries can be discarded by the broker or requeued. This behaviour is controlled by the requeue field. When the field is set to true, the broker will requeue the delivery (or multiple deliveries, as will be explained shortly) with the specified delivery tag.

这些方法通常用于否定地承认一次投递。这样的投递可以被broker丢弃或requeue。该行为由requeue字段控制。当该字段设置为true时,broker将使用指定的投递标记来重入队这个投递(或多次投递,稍后将对此进行解释)。

Both methods are usually exposed as operations on a channel in client libraries. Java client users will use Channel#basicReject and Channel#basicNack to perform a basic.reject and basic.nack, respectively:

// this example assumes an existing channel instance

boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "a-consumer-tag",
     new DefaultConsumer(channel) {
         @Override
         public void handleDelivery(String consumerTag,
                                    Envelope envelope,
                                    AMQP.BasicProperties properties,
                                    byte[] body)
             throws IOException
         {
             long deliveryTag = envelope.getDeliveryTag();
             // negatively acknowledge, the message will
             // be discarded
             channel.basicReject(deliveryTag, false);
         }
     });
// this example assumes an existing channel instance

boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "a-consumer-tag",
     new DefaultConsumer(channel) {
         @Override
         public void handleDelivery(String consumerTag,
                                    Envelope envelope,
                                    AMQP.BasicProperties properties,
                                    byte[] body)
             throws IOException
         {
             long deliveryTag = envelope.getDeliveryTag();
             // requeue the delivery
             channel.basicReject(deliveryTag, true);
         }
     });

When a message is requeued, it will be placed to its original position in its queue, if possible. If not (due to concurrent deliveries and acknowledgements from other consumers when multiple consumers share a queue), the message will be requeued to a position closer to queue head.

当消息被重新请求时,如果可能的话,它将被放置到队列中的原始位置。如果没有(由于多个使用者共享一个队列时来自其他使用者的并发投递和确认),则消息将被重新分配到更靠近队列头的位置。

Requeued messages may be immediately ready for redelivery depending on their position in the queue and the prefetch value used by the channels with active consumers. This means that if all consumers requeue because they cannot process a delivery due to a transient condition, they will create a requeue/redelivery loop. Such loops can be costly in terms of network bandwidth and CPU resources. Consumer implementations can track the number of redeliveries and reject messages for good (discard them) or schedule requeueing after a delay.

根据其在队列中的位置和通道与活动使用者使用的预取值,被重新请求的消息可以立即准备重新交付。这意味着,如果所有消费者因为临时条件而无法处理传递而请求,那么他们将创建一个请求/重新投递循环。这样的循环在网络带宽和CPU资源方面会很昂贵。使用者实现可以跟踪重新投递的数量,并永久拒绝消息(丢弃它们),或者在延迟后调度请求

It is possible to reject or requeue multiple messages at once using the basic.nack method. This is what differentiates it from basic.reject. It accepts an additional parameter, multiple. Here's a Java client example:

// this example assumes an existing channel instance

boolean autoAck = false;
channel.basicConsume(queueName, autoAck, "a-consumer-tag",
     new DefaultConsumer(channel) {
         @Override
         public void handleDelivery(String consumerTag,
                                    Envelope envelope,
                                    AMQP.BasicProperties properties,
                                    byte[] body)
             throws IOException
         {
             long deliveryTag = envelope.getDeliveryTag();
             // requeue all unacknowledged deliveries up to
             // this delivery tag
             channel.basicNack(deliveryTag, true, true);
         }
     });

Channel Prefetch Setting (QoS)

Because messages are sent (pushed) to clients asynchronously, there is usually more than one message "in flight" on a channel at any given moment. In addition, manual acknowledgements from clients are also inherently asynchronous in nature. So there's a sliding window of delivery tags that are unacknowledged. Developers would often prefer to cap the size of this window to avoid the unbounded buffer problem on the consumer end. This is done by setting a "prefetch count" value using the basic.qos method. The value defines the max number of unacknowledged deliveries that are permitted on a channel. Once the number reaches the configured count, RabbitMQ will stop delivering more messages on the channel unless at least one of the outstanding ones is acknowledged.

因为消息是异步发送(推送)到客户端的,所以在任何给定时刻,通道上通常有多个消息“正在传输”。此外,来自客户端的手动确认本质上也是异步的。所以有一个滑动窗口,上面有未确认的投递标签。开发人员通常倾向于限制这个窗口的大小,以避免消费者端的无限缓冲区问题。这是通过使用 basic.qos 方法。该值定义通道上允许的最大未确认传递数。一旦数量达到配置的计数,RabbitMQ将停止在通道上传递更多的消息,除非至少有一个未完成的消息得到确认。

For example, given that there are delivery tags 5, 6, 7, and 8 unacknowledged on channel Ch and channel Ch's prefetch count is set to 4, RabbitMQ will not push any more deliveries on Ch unless at least one of the outstanding deliveries is acknowledged. When an acknowledgement frame arrives on that channel with delivery_tag set to 5 (or 6, 7, or 8), RabbitMQ will notice and deliver one more message. Acknowledging multiple messages at once will make more than one message available for delivery.

例如,假定通道Ch上有未确认的传递标记5、6、7和8,并且通道Ch的预取计数设置为4,则RabbitMQ将不会在Ch上推送任何更多的传递,除非至少有一个未完成的传递被确认。当确认帧到达通道时,delivery_tag 设置为5(或6、7或8),RabbitMQ将通知并再传递一条消息。一次确认多个消息将使多个消息可用于传递。

It's worth reiterating that the flow of deliveries and manual client acknowledgements is entirely asynchronous. Therefore if the prefetch value is changed while there already are deliveries in flight, a natural race condition arises and there can temporarily be more than prefetch count unacknowledged messages on a channel.

值得重申的是,投递和手动客户端确认流是完全异步的。因此,如果有投递正在传送过程中,更改了预取值,则会出现自然竞争条件,并且通道上可能会暂时有超过预取计数的未确认消息。

Per-channel, Per-consumer and Global Prefetch

The QoS setting can be configured for a specific channel or a specific consumer. The Consumer Prefetch guide explains the effects of this scoping.

QoS设置可以针对特定通道或特定使用者进行配置。The Consumer Prefetch 指南解释了此范围界定的影响。

Prefetch and Polling Consumers 

预取和轮询消费者

The QoS prefetch setting has no effect on messages fetched using the basic.get ("pull API"), even in manual confirmation mode.

QoS预取设置对使用basic.get(“pull API”)取来的消息没有效果,即使在手动确认模式下。

Consumer Acknowledgement Modes, Prefetch and Throughput

Acknowledgement mode and QoS prefetch value have significant effect on consumer throughput. In general, increasing prefetch will improve the rate of message delivery to consumers. Automatic acknowledgement mode yields best possible rate of delivery. However, in both cases the number of delivered but not-yet-processed messages will also increase, thus increasing consumer RAM consumption.

确认模式和QoS预取值对用户吞吐量有显著影响。一般来说,增加预取将提高消息传递给消费者的速率。自动确认模式可产生最佳的传送速率。然而,在这两种情况下,已传递但尚未处理的消息的数量也将增加,从而增加消费者的RAM内存消耗。
 

Automatic acknowledgement mode or manual acknowledgement mode with unlimited prefetch should be used with care. Consumers that consume a lot of messages without acknowledging will lead to memory consumption growth on the node they are connected to. Finding a suitable prefetch value is a matter of trial and error and will vary from workload to workload. Values in the 100 through 300 range usually offer optimal throughput and do not run significant risk of overwhelming consumers. Higher values often run into the law of diminishing returns.

应小心使用自动确认模式或带有无限预取的手动确认模式。使用大量消息而不进行确认的使用者将导致所连接节点上的内存消耗增长。找到一个合适的预取值是一个反复试验的问题,并且会因工作负载的不同而有所不同。在100到300范围内的值通常提供最佳吞吐量,并且不会对压倒消费者造成重大风险。较高的价值往往会遇到收益递减规律。
 

Prefetch value of 1 is the most conservative. It will significantly reduce throughput, in particular in environments where consumer connection latency is high. For many applications, a higher value would be appropriate and optimal.

预取值1是最保守的。它将显著降低吞吐量,特别是在用户连接延迟很高的环境中。对于许多应用程序,较高的值是合适的和最佳的。
 

When Consumers Fail or Lose Connection: Automatic Requeueing

消费失败或失去连接时:自动重新排队

When manual acknowledgements are used, any delivery (message) that was not acked is automatically requeued when the channel (or connection) on which the delivery happened is closed. This includes TCP connection loss by clients, consumer application (process) failures, and channel-level protocol exceptions (covered below).

当使用手动确认时,当发生投递的通道(或连接)关闭时,任何未确认的投递(消息)都将自动重新排队。这包括客户端的TCP连接丢失、消费者应用程序(进程)故障和通道级协议异常(如下所述)。
 

Note that it takes a period of time to detect an unavailable client.

注意,检测不可用的客户端需要一段时间。

Due to this behavior, consumers must be prepared to handle redeliveries and otherwise be implemented with idempotence in mind. Redeliveries will have a special boolean property, redeliver, set to true by RabbitMQ. For first time deliveries it will be set to false. Note that a consumer can receive a message that was previously delivered to another consumer.

由于这种行为,消费者必须准备好处理重新投递的消息,否则在实现时要考虑到幂等性。Redeliveries将有一个特殊的布尔属性redeliver,由RabbitMQ设置为true。对于首次投递的消息,它将被设置为false。请注意,消费者可以接收先前投递给其他消费者的消息。
 

Client Errors: Double Acking and Unknown Tags

客户端错误:双重确认和未知标记
 

Should a client acknowledge the same delivery tag more than once, RabbitMQ will result a channel error such as PRECONDITION_FAILED - unknown delivery tag 100. The same channel exception will be thrown if an unknown delivery tag is used.

如果客户机不止一次确认同一个交付标记,RabbitMQ将导致通道错误,例如PRECONDITION_FAILED-unknown delivery tag 100。如果使用未知的传递标记,将引发相同的通道异常。

Another scenario in which the broker will complain about an "unknown delivery tag" is when an acknowledgement, whether positive or negative, is attempted on a channel different from that on which the delivery was received on. Deliveries must be acknowledged on the same channel.

borker 将抱怨“未知投递标记”的另一种情况是,在与接收传递的通道不同的通道上尝试确认(无论是肯定的还是否定的)。必须在同一channel上确认投递。

 

持续翻译中.......
 

Publisher Confirms

发布者确认

Networks can fail in less-than-obvious ways and detecting some failures takes time. Therefore a client that's written a protocol frame or a set of frames (e.g. a published message) to its socket cannot assume that the message has reached the server and was successfully processed. It could have been lost along the way or its delivery can be significantly delayed.

网络可能以不太明显的方式发生故障,检测某些故障需要时间。因此,将一个协议帧或一组帧(如已发布的消息)写入其套接字的客户端不能假定消息已到达服务器并已成功处理。它可能会在途中丢失,也可能会严重延迟投递。
 

Using standard AMQP 0-9-1, the only way to guarantee that a message isn't lost is by using transactions -- make the channel transactional then for each message or set of messages publish, commit. In this case, transactions are unnecessarily heavyweight and decrease throughput by a factor of 250. To remedy this, a confirmation mechanism was introduced. It mimics the consumer acknowledgements mechanism already present in the protocol.

使用标准AMQP 0-9-1,确保消息不会丢失的唯一方法是使用事务——使通道事务化,然后针对每个消息或消息集发布、提交。在这种情况下,事务是不必要的重量级,吞吐量降低了250倍。为此,引入了一种确认机制。它模仿了协议中已经存在的消费者确认机制。
 

To enable confirms, a client sends the confirm.select method. Depending on whether no-wait was set or not, the broker may respond with a confirm.select-ok. Once the confirm.select method is used on a channel, it is said to be in confirm mode. A transactional channel cannot be put into confirm mode and once a channel is in confirm mode, it cannot be made transactional.

要启用确认机制,客户端将发送 confirm.select 方法。根据是否设置了no-wait,broker可以使用confirm.select-ok 进行响应.一旦 confirm.select 方法在通道上使用,称为处于确认模式。事务性通道不能置于确认模式,一旦通道处于确认模式,就不能使其成为事务性通道。
 

Once a channel is in confirm mode, both the broker and the client count messages (counting starts at 1 on the first confirm.select). The broker then confirms messages as it handles them by sending a basic.ack on the same channel. The delivery-tag field contains the sequence number of the confirmed message. The broker may also set the multiple field in basic.ack to indicate that all messages up to and including the one with the sequence number have been handled.

一旦通道处于confirm模式,broker和客户机都会对消息进行计数(第一次confirm.select计数从1开始). 然后broker在确认消息时通过发送basic.ack在同一个channel。delivery-tag字段包含确认消息的序列号。broker还可以在basic.ack中设置multiple字段,表示所有消息(包括带序列号的消息 )都已被处理。

Negative Acknowledgments for Publishes

In exceptional cases when the broker is unable to handle messages successfully, instead of a basic.ack, the broker will send a basic.nack. In this context, fields of the basic.nack have the same meaning as the corresponding ones in basic.ack and the requeue field should be ignored. By nack'ing one or more messages, the broker indicates that it was unable to process the messages and refuses responsibility for them; at that point, the client may choose to re-publish the messages.

在异常情况下,broker无法成功处理消息,broker将发送一个bacic.nack,而不是basic.ack。

在这种情况下basic.nack与basic.ack是相同的含义,并且requeue字段应该被忽略。通过拒绝处理一个或多个消息,broker表明它无法处理这些消息并拒绝对它们负责;此时,客户端可以选择重新发布消息。
 

After a channel is put into confirm mode, all subsequently published messages will be confirmed or nack'd once. No guarantees are made as to how soon a message is confirmed. No message will be both confirmed and nack'd.

通道进入确认模式后,所有随后发布的消息都将被确认或取消一次。对于消息的确认时间,我们不作任何保证。不会有消息同时被确认和取消。
 

basic.nack will only be delivered if an internal error occurs in the Erlang process responsible for a queue.

basic.nack只有在负责队列的Erlang进程中发生内部错误时才会传递。
 

When Will Published Messages Be Confirmed by the Broker?

发布的消息何时由broker确认?

For unroutable messages, the broker will issue a confirm once the exchange verifies a message won't route to any queue (returns an empty list of queues). If the message is also published as mandatory, the basic.return is sent to the client before basic.ack. The same is true for negative acknowledgements (basic.nack).

对于无法路由的消息,一旦exchange验证消息不会路由到任何队列(返回一个空的队列列表),broker将发出一个confirm。

如果消息也是作为强制发布的,则basic.return将在basic.ack之前发送到客户端. 对于否定的确认也是如此(basic.nack).

For routable messages, the basic.ack is sent when a message has been accepted by all the queues. For persistent messages routed to durable queues, this means persisting to disk. For mirrored queues, this means that all mirrors have accepted the message.

对于可路由的消息,当消息被所有队列接受时发送basic.ack。对于路由到持久队列的持久消息,这意味着持久化到磁盘。对于镜像队列,这意味着所有镜像都已接受该消息。

Ack Latency for Persistent Messages

持久化消息的Ack延迟

basic.ack for a persistent message routed to a durable queue will be sent after persisting the message to disk. The RabbitMQ message store persists messages to disk in batches after an interval (a few hundred milliseconds) to minimise the number of fsync(2) calls, or when a queue is idle.

basic.ack对于持久消息,路由到持久队列的消息将在将消息持久化到磁盘后发送。RabbitMQ消息存储在间隔(几百毫秒)之后将消息成批地保存到磁盘,以最小化fsync(2)调用的数量,或者当队列空闲时。

This means that under a constant load, latency for basic.ack can reach a few hundred milliseconds. To improve throughput, applications are strongly advised to process acknowledgements asynchronously (as a stream) or publish batches of messages and wait for outstanding confirms. The exact API for this varies between client libraries.

这意味着在恒定负载下,延迟basic.ack可以达到几百毫秒。为了提高吞吐量,强烈建议应用程序异步处理确认(作为流)或发布批消息并等待未完成的确认。具体的API因客户端库而异。
 

Ordering Considerations for Publisher Confirms

发布确认的顺序性注意事项

In most cases, RabbitMQ will acknowledge messages to publishers in the same order they were published (this applies for messages published on a single channel).

在大多数情况下,RabbitMQ将按照消息发布的相同顺序向发布者确认消息(这适用于在单个通道上发布的消息)。

However, publisher acknowledgements are emitted asynchronously and can confirm a single message or a group of messages.

但是,发布者确认是异步发出的,可以确认单个消息或一组消息。

The exact moment when a confirm is emitted depends on the delivery mode of a message (persistent vs. transient) and the properties of the queue(s) the message was routed to (see above). Which is to say that different messages can be considered ready for acknowledgement at different times.

发出确认的确切时间取决于消息的投递模式(持久的还是暂时的)以及消息路由到的队列的属性(见上文)。也就是说,不同的消息可以被认为在不同的时间准备好进行确认。

This means that acknowledgements can arrive in a different order compared to their respective messages. Applications should not depend on the order of acknowledgements when possible.

这意味着,与各自的消息相比,确认可以以不同的顺序到达。在可能的情况下,应用程序不应依赖于确认的顺序。
 

Publisher Confirms and Guaranteed Delivery

发布确认和投递保证
 

A RabbitMQ node can lose persistent messages if it fails before said messages are written to disk. For instance, consider this scenario:

  1. a client publishes a persistent message to a durable queue
  2. a client consumes the message from the queue (noting that the message is persistent and the queue durable), but confirms are not active,
  3. the broker node fails and is restarted, and
  4. the client reconnects and starts consuming messages

如果RabbitMQ节点在所述消息写入磁盘之前发生故障,它可能会丢失持久消息。例如,考虑以下场景:

  1. 客户端将持久消息发布到持久队列
  2. 客户端消费来自队列的消息(注意消息是持久的,队列是持久的),但是确认不是活动的
  3. broker节点发生故障并重新启动,并且
  4. 客户端重新连接并开始消费消息

At this point, the client could reasonably assume that the message will be delivered again. This is not the case: the restart has caused the broker to lose the message. In order to guarantee persistence, a client should use confirms. If the publisher's channel had been in confirm mode, the publisher would not have received an ack for the lost message (since the message hadn't been written to disk yet).

此时,客户端可以合理地假设消息将再次被投递。事实并非如此:重新启动已导致broker丢失消息。为了保证持久性,客户端应该使用confirms。如果发布者的通道处于确认模式,则发布者将不会收到丢失消息的确认(因为消息尚未写入磁盘)。
 

Limitations

Maximum Delivery Tag

Delivery tag is a 64 bit long value, and thus its maximum value is 9223372036854775807. Since delivery tags are scoped per channel, it is very unlikely that a publisher or consumer will run over this value in practice.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值