kafka-消息防丟失和消息去重

如何防止數據丟失

生產者:同步發送消息,且消息配置爲-1或all,leader分區和所有follwer都寫到磁盤裏。

異步模式下,爲防止緩衝區滿,可以在配置文件設置不限制阻塞超時時間,當緩衝區滿時讓生產者一直處於阻塞狀態。

生產者:手動提交,即讀取到消息後,確認消息消費完畢,才手動提交offset。但是要避免邏輯處理時間過長,導致連接超時,會使消息重複消費。

故kafka一定要配置上消息重試的機制,並且重試的時間間隔一定要長一些,默認1秒鐘並不符合生產環境(網絡中斷時間有可能超過1秒)。
增加如下參數會較大幅度的減少kafka寫入數據照成的數據丟失,在公司實測,目前還沒遇到數據丟失的情況。

生產端

設計上保證數據的可靠安全性,依據分區數做好數據備份,設立副本數等。
push數據的方式:同步異步推送數據:權衡安全性和速度性的要求,選擇相應的同步推送還是異步推送方式,當發現數據有問題時,可以改爲同步來查找問題。

flush是kafka的內部機制,kafka優先在內存中完成數據的交換,然後將數據持久化到磁盤.kafka首先會把數據緩存(緩存到內存中)起來再批量flush.
可以通過log.flush.interval.messages和log.flush.interval.ms來配置flush間隔

可以通過replica機制保證數據不丟.
代價就是需要更多資源,尤其是磁盤資源,kafka當前支持GZip和Snappy壓縮,來緩解這個問題
是否使用replica(副本)取決於在可靠性和資源代價之間的balance(平衡)

broker到 Consumer kafka的consumer提供兩種接口.
high-level版本已經封裝了對partition和offset的管理,默認是會定期自動commit offset,這樣可能會丟數據的

low-level版本自己管理spout線程和partition之間的對應關係和每個partition上的已消費的offset(定期寫到zk)
並且只有當這個offset被ack後,即成功處理後,纔會被更新到zk,所以基本是可以保證數據不丟的即使spout線程crash(崩潰),重啓後還是可以從zk中讀到對應的offset

異步要考慮到partition leader在未完成副本數follows的備份時就宕機的情況,即使選舉出了新的leader但是已經push的數據因爲未備份就丟失了!
不能讓內存的緩衝池太滿,如果滿了內存溢出,也就是說數據寫入過快,kafka的緩衝池數據落盤速度太慢,這時肯定會造成數據丟失。
儘量保證生產者端數據一直處於線程阻塞狀態,這樣一邊寫內存一邊落盤。
異步寫入的話還可以設置類似flume回滾類型的batch數,即按照累計的消息數量,累計的時間間隔,累計的數據大小設置batch大小。
設置合適的方式,增大batch 大小來減小網絡IO和磁盤IO的請求,這是對於kafka效率的思考。
不過異步寫入丟失數據的情況還是難以控制
還是得穩定整體集羣架構的運行,特別是zookeeper,當然正對異步數據丟失的情況儘量保證broker端的穩定運作吧

設置同步模式, producer.type = sync, Request.required.acks =  -1, replication.factor >= 2 且 min.insync.replicas >= 2

broker端:

topic設置多分區,分區自適應所在機器,爲了讓各分區均勻分佈在所在的broker中,分區數要大於broker數。分區是kafka進行並行讀寫的單位,是提升kafka速度的關鍵。

broker能接收消息的最大字節數的設置一定要比消費端能消費的最大字節數要小,否則broker就會因爲消費端無法使用這個消息而掛起。

broker可賦值的消息的最大字節數設置一定要比能接受的最大字節數大,否則broker就會因爲數據量的問題無法複製副本,導致數據丟失

