Kafka消息體大小設置的一些細節
- 2019 年 10 月 7 日
- 筆記
還記得前幾天有個小夥伴跟我回饋發送消息時提示請求數據過大的異常嗎?經過調整 max.request.size 的大小之後,又報了了如下異常:

查看相關資料後,發現 Broker 端對 Producer 發送過來的消息也有一定的大小限制,這個參數叫 message.max.bytes,這個參數決定了 Broker 能夠接收到的最大消息的大小,它的默認值為 977 KB,而 max.request.size 的值已經設置成 2M 大小了,很顯然已經比 message.max.bytes 大了很多,因此消息大於 997KB 時,就會拋出如上異常。
值得一提的是,主題配置也有一個參數,叫 max.message.bytes,它只針對某個主題生效,可動態配置,可覆蓋全局的 message.max.bytes,好處就是可以針對不同主題去設置 Broker 接收消息的大小,而且不用重啟 Broker。
這還沒完,消費端拉取消息數據的大小也需要更改,這個參數叫 fetch.max.bytes,這個參數決定消費者單次從 Broker 獲取消息的最大位元組數,那麼問題來了,如果該參數值比 max.request.size 小,那麼會導致消費者很可能消費不了比 fetch.max.bytes 大的消息。
所以綜合起來,需要這麼設置:
producer端:max.request.size=5242880(5M)broker:message.max.bytes=6291456(6M)consumer:fetch.max.bytes=7340032(7M) max.request.size < message.max.bytes < fetch.max.bytes
另外補充一點,還記得之前說過的 batch.size 參數的作用嗎,從源碼可看出,Producer 每次發送的消息封裝成 ProducerRecord,然後利用消息累加器 RecordAccumulator 添加到 ProducerBatch 中,由於每次創建 ProducerBatch 都需要分配一個 batch.size 大小的記憶體空間,頻繁創建和關閉會導致性能極大開銷,所以 RecordAccumulator 內部有個 BufferPool,它實現了快取的復用,只不過只針對 batch.size 大小的 BufferByte 進行復用,如果大於 batch.size 的 ProducerBatch,它並不會加入 BufferPool 中,也就不會復用。
之前有個疑問就是:假如 max.request.size 大於 batch.size,那麼該條消息會不會分多個 batch 發送到 broker?
答案顯然是不會,根據上述所說,如果一個 ProducerRecord 就已經超出了 batch.size 的大小,那麼 ProducerBatch 僅包含一個 ProducerRecord,並且該 ProducerBatch 並不會加入到 BufferPool 中。
所以,在 Kafka Producer 調優過程中,根據業務需求,需要特別注意 batch.size 與 max.request.size 之間的大小值的設定,避免記憶體空間頻繁地創建和關閉。