😊你好,我是小航,一個正在變禿、變強的文藝傾年。
🔔本專欄《八股消消樂》旨在記錄個人所背的八股文,包括Java/Go開發、Vue開發、系統架構、大模型開發、具身智能、機器學習、深度學習、力扣算法
等相關知識點,期待與你一同探索、學習、進步,一起卷起來叭!
目錄
- 題目
- 答案
- 優化生產者
- 優化acks
- 優化批次
- 啟用壓縮
- 優化broker
- 優化 swap
- 優化網絡讀寫緩沖區
- 優化磁盤 IO
- 優化主從同步
- 優化JVM
題目
💬技術棧:RocketMQ、Kafka、RabbitMQ
🔍簡歷內容:為解決xx業務高峰期響應時間長、客戶端超時問題,通過優化acks、批次并將壓縮算法從 Snappy 更換為 LZ4,提高生產者發送效率。經排查,kafka 集群觸發了 full GC 之后,停頓時間就會很長,導致 Kafka 吞吐量顯著下降,有時候還會導致 Kafka 認為主分區已經崩潰觸發主從選舉,通過調大 JVM 的堆,并且在堆很大的情況下,啟用 G1 垃圾回收器解決了問題。
🚩面試問:Kafka 還有一些參數也對性能有影響,你能介紹一下你是如何優化的嗎?
💡建議暫停思考10s,你有答案了嘛?如果你有不同題解,歡迎評論區留言、打卡。
答案
簡歷準備:
- 你維護的業務在使用消息隊列的時候,后面優化措施中提到的
參數取值
都是多少? - 你們公司
消息隊列的各個參數有沒有被調過
?為什么調? - 你
是否遇到過和消息隊列有關的 Bug
?如果有,那么怎么解決的? - 你
維護的業務使用消息隊列時的 QPS 是多少
?
場景準備:高并發的消息隊列使用場景,要求高效發送、高效消費,不然就會有問題,比如說出現消息積壓或者生產者阻塞
的問題。
整理思路:從消息隊列的生產者、broker 和消費者這三方出發。
優化生產者
優化acks
場景:有一個系統在一個高并發場景下會發送消息到 Kafka,結果發現這個接口在業務高峰的時候響應時間很長,客戶端經常遇到超時的問題
。
排查后:寫這段代碼的人直接復制了已有的發送消息代碼
,而原本人家的業務追求的是消息不丟,所以 acks 設置成了 all
。實際上這個業務并沒有那么嚴格的消息不丟的要求,完全可以把 acks 設置為 0。
效果:這么一調整,整個接口的響應時間就顯著下降了
,客戶端那邊也很少再出現超時的問題。
不過
追求消息不丟失的業務場景
就不能把 acks 設置為 0 或者 1,這時候就只能考慮別的優化手段,比如說優化批次。
優化批次
場景:生產者發送消息的性能問題。
排查后:因為發送性能太差,導致發送緩沖池已經滿了
,阻塞了發送者。這個時候我們注意到其實發送速率還沒有達到 broker 的閾值
,也就是說,broker 其實是處理得過來的。
解決方案:在這種情況下,最直接的做法就是加快發送速率
,也就是調大 batch.size 參數
,從原本的 100 調到了 500,就沒有再出現過阻塞發送者的情況了。
當然,批次也不是說越大越好。
原因:批次大了的話,生產者這邊丟失數據的可能性就比較大
。而且批次大小到了一個地步之后,性能瓶頸就變成了 broker 處理不過來了
,再調大批次大小是沒有用的。最好的策略,還是通過壓測來確定合適的批次大小
。
發送者被阻塞也可能是因為緩沖池太小
。
解決方案:調大緩沖池
。
原因:topic、分區太多,每一個分區都有一塊緩沖池裝著批量消息,導致緩沖池空閑緩沖區不足,這一類不是因為發送速率的問題導致的阻塞,就可以通過調大緩沖池來解決。
所以發送者阻塞要仔細分析,如果是發送速率的問題
,那么調大發送緩沖區是治標不治本的。如果發送速率沒什么問題,確實就是因為緩沖池太小引起的
,就可以調大緩沖池。如果現實中,也比較難區別這兩種情況,就可以考慮先調大批次試試,再調整緩沖池。
啟用壓縮
場景:Kafka 默認是不啟用壓縮的,為了進一步提高 Kafka 的吞吐量,我也開啟了 Kafka 的壓縮功能,使用了 LZ4 壓縮算法
。【為了進一步提高 Kafka 的吞吐量,我將壓縮算法從 Snappy 換到了 LZ4
。】
一定要做性能測試
優化broker
優化 swap
Kafka 是一個非常依賴內存的應用,所以可以調小 vm.swappniess 參數來優化內存。
為了優化 Kafka 的性能,可以調小 vm.swappiness
。比如說調整到 10,這樣就可以充分利用內存
;也可以調整到 1,這個值在一些 linux 版本上是指進行最少的交換,但是不禁用交換
。目前我們公司用的就是 10。
為什么不直接禁用 swap 呢?
物理內存總是有限的,所以直接禁用的話容易遇到內存不足的問題。我們只是要盡可能優化內存,如果物理內存真的不夠,那么使用交換區也比系統不可用好
。
優化網絡讀寫緩沖區
Kafka 也是一個網絡 IO 頻繁的應用
,所以調整網絡有關的讀寫緩沖區,效果也會更好。對應的參數有6個。
- net.core.rmem_default 和 net.core.wmem_default:Socket 默認讀寫緩沖區大小。
- net.core.rmem_max 和 net.core.wmem_max:Socket 最大讀寫緩沖區。
- net.ipv4.tcp_wmem 和 net.ipv4.tcp_rmem:TCP 讀寫緩沖區。它們的值由空格分隔的最小值、默認值、最大值組成。可以考慮調整為 4KB、64KB 和 2MB。
回答模板:調大讀寫緩沖區
。Scoket 默認讀寫緩沖區可以考慮調整到 128KB
;Socket 最大讀寫緩沖區可以考慮調整到 2MB
,TCP 的讀寫緩沖區最小值、默認值和最大值可以設置為 4KB、64KB 和 2MB
。不過這些值究竟多大,還是要根據 broker 的硬件資源來確定。
優化磁盤 IO
Kafka 也是一個磁盤 IO 密集的應用,所以可以從兩個方向優化磁盤 IO。
(1)使用 XFS 作為文件系統
,它要比 EXT4 更加適合 Kafka。相比于 EXT4,XFS 性能更好。在同等情況下,使用 XFS 的 Kafka 要比 EXT4 性能高 5% 左右
。XFS還有別的優點,例如擴展性更好,支持更多、更大的文件。
(2)禁用 Kafka 用不上的 atime 功能
。
優化主從同步
總結: 都調大,它們的效果,就是為了讓從分區一批次同步盡可能多的數據
。
從分區和主分區數據同步的過程受到了幾個參數的影響。
- num.replica.fetchers:
從分區拉取數據的線程數量,默認是1
。你可以考慮設置成 3。 - replica.fetch.min.bytes:可以通過調大這個參數來
避免小批量同步數據
。 - replica.fetch.max.bytes:這個可以調大,比如說調整到 5m,但是不要小于 message.max.byte,也就是不要小于消息的最大長度。
- replica.fetch.wait.max.ms:如果主分區沒有數據或者數據不夠從分區的最大等待時間,可以考慮同步調大這個值和 replica.fetch.max.bytes。
首先調整從分區的同步數據線程數量
,比如說調整到 3,這樣可以加快同步速率,但是也會給主分區和網絡帶寬帶來壓力。
其次是調整同步批次的最小和最大字節數量
,越大則吞吐量越高,所以都盡量調大。
最后也可以調整從分區的等待時間
,在一批次中同步盡可能多的數據。
不過調大到一定地步之后,瓶頸就變成了從分區來不及處理。或者調大到超過了消息的并發量,那么也沒意義了。
Kafka 這種機制可以看作是典型的批量拉數據模型
。在這個模型里面,要著重考慮的就是多久拉一次,沒有怎么辦,一次拉多
少?在實現這種模型的時候,讓用戶根據自己的需要來設定參數是一個比較好的實踐。
優化JVM
Kafka 是運行在 JVM 上
的,所以理論上來說任何優化 Java 性能的措施,對 Kafka 也一樣有效果。
優化 JVM:
(1)首先就是考慮優化 GC,即優化垃圾回收
。而優化 GC 最重要的就是避免 full GC
。full GC 是指整個應用都停下來等待 GC 完成
。它會帶來兩方面影響。一方面是發送者如果設置 acks 為 1 或者 all,都會被阻塞,Kafka 吞吐量下降
。
(2)如果 full GC 時間太長
,那么主分區可能會被認為已經崩潰了,Kafka 會重新選擇主分區
;而如果是從分區,那么它會被挪出 ISR
,進一步影響 acks 設置為 all 的發送者
。
基本的思路就是調大 JVM 的堆,并且在堆很大的情況下,啟用 G1 垃圾回收器
。
之前我們的 Kafka 集群還出過 GC 引發的性能問題
。我們有一個 Kafka 的堆內存很大,有 8G,但是垃圾回收器還是用的 CMS
。觸發了 full GC 之后,停頓時間就會很長,導致 Kafka 吞吐量顯著下降
,并且有時候還會導致 Kafka 認為主分區已經崩潰,觸發主從選舉
。
優化思路:
(1)一個是考慮優化 CMS 本身
,比如說增大老年代,但是這個治標不治本,可以緩解問題,但是不能根治問題。
(2)直接切換到 G1 回收器
。G1 回收器果然表現得非常好,垃圾回收頻率和停頓時間都下降了。
往期精彩專欄內容,歡迎訂閱:
🔗【八股消消樂】20250711:淺嘗Kafka性能優化
🔗【八股消消樂】20250630:消息隊列優化—重復消費
🔗【八股消消樂】20250629:消息隊列優化—消息丟失
🔗【八股消消樂】20250627:消息隊列優化—消息積壓
🔗【八股消消樂】20250625:消息隊列優化—消息有序
🔗【八股消消樂】20250624:消息隊列優化—延遲消息
🔗【八股消消樂】20250623:消息隊列優化—系統架構設計
🔗【八股消消樂】20250622:Elasticsearch查詢優化
🔗【八股消消樂】20250620:Elasticsearch優化—檢索Labubu
🔗【八股消消樂】20250619:構建微服務架構體系—保證服務高可用
🔗【八股消消樂】20250615:構建微服務架構體系—鏈路超時控制
🔗【八股消消樂】20250614:構建微服務架構體系—實現制作庫與線上庫分離
🔗【八股消消樂】20250612:構建微服務架構體系—限流算法優化
🔗【八股消消樂】20250611:構建微服務架構體系—降級策略全總結
🔗【八股消消樂】20250610:構建微服務架構體系—熔斷恢復抖動優化
🔗【八股消消樂】20250609:構建微服務架構體系—負載均衡算法如何優化
🔗【八股消消樂】20250608:構建微服務架構體系—服務注冊與發現
🔗【八股消消樂】20250607:MySQL存儲引擎InnoDB知識點匯總
🔗【八股消消樂】20250606:MySQL參數優化大匯總
🔗【八股消消樂】20250605:端午節產生的消費數據,如何分表分庫?
🔗【八股消消樂】20250604:如何解決SQL線上死鎖事故
🔗【八股消消樂】20250603:索引失效與優化方法總結
🔗【八股消消樂】20250512:慢SQL優化手段總結
🔗【八股消消樂】20250511:項目中如何排查內存持續上升問題
🔗【八股消消樂】20250510:項目中如何優化JVM內存分配?
🔗【八股消消樂】20250509:你在項目中如何優化垃圾回收機制?
🔗【八股消消樂】20250508:Java編譯優化技術在項目中的應用
🔗【八股消消樂】20250507:你了解JVM內存模型嗎?
🔗【八股消消樂】20250506:你是如何設置線程池大小?
🔗【八股消消樂】20250430:十分鐘帶背Duubo中大廠經典面試題
🔗【八股消消樂】20250429:你是如何在項目場景中選取最優并發容器?
🔗【八股消消樂】20250428:你是項目中如何優化多線程上下文切換?
🔗【八股消消樂】20250427:發送請求有遇到服務不可用嗎?如何解決?
📌 [ 筆者 ] 文藝傾年
📃 [ 更新 ] 2025.7.11
? [ 勘誤 ] /* 暫無 */
📜 [ 聲明 ] 由于作者水平有限,本文有錯誤和不準確之處在所難免,本人也很想知道這些錯誤,懇望讀者批評指正!