Kafka問題總結及性能優化最佳實踐

一、書寫背景:

? 最近陸續碰到不少朋友在導論在使用kafka時遇到了不少問題,特別在高流量的場景下,更是問題百出,防不勝防。剛好在之前的項目中也遇到了類似場景的問題,通過各種摸爬滾打,算是最近解決了遇到的問題。因此趁此機會把實踐與大家共享,期望對各位遇到問題的朋友有一定的幫助。

二、最佳實踐:

1.? 安裝及時使用:

? ?kafka的安裝及基本使用可參考:https://www.cnblogs.com/dadonggg/p/8205302.html

2.?百億流量規劃:


流量分解及環境分析過程


3. JVM參數設置

kafka是scala語言開發,運行在JVM上,需要對JVM參數合理設置,修改bin/kafka-start-server.sh中的jvm設置,假設機器是32G內存,可以如下設置:

export KAFKA_HEAP_OPTS="‐Xmx16G‐Xms16G‐Xmn10G‐XX:MetaspaceSize=256M‐XX:+UseG1GC‐XX:MaxGCPauseMillis=50‐XX:G1HeapRegionSize=16M"

這種大內存的情況一般都要用G1垃圾收集器,因為年輕代內存比較大,用G1可以設置GC最大停頓時間(針對每個參數的具體含義如有不清楚的可百度,在此不對其參數的含義做過多的講解),不至于一次minorgc就花費太長時間,當然,因為像kafka,rocketmq,es這些中間件,寫數據到磁盤會用到操作系統的page cache(對于系統的所有文件I/O請求,操作系統都是通過page cache機制實現的,對于操作系統而言,磁盤文件都是由一系列的數據塊順序組成,數據塊的大小隨系統不同而不同,x86 linux系統下是4KB(一個標準頁面大小)。內核在處理文件I/O請求時,首先到page cache中查找(page cache中的每一個數據塊都設置了文件以及偏移信息),如果未命中,則啟動磁盤I/O,將磁盤文件中的數據塊加載到page cache中的一個空閑塊。之后再copy到用戶緩沖區中),所以JVM內存不宜分配過大,需要給操作系統的緩存留出幾個G。

4. 線上問題及優化:

1). 消息丟失情況:

消息發送端:

(1)acks=0: 表示producer不需要等待任何broker確認收到消息的回復,就可以繼續發送下一條消息。性能最高,但是最容易丟消息。大數據統計報表場景,對性能要求很高,對數據丟失不敏感的情況可以用這種。

(2)acks=1: 至少要等待leader已經成功將數據寫入本地log,但是不需要等待所有follower是否成功寫入。就可以繼續發送下一條消息。這種情況下,如果follower沒有成功備份數據,而此時leader又掛掉,則消息會丟失。

(3)acks=-1或all: 這意味著leader需要等待所有備份(min.insync.replicas配置的備份個數)都成功寫入日志,這種策略會保證只要有一個備份存活就不會丟失數據。這是最強的數據保證。一般除非是金融級別,或跟錢打交道的場景才會使用這種配置。當然如果min.insync.replicas配置的是1則也可能丟消息,跟acks=1情況類似。

消息消費端:

如果消費這邊配置的是自動提交,萬一消費到數據還沒處理完,就自動提交offset了,但是此時你consumer直接宕機了,未處理完的數據丟失了,下次也消費不到了。

2). 消息重復消費

消息發送端:

發送消息如果配置了重試機制,比如網絡抖動時間過長導致發送端發送超時,實際broker可能已經接收到消息,但發送方會重新發送消息

消息消費端:

如果消費這邊配置的是自動提交,剛拉取了一批數據處理了一部分,但還沒來得及提交,服務掛了,下次重啟又會拉取相同的一批數據重復處理

一般消費端都是要做消費冪等處理的。

3). 消息亂序

如果發送端配置了重試機制,kafka不會等之前那條消息完全發送成功才去發送下一條消息,這樣可能會出現,發送了1,2,3條消息,第一條超時了,后面兩條發送成功,再重試發送第1條消息,這時消息在broker端的順序就是2,3,1了

所以,是否一定要配置重試要根據業務情況而定。也可以用同步發送的模式去發消息,當然acks不能設置為0,這樣也能保證消息發送的有序。

kafka保證全鏈路消息順序消費,需要從發送端開始,將所有有序消息發送到同一個分區,然后用一個消費者去消費,但是這種性能比較低,可以在消費者端接收到消息后將需要保證順序消費的幾條消費發到內存隊列(可以搞多個),一個內存隊列開啟一個線程順序處理消息。

4). 消息積壓

(1)線上有時因為發送方發送消息速度過快,或者消費方處理消息過慢,可能會導致broker積壓大量未消費消息。

此種情況如果積壓了上百萬未消費消息需要緊急處理,可以修改消費端程序,讓其將收到的消息快速轉發到其他topic(可以設置很多分區),然后再啟動多個消費者同時消費新主題的不同分區。

(2)由于消息數據格式變動或消費者程序有bug,導致消費者一直消費不成功,也可能導致broker積壓大量未消費消息。

此種情況可以將這些消費不成功的消息轉發到其它隊列里去(類似死信隊列),后面再慢慢分析死信隊列里的消息處理問題。

5). 延時隊列

延時隊列存儲的對象是延時消息。所謂的“延時消息”是指消息被發送以后,并不想讓消費者立刻獲取,而是等待特定的時間后,消費者才能獲取這個消息進行消費,延時隊列的使用場景有很多, 比如 :

1)在訂單系統中, 一個用戶下單之后通常有 30 分鐘的時間進行支付,如果 30 分鐘之內沒有支付成功,那么這個訂單將進行異常處理,這時就可以使用延時隊列來處理這些訂單了。

