RabbitMQ数据可靠性

1.1 消费者

消费者通过 Delivery Acknowledgements 确保数据的可靠投递,Delivery Acknoledgements 包含两种模式,分别为自动和手动。

1.1.1 自动Acknowledgement

Channel#basicConsume(autoAck=false) ,这种模式下,consumer并未真正的发送Ack到Broker,即消费者不做任何操作,Broker便自动确认,其确认的具体时机为消息写入TCP Socket。所以这种模式下,并不能保证数据的安全投递(Delivery,指Broker到消费者)。

1.1.2 手动Acknowledgement

Channel#basicConsume(autoAck=false) ,这种模式下,consumer需要手动发送Ack,其确认的时机由用户决定,一般是处理完消息后发送Ack。

1.1.2.1 手动Acknowledgement原理

Broker向Consumer投递消息时,每条消息都会附带一个Devlivery Tag (一个单调递增的整数),消费者在对某条消息进行手动Ack时,需要携带其Devlivery Tag ,Broker便是根据Devlivery Tag 识别Ack所对应的消息的。

1.1.2.2 手动Acknowledgement类型
  1. Channel#basicAck :表明消息已经受到并被正确处理,Broker可将该消息删除。

  2. Chanenl#basicReject :表明消息已经收到但是未被处理,Broker可根据Consumer发送的reject消息中包含的requeue参数决定将消息删除或是将消息重新入队。

    应用场景:有多个消费者实例,若当前消费者繁忙,则可reject当前消息,并令其重新入队。然后由其他消费者实例处理。

  3. Channel#basicNack:同basicReject方法类似,但是支持批量拒绝消息。

1.1.2.3 批量Ack

Consumer每次进行Ack,都会向Broker发送一次请求,为减轻带宽压力,Consumer支持批量Ack,示例代码如下:

channel.basicAck(deliveryTag, multiple=false)

注:Chanenl#basicReject不支持批量Ack。

1.2 生产者

生产者可通过事务或者confirm ,确保消息的可靠发布(publish),其中事务机制性能较差,并不推荐使用。

1.2.1 confirm方案

1.2.1.1 基本原理

可使用channel#confirmSelect启用生产者confirm

生产者confirm 方案的原理借鉴于消费者的acknowledgement,Producer向Broker发布消息时,每条消息都会附带一个Devlivery Tag (一个单调递增的整数),Broker在收到消息后会向Producer返回Acknowledgement(包括ack或者nack),Acknowledgement中同样会携带收到的消息中包含的Devlivery Tag生产者可根据Devlivery Tag 识别对应的消息。

confirm的完整流程如下图所示:

在这里插入图片描述

1.2.1.2 生产者处理confirm信息

生产者处理confirm信息的策略有如下几种

  1. 逐条发送,同步等待,处理Confirm信息
while (thereAreMessagesToPublish()) {
    byte[] body = ...;
    BasicProperties properties = ...;
    channel.basicPublish(exchange, queue, properties, body);
    // uses a 5 second timeout
    channel.waitForConfirmsOrDie(5_000);
}
  1. 批量发送,同步等待,处理批量Confirm信息
int batchSize = 100;
int outstandingMessageCount = 0;
while (thereAreMessagesToPublish()) {
    byte[] body = ...;
    BasicProperties properties = ...;
    channel.basicPublish(exchange, queue, properties, body);
    outstandingMessageCount++;
    if (outstandingMessageCount == batchSize) {
        channel.waitForConfirmsOrDie(5_000);
        outstandingMessageCount = 0;
    }
}
if (outstandingMessageCount > 0) {
    channel.waitForConfirmsOrDie(5_000);
}
  1. 异步处理confirm信息

该方案更为常用,通过为channel绑定ConfirmListener回调函数,来处理confirm信息。

Channel channel = connection.createChannel();
channel.confirmSelect();
channel.addConfirmListener((sequenceNumber, multiple) -> {
    // code when message is confirmed
}, (sequenceNumber, multiple) -> {
    // code when message is nack-ed
});
1.2.1.3 生产者处理return信息

根据上述的confirm流程可以看出,若Message发布到Exchange之后,未正确路由到队列,Broker可将该Message返回给Producer,Producer可使用ReturnListener接受返回的消息,然后作进一步处理,示例代码如下:

channel.addReturnListener(new ReturnListener() {
    public void handleReturn(int replyCode,
                                  String replyText,
                                  String exchange,
                                  String routingKey,
                                  AMQP.BasicProperties properties,
                                  byte[] body)
    throws IOException {
        ...
    }
});

1.3 Broker

Broker为保证数据可靠性,可使用durable queue ,其会将数据持久化到磁盘。

注:生产者发送数据时,需声明Delivery mode为persistent,若不声明,即便其位于durable queue中,当Broker重启后也会丢失。

为保证生产者的消息可靠的发布到Broker,Broker是在将所有消息路由到所有匹配队列,并落盘之后才会向生产者发送Ack。

为保证数据从Broker可靠的投递到消费者,Broker支持消费者打回数据,并重新入队,重新投递。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值