文章目錄
消息應答
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會安排該消息重新進入隊列,等待投遞給下一個消費者,當然也可能還是原來的消費者。