rabbitmq.“消费端确认收到”和“推送者确认”(2)

消费端确认模式和数据安全性

    当向消费者发送消息时,要考虑消息是否被处理(至少是否被消费者接收到)。因为想app,connection等都可能失败,这是基于数据安全的考虑。协议提供了一种机制,当消费者连接时,告知其连接上。是否可借助这种机制呢。

    借助于这种确认模式,RabbitMQ可以确认发送成功,或者收到客户端的确认消息。手动发送应答信息,可以是肯定的也可以是否定的,分别使用如下函数方法:

    basic.ack用于肯定应答

    basic.nack应用于否定应答

    这些函数方法如何使用,下面会讨论这些api。

    肯定应答是通知RabbitMQ这个信息是派送的,可以删除了丢弃了。否定应答有相同的作用。两个不同点正如语义:前者是已经成功处理,后者则是未成功处理,但是服务端也可以丢弃这则信息。

    自动确认模式下,只要发送出去就视为投递成功。这种模式以牺牲数据的可靠性,获取很高的数据吞吐量。这种模式通长被视为即发即(fire-and-forget)。不同于手动确认模式,这个模式下,在成功投递成功前与消费者的tcp连接或者channel关闭,服务端已经发送也视为投递成功,信息会丢失。所以自动模式不能视为安全的,也不适用于所有工作场景。

   此外,一个重要的事情是是否选择使用自动确认模式要考虑客户端的负载情况。手动模式的经典使用场景是针对通道中传输数量有限制的有界的通道预取情况。面对高速率的传输,自动模式有可能不不堪重负,有可能在存储空间中堆积大量的log,消耗堆空间,进程甚至可能被系统终端。一些客户端可能有tcp背压(直到数量低于阈值,停止从socket读取信息)。自动模式只要考虑客户端可以以稳定的速率高效的处理。

肯定应答传递

    传递应答的相关api通长是客户端库的channel对象方法java客户端使用Channel#basicAck 和 Channel#basicNack分别作为basic.ack 和basic.nack调用这是一个肯定应答的实例:

 

// 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);
         }
     });

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);
         }
     });

    .NET客户端则是IModel#BasicAck 和IModel#BasicNack,这是一个肯定应答的实例:

 

// this example assumes an existing channel (IModel) instance

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (ch, ea) =>
                {
                    var body = ea.Body;
                    // positively acknowledge a single delivery, the message will
                    // be discarded
                    channel.BasicAck(ea.DeliveryTag, false);
                };
String consumerTag = channel.BasicConsume(queueName, false, consumer);



var consumer = new EventingBasicConsumer(channel);
consumer.Received += (ch, ea) =>
                {
                    var body = ea.Body;
                    // positively acknowledge a single delivery, the message will
                    // be discarded
                    channel.BasicAck(ea.DeliveryTag, false);
                };
String consumerTag = channel.BasicConsume(queueName, false, consumer);

 

原文:

Consumer Acknowledgement Modes and Data Safety Considerations

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

Depending on the acknowledgement mode used, RabbitMQ can consider a message to besuccessfully delivered either immediately after it is sent out (written to a TCP socket)or when an explicit ("manual") client acknowledgement is received. Manually sentacknowledgements 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

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

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 differenceis primarily in the semantics: positive acknowledgements assumea message was successfully processed while their negative counterpartsuggests that a delivery wasn't processed but still should be deleted.

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

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

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#basicNackto perform a basic.ack and basic.nack, respectively. Here's a Javaclient 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);
         }
     });


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);
         }
     });

In .NET client the methods are IModel#BasicAck and IModel#BasicNack, respectively.Here's an example that demonstrates a positive acknowledgement with that client:

// this example assumes an existing channel (IModel) instance

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (ch, ea) =>
                {
                    var body = ea.Body;
                    // positively acknowledge a single delivery, the message will
                    // be discarded
                    channel.BasicAck(ea.DeliveryTag, false);
                };
String consumerTag = channel.BasicConsume(queueName, false, consumer);


var consumer = new EventingBasicConsumer(channel);
consumer.Received += (ch, ea) =>
                {
                    var body = ea.Body;
                    // positively acknowledge a single delivery, the message will
                    // be discarded
                    channel.BasicAck(ea.DeliveryTag, false);
                };
String consumerTag = channel.BasicConsume(queueName, false, consumer);

 

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值