本文作者是一位軟體工程師,他對20位開發人員和數據科學家使用Apache Kafka的方式進行了最大限度得深入研究,最終將生產實踐環節需要註意的問題總結為本文所列的20條建議。 Apache Kafka是一個廣受歡迎的分散式流媒體平臺,New Relic、Uber以及Square等數千家公司都在使用 ...
本文作者是一位軟體工程師,他對20位開發人員和數據科學家使用Apache Kafka的方式進行了最大限度得深入研究,最終將生產實踐環節需要註意的問題總結為本文所列的20條建議。
![](http://s5.51cto.com/oss/201808/24/1d00c9247117d533ceb0c511046419db.jpeg-wh_651x-s_1486314781.jpeg)
Apache Kafka是一個廣受歡迎的分散式流媒體平臺,New Relic、Uber以及Square等數千家公司都在使用它構建可擴展、高吞吐量、可靠的實時流媒體系統。例如,New Relic的Kafka集群每秒處理超過1500萬條消息,總數據速率接近1 Tbps。
Kafka在應用程式開發人員和數據科學家中非常受歡迎,因為它極大簡化了數據流的處理過程。但是,Kafka在Scala上實踐會比較複雜。如果消費者無法跟上數據流,並且消息在他們看到之前就消失了,那麼具有自動數據保留限制的高吞吐量發佈/訂閱模式並沒有多大用。同樣,如果托管數據流的系統無法擴展以滿足需求或者不可靠,也沒有什麼用。
為了降低這種複雜性,作者將可能的問題分為4大類共20條,以方便用戶理解:
- Partitions(分區)
- Consumers(消費者)
- Producers(生產者)
- Brokers
Kafka是一種高效分散式消息傳遞系統,可提供內置數據冗餘和彈性,同時保留高吞吐量和可擴展性。它包括自動數據保留限制,使其非常適合將數據視為流的應用程式,並且還支持對鍵值對映射建模的“壓縮”流。
瞭解最佳實踐之前,你需要熟悉一些關鍵術語:
- Message消息:Kafka中的記錄或數據單元。每條消息都有一個鍵(key)和一個值(value),以及可選標題。
- 生產者:生產者向Kafka的topic發佈消息。生產者決定要發佈哪個topic分區,可以隨機(迴圈)或使用基於消息密鑰的分區演算法。
- Broker:Kafka在分散式系統或集群中運行,集群中的每個節點都稱為broker。
- Topic:Topic是發佈數據記錄或消息的類別。消費者訂閱topic以讀取寫入其中的數據。
- Topic partition:topic分為多個分區,每個消息都有一個偏移量。每個分區通常至少複製一或兩次。每個分區都有一個leader和至少一個副本(數據副本),這些副本存在於follower身上,可以防止broker失敗。集群中的所有broker都是leader和follower,但是代理最多只有一個topic partition副本,leader用於所有讀寫操作。
- 偏移:為分區內的每條消息分配一個偏移量,這是一個單調遞增整數,用作分區內消息的唯一標識符。
- 消費者:消費者通過訂閱 topic partition讀取Kafka主題的消息,消費應用程式,並處理消息以完成所需工作。
- Consumer group:消費者可以組織成消費者群組,分配topic partition以平衡組中所有使用者。在消費者群組中,所有消費者都在負載均衡模式下工作。換句話說,組中每個消費者都將看到每條消息。如果一個消費者離開,則將該分區分配給該組中的其他消費者,這個過程稱為再平衡。如果組中的消費者多於分區,則一些消費者將閑置。如果組中的消費者少於分區,則某些消費者將使用來自多個分區的消息。
- Lag:當消費者無法從分區中讀取消息,消費者就會出現Lag,表示為分區頂部後的偏移數。從Lag狀態恢復所需的時間取決於消費者每秒消耗消息的速度:
- time = messages / (consume rate per second - produce rate per second)
第一部分:使用分區的最佳實踐!
在分區部分,我們需要瞭解分區的數據速率,以確保擁有正確的保留空間。分區的數據速率是生成數據的速率。換句話說,它是平均消息大小乘以每秒消息數。數據速率決定了給定時間內所需的保留空間(以位元組為單位)。如果不知道數據速率,則無法正確計算滿足基本保留目標所需的空間大小。數據速率指定了單個消費者需要支持的最低性能而保證不會出現Lag。
除非有其他架構需求,否則在寫入topic時使用隨機分區。當進行大規模操作時,分區之間的數據速率不均可能難以管理。需要註意以下三方面:
1、首先,“熱點”(更高吞吐量)分區的消費者必須處理比消費者群組中其他消費者更多的消息,這可能導致處理和網路瓶頸。
2、其次,必須為具有最高數據速率的分區調整topic保留空間大小,這可能會導致topic中其他分區的磁碟使用量增加。
3、最後,在分區領導方面實現最佳平衡比簡單地擴展到所有 brokers更複雜。“熱點”分區的份量可能是同一topic中另一分區的10倍。
第二部分:使用消費者最佳實踐!
如果消費者運行的Kafka版本低於0.10,請升級。在0.8.x版本中,消費者使用Apache ZooKeeper進行消費者群組協調,並且許多已知錯誤可能導致長期運行的平衡甚至是重新平衡演算法的失敗(我們稱之為“重新平衡風暴”)。在重新平衡期間,將一個或多個分區分配給使用者群組中的每個使用者。在再平衡中,分區所有權在消費者中不斷變通,阻止任何消費者在消費方面取得實際進展。
4、調整消費者套接字緩衝區以進行高速獲取。在Kafka 0.10.x中,參數為isreceive.buffer.bytes,預設為64kB。在Kafka 0.8.x中,參數是socket.receive.buffer.bytes,預設為100kB。對於高吞吐量環境,這兩個預設值都太小,特別是如果brocker和消費者之間的網路帶寬延遲大於區域網(LAN)。對於延遲為1毫秒或更長的高帶寬網路(10 Gbps或更高),請考慮將套接字緩衝區設置為8或16 MB。如果記憶體不足,請考慮1 MB,也可以使用值-1,這樣底層操作系統可以根據網路條件調整緩衝區大小。但是,對於需要啟動“熱點”消費者的系統而言,自動調整的速度可能或比較慢。
5、設計高吞吐量消費者,以便在有保證的情況下實施背壓,最好只消耗可以有效處理的東西,而不是消耗太多,以至於過程停止,退出消費者群組。 消費者應該使用固定大小的緩衝區(參見Disruptor模式),如果在Java虛擬機(JVM)中運行,最好是在堆外使用。固定大小的緩衝區將阻止消費者將大量數據拖到堆上,JVM花費所有時間來執行垃圾收集而不是做你想讓它處理的工作——處理消息。
6、在JVM上運行消費者時,請註意垃圾回收可能對消費者產生的影響。例如,垃圾收集較長時間暫停可能導致ZooKeeper會話或者消費者組失去平衡。對於brocker來說也是如此,如果垃圾收集暫停時間過長,則可能會從集群中退出。
![](http://s2.51cto.com/oss/201808/24/086660acea19ad8c0910e85e60174062.jpeg)
第三部分:使用生產者最佳實踐!
7、配置生產者等待確認。 這就是生產者如何知道消息實際已經發送到brocker上的分區。在Kafka 0.10.x中,設置為acks; 在0.8.x中,它是request.required.acks。Kafka通過複製提供容錯功能,因此單個節點的故障或分區leader的更改不會影響可用性。如果將生產者配置為沒有ack(也稱為“fire and forget”),則消息可能會無聲地丟失。
8、配置生產者重試次數。預設值為3,通常太低。正確的值取決於需求,對於無法容忍數據丟失的應用程式,請考慮Integer.MAX_VALUE(實際上是無窮大),這可以防止leader分區的brocker無法立即響應生產請求。
9、對於高吞吐量生產者,調整緩衝區大小,特別是buffer.memory和batch.size(以位元組為單位)。由於batch.size是按分區設置的,因此生產者性能和記憶體使用量可與topic中的分區數相關聯。這裡的值取決於幾個因素:生產者數據速率(消息的大小和數量),生成的分區數以及可用的記憶體量。請記住,較大的緩衝區並不總是好的,如果生產者由於某種原因而停頓(例如,一個領導者通過確認響應較慢),在堆上緩存更多數據可能會導致更多垃圾收集。
10、制定應用程式跟蹤指標,例如生成的消息數,平均生成的消息大小和消耗的消息數。
第四部分:brocker最佳實踐!
11、Topic需要brocker的記憶體和CPU資源,日誌壓縮需要brocker上的堆(記憶體)和CPU周期才能成功完成,並且失敗的日誌壓縮會使brocker處於無限增長的分區風險中。你可以在brocker上使用tunelog.cleaner.dedupe.buffer.size和log.cleaner.threads,但請記住,這些值會影響brocker上的堆使用情況。如果brocker拋出OutOfMemoryError異常,它將關閉並可能丟失數據。緩衝區大小和線程數將取決於要清理的主題分區數量以及這些分區中消息的數據速率和密鑰大小。從Kafka 0.10.2.1版本開始,監視日誌清理程式日誌文件以查找ERROR條目是檢測日誌清理程式線程問題的最可靠方法。
12、監控brocker的網路吞吐量。確保使用發送(TX)和接收(RX),磁碟I/O,磁碟空間和CPU使用率來執行此操作。容量規劃是維護集群性能的關鍵部分。
13、在集群中的brocker之間分配分區leader,其需要大量的網路I/O資源。例如,當使用複製因數3運行時,leader必須接收分區數據,並同步傳遞給所有副本,再傳輸給想要使用該數據的消費者。因此,在這個例子中,作為領導者,在使用網路I/O方面至少是follower的四倍,leader必須從磁碟讀取,follower只需要寫。
14、不要忽略監視brocker的同步副本(ISR)縮減,重覆不足的分區和不受歡迎的lesder。這些是集群中潛在問題的跡象。例如,單個分區的頻繁ISR收縮可能表明該分區的數據速率超過了leader為消費者和副本線程提供服務的能力。
15、根據需要修改Apache Log4j屬性。Kafka代理日誌記錄可能會占用過多磁碟空間。但是,不要完全放棄日誌記錄,brocker日誌可能是在事件發生後重建事件序列的最佳方式,有時也是唯一方式。
16、禁用topic自動創建有關的明確策略,定期清理未使用的topic。例如,如果x天沒有看到任何消息,請考慮topic失效並將其從集群中刪除,這樣可以避免在集群中創建必須管理的其他元數據。
17、對於持續的高吞吐量代理,請提供足夠的記憶體以避免從磁碟系統讀取,應儘可能直接從操作系統的文件系統緩存中提供分區數據。但是,這意味著必須確保消費者能夠跟上,滯後的消費者將迫使brocker從磁碟讀取。
18、對於具有高吞吐量服務級別目標(SLO)的大型集群,請考慮將topic隔離到brocker子集。如何確定要隔離的topic取決於業務需求,例如,如果有多個使用相同集群的聯機事務處理(OLTP)系統,則將每個系統的topic隔離到brocker的不同子集以幫助限制事件的潛在爆炸半徑。
19、使用較新topic消息格式的舊客戶端(反之亦然)會在brocker客戶端轉換格式時對brocker程式施加額外負擔,儘可能避免這種情況。
20、不要認為在本地台式機上測試brocker代表在實際生產環境中的性能。使用複製因數1對分區的環回介面進行測試是與大多數生產環境完全不同的拓撲。通過環回可以忽略網路延遲,並且在不涉及複製時,接收leader確認所需的時間可能會有很大差異。