Kafka保證消息不丟失

Kafka保證消息不丟失

kafka保證消息不丟失,需要從三個方面考慮:

  • 生產者端消息不丟失
  • kafka服務器broker本身消息不丟失
  • 消費者端消息不丟失

這篇文章對最新發送kafka數據丟失的情況做一個總結。

1.爲什麼要出這樣一個文檔

首先,部門很多人都kafka的使用不太懂,主要集中才kafka參數的設置使用,比如producer、server下的topic參數、consumer使用,往往配置的參數設置不合適出現各種問題;

其次,我們的消息(傳感器數據)的特點是:消息體大小差別很大,小的幾kb,大的消息體可能有好幾十M。總體是要設置一個較大的單挑消息的上限值,30M左右;消息的字節數大,導致吞吐量也比較大,kafka的設置需要適應較高的吞吐量;
最後,最近測試人員提出的kafka消息的丟失等問題,始終存在,不斷解決類似湧現的問題,在遠程辦公的條件下,解決此類問題可以說是效率低下。

2.想要集中解決的問題:

通過設置合適的kafka參數,保證使用kafka的過程的的穩定性。解決由於個體差異導致類似問題不停重複出現的問題;

3.詳細問題解答

3.1客戶端保證消息不丟失
消息的完整性和系統的吞吐量是互斥的,爲了確保消息不丟失就必然會損失系統的吞吐量
producer:
1、ack設置-1
該參數默認值爲1,只是保證topic中的patition的leader刷寫磁盤成功,此時副本不一定同步成功,如果此時該分區的leader掛掉,會導致數據丟失;
保證數據不丟失,建議設置爲”all”或者“-1”,此時會保證分區下的所有副本都同步成功。目前副本數是2(即一主leader一副本replic)

2、設置副本同步成功的最小同步個數爲副本數-1
min.insync.replicas
同步副本數量,如果分區replica副本數爲3,此處最好設置爲2
3、加大重試次數 reties = 10
該參數可以保證,第一次發送數據失敗的時候,是否需要重新發送,此處爲重試10,如果重試10次仍然不能成功,則producer會拋出異常或者不報異常直接丟棄數據。(默認是不報出異常的直接丟棄數據,如果想要獲得失敗的丟棄的數據,就可以使用producer的callBack函數獲取異常感知);
4、同步發送
默認kafka採用異步方式發送數據,來保證較大的吞吐量;同步方式,需要每條消息都確認接受並刷寫磁盤成功纔會返回ack確認,纔會開始發送下一條,效率較低;
5、對於單條數據過大,要設置可接收的單條數據的大小
該設置是在kafkaManager的每個topic中設置max.message.bytes來確定每個消息大小的。默認大小爲1m;
6、對於異步發送,通過回調函數來感知丟消息,使用KafkaProducer.send(record, callback)方法而不是send(record)方法
如果是採用異步的方式發送數據,最好是採用kafka回調callback的方式,捕獲發送失敗情況下的異常,提前獲知哪些消費發送失敗;

7、配置不允許非ISR(In-Sync Replicas,副本同步隊列)集合中的副本當leader。所有的副本(replicas)統稱爲 Assigned Replicas,即 AR
unclean.leader.election
kafka 選擇非同步副本作爲首領副本的行爲叫做,不完全首領選舉。如何控制kafka在leader宕機時,同步副本不可用時,是否選擇非同步
作爲首領?通過kafka的另外一個參數來控制的 : unclean.leader.election. 如果是true 則會發生不完全首領選舉。
副本數建議3個就可以,多的話需要更多的磁盤,unclean.leader.election 建議false.

8、客戶端緩衝區滿了也可能會丟消息;或者異步情況下消息在客戶端緩衝區還未發送,客戶端就宕機

具體來說,建議的客戶端配置如下:

Properties props = new Properties();
props.put("bootstrap.servers", kafkaIP);
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer", "org.apache.kafka.common.serialization.ByteArraySerializer");

//表明kafka的數據來源,標記produceId
props.put("client.id","myname-tank");
props.put("acks", "all");
props.put("retries", "10");
//同一個分區中每一個批次的中的大小字節數,默認是16342個字節;此處改爲每個批次2M(此處可以具體調整)
props.put("batch.size","2000000");
//此處改爲過多久發送一批次數據,即使批次沒有達到要求的批次大小,也會觸發發送;此處改爲1000ms
props.put("linger.ms","1000");

//限制單個消息請求的最大值
props.put("max.request.size", MAX_NUMBER);
//TCP發送緩衝區(SO_SNDBUF)的大小,若send.buffer.bytes設爲-1,則使用操作系統的默認值
props.put("send.buffer.bytes", MAX_NUMBER);
props.put("buffer.memory", MAX_NUMBER);

從kafkaManager的topic中配置詳細的參數如下:

4.問題思考

以上方法固然可以避免kafka發送數據丟失的情況(說到底只是解決問題的手段),那麼當前數據丟失的根本原因是什麼呢?(根本問題)【思維方法:我們可以採用常規問題定位+驗證,然後排除錯誤猜想,抽絲剝繭,根據已有依據,縮小猜想範圍,不斷迭代從而最終定位問題】
目前的經常性發送數據丟失,正常情況下是broker宕機導致kafka 的topic下的patition的中leader宕機,從而出現數據丟失的情況。
但是目前kafka系統並沒有出現明顯的broker宕機的日誌,排除broker宕機導致的leader丟失情況,那麼我們繼續推測的話,發現zookeeper作爲分佈式協調服務中心存在,kafka每個節點的心跳信息,kafka的元數據管理(kafka的topic信息保存,offset保存(當前已經改爲kafka自己保存了)),leader節點選舉等工作歸其管轄。
通過日誌發現,其日誌中存在大量的leader節點選舉相關的日誌輸出。(我們知道這樣一個前提,那就是kafka的leader節點在選舉期間是不能提供對外讀寫服務的)。這種不能提供對外服務的情況使得client端報出找不到leader的錯誤(消費者連接kafka也可能出現這個錯誤)。通過kafka服務器端報出大量的選舉日誌和lsr同步日誌。兩種日誌結合起來看,節點一旦出現選舉,來不及同步副本的leader會出現掛機(acks=1),導致leader分區上的消息丟失。
以上的分析結果最有可能的,是zookeeper獲取不到分區leader的心跳信息,以爲其掛掉導致重新選舉,因此問題轉向zookeeper與kafka的心跳聯繫的問題;

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