- 主要目標: 高吞吐量 、 低延時
- 吞吐量
- 即 TPS ,指的是Broker端進程或Client端應用程式每秒能處理的 位元組數 或 消息數
- 延時 ,可以有兩種理解
- 從 Producer發送消息 到 Broker持久化 完成之間的時間間隔
- 端到端的延時 ,即從 Producer發送消息 到 Consumer成功消費該消息 的總時長
優化漏斗
優化漏斗是調優過程中的分層漏斗,層級越靠上,調優的效果越明顯
作業系統層
- mount -o noatime
- 在 掛載 文件系統時禁用 atime (Access Time)更新,記錄的是 文件最後被訪問的時間
- 記錄 atime 需要作業系統訪問 inode 資源,禁用atime可以 避免inode訪問時間的寫入操作
- 文件系統選擇 ext4 、 XFS 、 ZFS
- 將 swappiness 設置成一個 很小的值 (1~10,默認是60),防止Linux的 OOM Killer 開啟 隨機殺掉 進程
- swappiness=0 ,並不會禁止對swap的使用,只是 最大限度 地降低使用swap的可能性
- 因為一旦設置為0,當物理內存耗盡時,作業系統會觸發 OOM Killer
- OOM Killer會 隨機 挑選一個進程然後kill掉, 不會給出任何預警
- swappiness=N,表示內存使用 (100-N)% 時,開始使用Swap
- ulimit -n 設置大一點,否則可能會出現 Too Many File Open 錯誤
- vm.max_map_count 也設置大一點(如655360,默認值65530)
- 在一個主題數超多的機器上,可能會碰到 OutOfMemoryError:Map failed 錯誤
- 頁緩存大小
- 給Kafka預留的頁緩存至少也要容納一個 日誌段 的大小( log.segment.bytes ,默認值為 1GB )
- 消費者程序在 消費 時能 直接命中 頁緩存,從而避免 昂貴的物理磁碟IO操作
JVM層
- 堆大小,經驗值為 6~8GB
- 如果需要精確調整,關注 Full GC後堆上存活對象的總大小 ,然後將堆大小設置為該值的 1.5~2倍
- jmap -histo:live
可以人為觸發Full GC
- 選擇垃圾收集器
- 推薦使用 G1 ,主要原因是 優化難度比CMS小
- 如果使用G1後,頻繁Full GC,配置 -XX:+PrintAdaptiveSizePolicy ,查看觸發Full GC的原因
- 使用G1的另一個問題是 大對象 ,即 too many humongous allocations
- 大對象一般指的是 至少占用半個Region大小的對象 ,大對象會被直接分配在 大對象區
- 可以適當增大 -XX:+G1HeapRegionSize=N
- 儘量避免Full GC!!
框架層
儘量保持 客戶端 版本和 Broker端 版本 一致 ,否則可能會喪失很多 性能收益 ,如 Zero Copy
應用程式層
- 不要頻繁創建 Producer和Consumer對象實例,構造這些對象的 開銷很大
- 用完及時關閉
- Producer對象和Consumer對象會創建很多物理資源,如Socket連接、ByteBuffer緩衝區,很容易造成 資源泄露
- 合理利用 多線程 來改善性能,Kafka的Java Producer是線程安全的,而Java Consumer不是線程安全的
性能指標調優
TPS != 1000 / Latency(ms) **
- 假設Kafka Producer以2ms的延時來發送消息,如果 每次都只發送一條消息 ,那麼 TPS=500
- 但如果Producer不是每次只發送一條消息,而是在發送前 等待一段時間 ,然後 統一發送一批消息
- 如Producer每次發送前等待8ms,總共緩存了1000條消息,總延時累加到了10ms,但 TPS=100,000
- 雖然延時增加了4倍,但TPS卻增加了200倍,這就是 批次化 或 微批次化 的優勢
- 用戶一般願意用 較小的延時增加 的代價,去換取 TPS的顯著提升 ,Kafka Producer就是採用了這樣的思路
- 基於的前提: 內存操作 (幾百納秒)和 網絡IO操作 (毫秒甚至秒級)的時間量級不同
調優吞吐量
- Broker端
- 適當增加 num.replica.fetchers (默認值為1),但 不用超過CPU核數
- 生產環境中,配置了 acks=all 的Producer程序吞吐量被拖累的首要因素,就是 副本同步性能
- 調優GC參數避免頻繁Full GC
- Producer端
- 適當增加 batch.size (默認值為16KB,可以增加到 512KB 或 1MB )
- 增加消息批次的 大小
- 適當增加 linger.ms (默認值為0,可以增加到10~100)
- 增加消息批次的 緩存時間
- 修改 compression.type (默認值為none,可以修改為 lz4 或 zstd ,適配最好)
- 修改 acks (默認值為1,可以修改為 0 或 1 )
- 優化的目標是吞吐量,不要開啟 acks=all (引入的 副本同步時間 通常是吞吐量的瓶頸)
- 修改 retries (修改為 0 )
- 優化的目標是吞吐量,不要開啟重試
- 如果多線程共享同一個Producer,增加 buffer.memory (默認為 32MB )
- TimeoutException:Failed to allocate memory within the configured max blocking time
- Consumer端
- 採用多Consumer進程或線程 同時消費 數據
- 適當增加 fetch.min.bytes (默認值為1Byte,可以修改為 1KB 或更大)
end:如果你覺得本文對你有幫助的話,記得關注點贊轉發,你的支持就是我更新動力。