RabbitMQ的高可靠(消息應答、持久化、事務機制、confirm模式、發送方 / 接收方確認機制)

消息應答

boolean autoAck = false;
channel.basicConsume(QUEUE_NAME, autoAck, consumer);

boolean autoAck = false;自動確認模式,一旦RabbitMQ將消息分發給消費者就會從內存中刪除;這種情況下,如果殺死正在執行的消費者,就會丟失正在處理的消息。

boolean autoAck = false;手動模式,如果有一個消費者掛掉,就會交付給其他消費者,RabbitMQ支持消息應答,消費者發送一個消息應答告訴RabbitMQ這個消息已經處理完成,然後RabbitMQ就刪除內存中的消息。

消息應答默認是打開的,即默認是false。

如果RabbitMQ掛了,我們的消息仍然會丟失。

消息的持久化(確保消息不丟失)

RabbitMQ的持久化分爲三個部分:交換器的持久化、隊列的持久化、消息的持久化。

//聲明隊列
channel.queueDeclare(QUEUE_NAME, false, false, false, null);

其中的參數源碼如下:

public com.rabbitmq.client.impl.AMQImpl.Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) throws IOException {
    validateQueueNameLength(queue);
    return (com.rabbitmq.client.impl.AMQImpl.Queue.DeclareOk)this.exnWrappingRpc((new com.rabbitmq.client.AMQP.Queue.Declare.Builder()).queue(queue).durable(durable).exclusive(exclusive).autoDelete(autoDelete).arguments(arguments).build()).getMethod();
}

存在的問題:將代碼中的boolean durable = false; 改爲true,是不可以的,儘管代碼是正確的,也不會運行成功,因爲已經定義了一個同名的work queue,這個queue是未持久化的,RabbitMQ不允許重新定義(不同參數)一個已存在的隊列。
解決辦法:從控制檯刪除已定義的queue。

RabbitMQ的事務機制+confirm模式

在RabbitMQ中,我們可以通過持久化數據,解決RabbitMQ服務器異常導致的數據丟失問題。

問題:生產者將消息發送出去之後,消息到底有沒有到達RabbitMQ服務器?
兩種方式:

  • AMQP實現了的事務機制
  • Confirm模式

AMQP提供的事務機制

txSelect、txCommit、txRollback
txSelect:用於將當前Channel設置成transaction事務模式
txCommit:用於提交事務
txRollback:回滾事務
這種事務機制降低了RabbitMQ的吞吐量。

Confirm模式

生產者端Confirm模式的實現原理:Confirm模式的最大的好處是異步的。
開啓Confirm模式:

channel.confirmSelect();

編程模式

  • 普通:發一條,waitForConfirms()
  • 批量的:發一批,waitForConfirms
  • 異步的Confirm模式:提供一個回調方法

異步模式:Channel對象提供的ConfirmListener()回調方法只包含deliverTag(當前Channel發出的消息序號),我們需要自己爲每一個Channel維護一個unconfirm的消息序號集合,每publish(發送)一條數據,集合中元素加1,每回調一次handleAck()方法,unconfirm集合刪掉相應的一條(multiple=false)或多條(multiple=true)記錄,從程序運行效率上看,這個unconfirm集合最好採用有序集合SortedSet存儲結構。

RabbitMQ的發送方確認機制(確保消息發送正確)

採用事務機制會嚴重降低RabbitMQ的吞吐量,於是引入了一種輕量級的方式——發送方確認機制。具體是:生產者將信道設置成 confirm(確認)模式,一旦信道進入 confirm 模式,所有在該信道上面發佈的消息都會被指派一個唯一的ID(從1開始),一旦消息被投遞到所有匹配的隊列之後,RabbitMQ就會發送一個確認(Basic.Ack)給生產者(包含消息的唯一ID),這就使得生產者知道消息已經正確到達目的地了。

RabbitMQ的接收方確認機制(確保消息被正確消費)

爲了確保消息從隊列可靠地到達消費者,RabbitMQ提供了消息確認機制:消費者在訂閱隊列時,可以指定autoAck參數,當autoAck = false 時,RabbitMQ會等待消費者顯式地回覆確認信號後才從內存(或者磁盤)中移除消息。當autoAck = true時,RabbitMQ會自動把發送出去的消息置爲確認,然後從內存(或磁盤)中刪除,而不管消費者是否真正地消費到了這些消息。

如果RabbitMQ一直沒有收到消費者的確認信號,並且消費此消息的消費者已經斷開連接,則RabbitMQ會安排該消息重新進入隊列,等待投遞給下一個消費者,當然也可能還是原來的消費者。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章