Producer發送消息階段 發送消息階段涉及到Producer到broker的網絡通信,因此丟失消息的幾率一定會有,那RocketMQ在此階段用了哪些手段保證消息不丟失了(或者說降低丟失的可能性)。 手段一:提供SYNC的發送消息方式,等待broker處理結果。RocketMQ提供了3種發送消息方式,分別是: 同步發送:Producer 向 broker 發送消息,阻塞當前線程等待 broker 響應 發送結果。 異步發送:Producer 首先構建一個向 broker 發送消息的任務,把該任務提交給線程池,等執行完該任務時,回調用戶自定義的回調函數,執行處理結果。 Oneway發送:Oneway 方式只負責發送請求,不等待應答,Producer只負責把請求發出去,而不處理響應結果。 我們在調用producer.send方法時,不指定回調方法,則默認采用同步發送消息的方式,這也是丟失幾率最小的一種發送方式。 手段二:發送消息如果失敗或者超時,則重新發送。 發送重試源碼如下,本質其實就是一個for循環,當發送消息發生異常的時候重新循環發送。默認重試3次,重試次數可以通過producer指定。 手段三:broker提供多master模式,即使某台broker宕機了,保證消息可以投遞到另外一台正常的broker上。 如果broker只有一個節點,則broker宕機了,即使producer有重試機制,也沒用,因此利用多主模式,當某台broker宕機了,換一台broker進行投遞。 總結 producer消息發送方式雖然有3種,但為了減小丟失消息的可能性盡量采用同步的發送方式,同步等待發送結果,利用同步發送+重試機制+多個master節點,盡可能減小消息丟失的可能性。 Broker處理消息階段 手段四:提供同步刷盤的策略 public enum FlushDiskType { SYNC_FLUSH, //同步刷盤 ASYNC_FLUSH//異步刷盤(默認) } 我們知道,當消息投遞到broker之后,會先存到page cache,然后根據broker設置的刷盤策略是否立即刷盤,也就是如果刷盤策略為異步,broker並不會等待消息落盤就會返回producer成功,也就是說當broker所在的服務器突然宕機,則會丟失部分頁的消息。 手段五:提供主從模式,同時主從支持同步雙寫 即使broker設置了同步刷盤,如果主broker磁盤損壞,也是會導致消息丟失。 因此可以給broker指定slave,同時設置master為SYNC_MASTER,然后將slave設置為同步刷盤策略。 此模式下,producer每發送一條消息,都會等消息投遞到master和slave都落盤成功了,broker才會當作消息投遞成功,保證休息不丟失。 總結 在broker端,消息丟失的可能性主要在於刷盤策略和同步機制。 RocketMQ默認broker的刷盤策略為異步刷盤,如果有主從,同步策略也默認的是異步同步,這樣子可以提高broker處理消息的效率,但是會有丟失的可能性。因此可以通過同步刷盤策略+同步slave策略+主從的方式解決丟失消息的可能。 Consumer消費消息階段 手段六:consumer默認提供的是At least Once機制 從producer投遞消息到broker,即使前面這些過程保證了消息正常持久化,但如果consumer消費消息沒有消費到也不能理解為消息絕對的可靠。因此RockerMQ默認提供了At least Once機制保證消息可靠消費。 何為At least Once? Consumer先pull 消息到本地,消費完成后,才向服務器返回ack。 通常消費消息的ack機制一般分為兩種思路: 1、先提交后消費; 2、先消費,消費成功后再提交; 思路一可以解決重復消費的問題但是會丟失消息,因此Rocketmq默認實現的是思路二,由各自consumer業務方保證冪等來解決重復消費問題。
說白了,同步發送,同步落盤