Kafka Cluster優化兩三事
轉自:https://bigdata-ny.github.io/2016/12/05/kafka-cluster-optimize/
寫在之前:本文將講述Kafka Cluster配置和優化。
Kafka Cluster(相對於單個server)最大的優點:可擴充套件性和容錯性。
Kafka叢集簡圖
Kafka Broker個數
決定Kafka叢集大小的因素有以下幾點:
- 磁碟容量:首先考慮的是所需儲存的訊息所佔用的總磁碟容量和每個broker所能提供的磁碟空間。如果Kafka叢集需要保留 10 TB資料,單個broker能儲存 2 TB,那麼我們需要的最小Kafka叢集大小 5 個broker。此外,如果啟用副本引數,則對應的儲存空間需至少增加一倍(取決於副本引數)。這意味著對應的Kafka叢集至少需要 10 個broker。
- 請求量:另外一個要考慮的是Kafka叢集處理請求的能力。這主要取決於對Kafka client請求的網路處理能力,特別是,有多個consumer或者網路流量不穩定。如果,高峰時刻,單個broker的網路流量達到80%,這時是撐不住兩個consumer的,除非有兩個broker。再者,如果啟用了副本引數,則需要考慮副本這個額外的consumer。也可以擴充套件多個broker來減少磁碟的吞吐量和系統記憶體。
Kafka Broker配置
同一個Kafka叢集的所有broker機器必須滿足以下兩個引數:
- 所有broker機器需配置相同的zookeeper連線引數(.connect)。這決定了Kafka叢集儲存的元資料位置;
- 所有broker機器需配置唯一的broker id( .id)。如果一個叢集下的兩個broker配置了相同的broker id,則第二個broker啟動時會失敗並報錯。
作業系統優化
大部分Linux釋出版本預設的核心引數配置能讓大部分應用工作的相當好。但對於實際的Kafka broker場景來說,做稍些改變會提升broker效能。主要涉及的配置:虛擬記憶體、網路和磁碟掛載(用來儲存log segment),一般在/etc/sysctl.conf (CentOS系統)。
- Virtual Memory
一般來說,Linux的虛擬記憶體會根據系統負載自動調整。記憶體頁(page)swap到磁碟會顯著的影響Kafka的效能,並且Kafka重度使用page cache,如果VM系統swap到磁碟,那說明沒有足夠的記憶體來分配page cache。
避免swap的一種方式是設定swap空間為0。但是,swap會在系統崩潰時提供安全機制,或者會在out of memory的情況下阻止作業系統 kill 掉程序。由於這個原因,推薦 vm.swappiness引數設定為一個非常低的值:1 。這個引數表示 VM系統中的多少百分比用來作為swap空間。
另外一種方式是通過核心調節“髒頁”(注:“髒頁”會被刷到磁碟上)。Kafka依賴磁碟I/O效能來提高producer的響應時間。這也是為什麼通常優先把log segment功能放在可以快速響應的磁碟中(比如,SSD)。這樣使得flush程序把“髒資料”寫入磁碟前,“髒頁”數目就減少了,可以設定vm.dirty_background_ratio(表示佔用系統記憶體的百分比)引數的值為 10 以下。大部分應用場景下,vm.dirty_background_ratio設定為 5 就夠用了,要注意了:這個引數值不能設定為 0 ,因為設定為 0 後會引起核心持續刷“髒頁”,使得核心的buffer write功能沒法施展。
“髒頁”的總量可以通過vm.dirty_ratio 來改變,預設值是 20 (此處也是百分比),這個值的設定範圍較大,一般建議設定 60 到 80 為合理的值。但是vm.dirty_ratio 引數也引來了不小的風險,會造成大量unflush的資料在硬刷到磁碟時產生較長的I/O停頓。如果vm.dirty_ratio 值設定的較大時,強烈建議Kafka開啟備份功能,以備系統崩潰。
在設定了這些引數後,需要監控Kafka叢集執行時“髒頁”的數量,當前“髒頁”數量可由如下方式檢視(/proc/vmstat檔案):
1 2 3 |
# cat /proc/vmstat | egrep "dirty|writeback" nr_dirty 3875 nr_writeback 29 nr_writeback_temp 0 |
- 磁碟
除了考慮磁碟硬體本身和RAID配置外,磁碟的filesystem對Kafka叢集的影響最大。雖然有許多filesystem,但最常用的是EXT4或者XFS。在這裡XFS檔案系統比EXT4稍好,具體原因Google下。
另外一點是,建議開啟mount的noatime mount選項。檔案系統在檔案被訪問、建立、修改等的時候會記錄檔案的一些時間戳,比如:檔案建立時間(ctime)、最近一次修改時間(mtime)和最近一次訪問時間(atime)。預設情況下,atime的更新會有一次讀操作,這會產生大量的磁碟讀寫,然而atime對Kafka完全沒用。
- 網路
Linux釋出版本的網路引數對高網路流量不適用。對於Kafka叢集,推薦更改每個socket傳送和接收buffer的最大記憶體:net.core.wmem_default 和 net.core.rmem_default 為128 kb,net.core.wmem_max 和net.core.rmem_max 為 2 Mb。另外一個socket引數是TCP socket的傳送和接收buffer: net.ipv4.tcp_wmem 和 net.ipv4.tcp_rmem。
Kafka叢集穩定
主要涉及到GC、資料中心佈局和ZK使用:
- GC調優
調GC是門手藝活,幸虧Java 7引進了G1 垃圾回收,使得GC調優變的沒那麼難。G1主要有兩個配置選項來調優:MaxGCPauseMillis和InitiatingHeapOccupancyPercent,具體引數設定可以參考Google,這裡不贅述。
Kafka broker能夠有效的利用堆記憶體和物件回收,所以這些值可以調小點。對於 64Gb記憶體,Kafka執行堆記憶體5Gb,MaxGCPauseMillis和InitiatingHeapOccupancyPercent 分別設定為 20毫秒和 35。
Kafka的啟動指令碼使用的不是 G1回收,需要在環境變數中加入:
1 2 3 |
# export JAVA_HOME=/usr/java/jdk1.8.0_51 # export KAFKA_JVM_PERFORMANCE_OPTS="-server -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:InitiatingHeapOccupancyPercent=35 -XX:+DisableExplicitGC -Djava.awt.headless=true" # /usr/local/kafka/bin/kafka-server-start.sh -daemon /usr/local/kafka/config/server.properties |
- 資料中心佈局
原則上Kafka broker不建議都在一個機架上,為了容災,但現實情況大部分公司做不到,此處略去。
- Zookeeper
Kafka叢集利用ZK來儲存broker、topic和partition的元資料資訊。
在Kafka 0.9.0之前,consumer利用ZK來直接儲存consumer group的資訊,包括topic的消費情況、每個partition消費的週期性commit。在0.9.0版本,提供新的consumer介面利用Kafka broker來管理。
Consumer可以選擇使用Zk或者Kafka來提交 offset和 提交間隔。如果consumer使用ZK管理offset,那每個consumer在每個partition的每個時間間隔寫入ZK。合理的offset提交間隔是1分鐘,但如果一個Kafka叢集有大量的consumer消費時,這個ZK流量將是巨大的。所以如果ZK不能處理大流量,那隻能把offset提交間隔設大,但同時也帶來丟資料的風險。最保險的建議是使用Kafka來提交offset。
另外,建議Kafka叢集不要和其他應用使用同一組ZK,因為Kafka對於ZK的延遲和超時是相當敏感的,ZK的不通將會導致Kafka的不可預測性。