消費端

		//producer用於壓縮數據的壓縮類型。默認是無壓縮。正確的選項值是none、gzip、snappy。壓縮最好用於批量處理,批量處理消息越多,壓縮性能越好
     props.put("compression.type", "gzip");
     //增加延遲
     props.put("linger.ms", "50");
     //這意味着leader需要等待所有備份都成功寫入日誌,這種策略會保證只要有一個備份存活就不會丟失數據。這是最強的保證。,
     props.put("acks", "all");
     //無限重試,直到你意識到出現了問題,設置大於0的值將使客戶端重新發送任何數據,一旦這些數據發送失敗。注意,這些重試與客戶端接收到發送錯誤時的重試沒有什麼不同。允許重試將潛在的改變數據的順序,如果這兩個消息記錄都是發送到同一個partition,則第一個消息失敗第二個發送成功,則第二條消息會比第一條消息出現要早。
     props.put("retries ", MAX_VALUE);
     props.put("reconnect.backoff.ms ", 20000);
     props.put("retry.backoff.ms", 20000);
     
     //關閉unclean leader選舉,即不允許非ISR中的副本被選舉爲leader,以避免數據丟失
     props.put("unclean.leader.election.enable", false);
     //關閉自動提交offset
     props.put("enable.auto.commit", false);
     限制客戶端在單個連接上能夠發送的未響應請求的個數。設置此值是1表示kafka broker在響應請求之前client不能再向同一個broker發送請求。注意:設置此參數是爲了避免消息亂序
     props.put("max.in.flight.requests.per.connection", 1);

topic設置多分區,分區自適應所在機器,爲了讓各分區均勻分佈在所在的broker中,分區數要大於broker數。分區是kafka進行並行讀寫的單位,是提升kafka速度的關鍵。

如果處理耗時很長,則建議把邏輯放到另一個線程中去做。爲了避免數據丟失,有兩點建議:

enable.auto.commit=false 關閉自動提交位移

在消息被完整處理之後再手動提交位移

消息重複解決方案

針對消息重複:將消息的唯一標識保存到外部介質中,每次消費時判斷是否處理過即可。比如redis中

消息可以使用唯一id標識

生產者(ack=all 代表至少成功發送一次)

消費者 (offset手動提交,業務邏輯成功處理後,提交offset)

落表(主鍵或者唯一索引的方式,避免重複數據)

業務邏輯處理(選擇唯一主鍵存儲到Redis或者mongdb中,先查詢是否存在,若存在則不處理;若不存在,先插入Redis或Mongdb,再進行業務邏輯處理)

新版本的API在平衡的時候可以註冊一個對象,在平衡前和後可以調用這個對象的方法,我們在這個方法裏面將此topic的stream提交(這可能會造成數據丟失,因爲這些數據很可能還沒處理),

這個新API測試了下,基本沒什麼問題。
高級API如何解決?用類分佈式鎖最終解決了這個問題,實現思路比較簡單,就是通過ZK來實現,程序啓動前先定義好需要啓動的消費者數量,如果還沒達到這個量,線程都不能啓動,達到這個線程數後,休眠幾秒後啓動,在啓動的時候,消費者線程已經得到了平衡,除非線程死掉否則不會發生平衡了,所以暫時解決了這個問題。
思路共享出來,希望對大家有所幫助。

這裏需要 HW ( HighWartermark ) 的協同配合。類似於木桶原理,水位取決於最低那塊短板

某個 topic 的某 partition 有三個副本,分別爲 A、B、C。A 作爲 leader 肯定是 LEO 最高,B 緊隨其後,C 機器由於配置比較低,網絡比較差,故而同步最慢。這個時候 A 機器宕機,這時候如果 B 成爲 leader,假如沒有 HW,在 A 重新恢復之後會做同步(makeFollower) 操作,在宕機時 log 文件之後直接做追加操作,而假如 B 的 LEO 已經達到了 A 的 LEO,會產生數據不一致的情況

leader epoch

1500 * 1500

10023 項目名稱:A QT Latex Editor
詳細介紹:用QT實現一個所見即所得的Latex編輯器,能夠在圖形化界面的IDE裏面,採用類似Word的方式,所見即所得書寫文檔,生成Latex語法的源文件(.tex文件)。將此文件傳遞到服務器端,保存到數據庫中,編譯成pdf文件返回客戶端顯示。 支持在本地打開存儲在服務器端數據庫的文檔進行繼續編輯。
使用語言:qt(當然搭建服務器可以用node
截止日期:2019年5月31日
預期達到的效果:能夠獲得.tex文件和pdf文件,支持生成複雜公式
重點強調:附加講解工作,就是程序解讀以及使用說明

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