數據不能多,也不能少,不能可能是說消息不能重複消費,這個咱們上一節已解決;不能少,就是說不能丟失數據。若是mq傳遞的是很是核心的消息,支撐核心的業務,那麼這種場景是必定不能丟失數據的。bash
丟數據通常分爲兩種,一種是mq把消息丟了,一種就是消費時將消息丟了。下面從rabbitmq和kafka分別說一下,丟失數據的場景,
(1)rabbitmq
A:生產者弄丟了數據 生產者將數據發送到rabbitmq的時候,可能在傳輸過程當中由於網絡等問題而將數據弄丟了。
B:rabbitmq本身丟了數據 若是沒有開啓rabbitmq的持久化,那麼rabbitmq一旦重啓,那麼數據就丟了。所依必須開啓持久化將消息持久化到磁盤,這樣就算rabbitmq掛了,恢復以後會自動讀取以前存儲的數據,通常數據不會丟失。除非極其罕見的狀況,rabbitmq還沒來得及持久化本身就掛了,這樣可能致使一部分數據丟失。
C:消費端弄丟了數據 主要是由於消費者消費時,剛消費到,尚未處理,結果消費者就掛了,這樣你重啓以後,rabbitmq就認爲你已經消費過了,而後就丟了數據。 網絡
(1)rabbitmq
A:生產者丟失消息
①:能夠選擇使用rabbitmq提供是事物功能,就是生產者在發送數據以前開啓事物,而後發送消息,若是消息沒有成功被rabbitmq接收到,那麼生產者會受到異常報錯,這時就能夠回滾事物,而後嘗試從新發送;若是收到了消息,那麼就能夠提交事物。異步
channel.txSelect();//開啓事物
try{
//發送消息
}catch(Exection e){
channel.txRollback();//回滾事物
//從新提交
}
複製代碼
缺點: rabbitmq事物已開啓,就會變爲同步阻塞操做,生產者會阻塞等待是否發送成功,太耗性能會形成吞吐量的降低。post
②:能夠開啓confirm模式。在生產者哪裏設置開啓了confirm模式以後,每次寫的消息都會分配一個惟一的id,而後如何寫入了rabbitmq之中,rabbitmq會給你回傳一個ack消息,告訴你這個消息發送OK了;若是rabbitmq沒能處理這個消息,會回調你一個nack接口,告訴你這個消息失敗了,你能夠進行重試。並且你能夠結合這個機制知道本身在內存裏維護每一個消息的id,若是超過必定時間還沒接收到這個消息的回調,那麼你能夠進行重發。性能
//開啓confirm
channel.confirm();
//發送成功回調
public void ack(String messageId){
}
// 發送失敗回調
public void nack(String messageId){
//重發該消息
}
複製代碼
兩者不一樣 事務機制是同步的,你提交了一個事物以後會阻塞住,可是confirm機制是異步的,發送消息以後能夠接着發送下一個消息,而後rabbitmq會回調告知成功與否。 通常在生產者這塊避免丟失,都是用confirm機制。
B:rabbitmq本身弄丟了數據 設置消息持久化到磁盤。設置持久化有兩個步驟:
①建立queue的時候將其設置爲持久化的,這樣就能夠保證rabbitmq持久化queue的元數據,可是不會持久化queue裏面的數據。
②發送消息的時候講消息的deliveryMode設置爲2,這樣消息就會被設爲持久化方式,此時rabbitmq就會將消息持久化到磁盤上。 必需要同時開啓這兩個才能夠。spa
並且持久化能夠跟生產的confirm機制配合起來,只有消息持久化到了磁盤以後,纔會通知生產者ack,這樣就算是在持久化以前rabbitmq掛了,數據丟了,生產者收不到ack回調也會進行消息重發。
C:消費者弄丟了數據 使用rabbitmq提供的ack機制,首先關閉rabbitmq的自動ack,而後每次在確保處理完這個消息以後,在代碼裏手動調用ack。這樣就能夠避免消息尚未處理完就ack。code
(2)kafka
A:消費端弄丟了數據 關閉自動提交offset,在本身處理完畢以後手動提交offset,這樣就不會丟失數據。cdn
B:kafka弄丟了數據 通常要求設置4個參數來保證消息不丟失:
①給topic設置 replication.factor參數:這個值必須大於1,表示要求每一個partition必須至少有2個副本。blog
②在kafka服務端設置min.isync.replicas參數:這個值必須大於1,表示 要求一個leader至少感知到有至少一個follower在跟本身保持聯繫正常同步數據,這樣才能保證leader掛了以後還有一個follower。接口
③在生產者端設置acks=all:表示 要求每條每條數據,必須是寫入全部replica副本以後,才能認爲是寫入成功了
④在生產者端設置retries=MAX(很大的一個值,表示無限重試):表示 這個是要求一旦寫入事變,就無限重試
C:生產者弄丟了數據 若是按照上面設置了ack=all,則必定不會丟失數據,要求是,你的leader接收到消息,全部的follower都同步到了消息以後,才認爲本次寫成功了。若是沒知足這個條件,生產者會自動不斷的重試,重試無限次。
上一篇《如何保證消息不重複消費》
下一篇《如何保證消息按順序執行》