2)訂單完成1小時后通知用戶進行評價。

實現思路:發送延時消息時先把消息按照不同的延遲時間段發送到指定的隊列中(topic_1s,topic_5s,topic_10s,...topic_n,這個一般不能支持任意時間段的延時),然后通過定時器進行輪詢消費這些topic,查看消息是否到期,如果到期就把這個消息發送到具體業務處理的topic中,隊列中消息越靠前的到期時間越早,具體來說就是定時器在一次消費過程中,對消息的發送時間做判斷,看下是否延遲到對應時間了,如果到了就轉發,如果還沒到這一次定時任務就可以提前結束了。

6). 消息回溯

如果某段時間對已消費消息計算的結果覺得有問題,可能是由于程序bug導致的計算錯誤,當程序bug修復后,這時可能需要對之前已消費的消息重新消費,可以指定從多久之前的消息回溯消費,這種可以用consumer的offsetsForTimes、seek等方法指定從某個offset偏移的消息開始消費。

7). 分區數越多吞吐量越高嗎

可以用kafka壓測工具自己測試分區數不同,各種情況下的吞吐量

# 往test里發送一百萬條消息(--num-records 1000000),每條設置1KB(record-size 1024字節)

# throughput 用來進行限流控制,當設定的值小于 0 時不限流,當設定的值大于 0 時,當發送的吞吐量大于該值時就會被阻塞一段時間

bin/kafka-producer-perf-test.sh --topic test --num-records 1000000 --record-size 1024 --throughput -1 --producer-props bootstrap.servers=192.168.2.4:9092 acks=1

壓測效果圖

網絡上很多資料都說分區數越多吞吐量越高 , 但從壓測結果來看,分區數到達某個值吞吐量反而開始下降,實際上很多事情都會有一個臨界值,當超過這個臨界值之后,很多原本符合既定邏輯的走向又會變得不同。一般情況分區數跟集群機器數量相當就差不多了。

當然吞吐量的數值和走勢還會和磁盤、文件系統、 I/O調度策略等因素相關。

注意:如果分區數設置過大,比如設置10000,可能會設置不成功,后臺會報錯"java.io.IOException : Too manyopenfiles"。

異常中最關鍵的信息是“ Too many open flies”,這是一種常見的 Linux 系統錯誤,通常意味著文件描述符不足,它一般發生在創建線程、創建 Socket、打開文件這些場景下 。 在 Linux系統的默認設置下,這個文件描述符的個數不是很多 ,通過 ulimit -n 命令可以查看:一般默認是1024,可以將該值增大,比如:ulimit-n 65535

8). 消息傳遞保障

at most once(消費者最多收到一次消息,0--1次):acks = 0 可以實現。

at least once(消費者至少收到一次消息,1--多次):ack = all 可以實現。

exactly once(消費者剛好收到一次消息):at least once 加上消費者冪等性可以實現,還可以用kafka生產者的冪等性來實現。

kafka生產者的冪等性:因為發送端重試導致的消息重復發送問題,kafka的冪等性可以保證重復發送的消息只接收一次,只需在生產者加上參數 props.put(“enable.idempotence”, true) 即可,默認是false不開啟 。--也可以在消費端的業務代碼中實現冪等性

9). kafka的事務

Kafka的事務不同于Rocketmq,Rocketmq是保障本地事務(比如數據庫)與mq消息發送的事務一致性,Kafka的事務主要是保障一次發送多條消息的事務一致性(要么同時成功要么同時失敗),一般在kafka的流式計算場景用得多一點,比如,kafka需要對一個topic里的消息做不同的流式計算處理,處理完分別發到不同的topic里,這些topic分別被不同的下游系統消費(比如hbase,redis,es等),這種我們肯定希望系統發送到多個topic的數據保持事務一致性。Kafka要實現類似Rocketmq的分布式事務需要額外開發功能。

kafka的事務處理可以參考官方文檔

實現代碼可參考如下:

Properties props = new Properties();

props.put("bootstrap.servers", "localhost:9092");

props.put("transactional.id", "my-transactional-id");

Producer<String, String> producer = new KafkaProducer<>(props, new StringSerializer(), new StringSerializer());

//初始化事務

producer.initTransactions();

try {

? ? //開啟事務

? ? producer.beginTransaction();

? ? for (int i = 0; i < 100; i++){

? ? ? ? //發到不同的主題的不同分區

? ? ? ? producer.send(new ProducerRecord<>("hdfs-topic", Integer.toString(i), Integer.toString(i)));

? ? ? ? producer.send(new ProducerRecord<>("es-topic", Integer.toString(i), Integer.toString(i)));

? ? ? ? producer.send(new ProducerRecord<>("redis-topic", Integer.toString(i), Integer.toString(i)));

? ? }

? ? //提交事務

? ? producer.commitTransaction();

} catch (ProducerFencedException | OutOfOrderSequenceException | AuthorizationException e) {

? ? // We can't recover from these exceptions, so our only option is to close the producer and exit.

? ? producer.close();

} catch (KafkaException e) {

? ? // For all other exceptions, just abort the transaction and try again.

? ? //回滾事務

? ? producer.abortTransaction();

}

producer.close();

10). kafka高性能的原因

(1). 磁盤順序讀寫:kafka消息不能修改以及不會從文件中間刪除保證了磁盤順序讀,kafka的消息寫入文件都是追加在文件末尾,不會寫入文件中的某個位置(隨機寫)保證了磁盤順序寫。

(2). 數據傳輸的零拷貝(零拷貝主要指數據操作時在內核空間可直接完成,不用與用戶空間(JVM)進行交互),其原理如下:


(3). 讀寫數據的批量batch處理以及壓縮傳輸

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容