Kafkaのメッセージサイズ上限を上げたのに通らない原因 — 3箇所の制限と設定方法
Kafkaで大きいメッセージを送ろうとして MessageSizeTooLargeException が出たとき、設定を上げる場所はProducer・Broker・Topicの3箇所あります。どれか1つでも漏れると通りません。
何を調べたか
Kafkaでメッセージサイズの上限を上げたのに、まだエラーで弾かれるという状況に遭遇したんですよね。Producerの max.request.size を上げたのに MessageSizeTooLargeException が消えない。調べてみたら、メッセージサイズの制限って3箇所に分かれていて、それぞれ独立して判定しているということがわかりました。
どういうことか — 3箇所の制限
メッセージがProducerからBrokerに届いて、Topicに格納されるまでに、3つのゲートを通ります。
flowchart LR
P["Producer<br/>max.request.size<br/>デフォルト: ≒1MB"] -->|送信| B["Broker<br/>message.max.bytes<br/>デフォルト: ≒1MB"]
B -->|書き込み| T["Topic<br/>max.message.bytes<br/>デフォルト: Broker値を継承"]
それぞれの役割はこうなっています。
| ゲート | 設定名 | 役割 | デフォルト |
|---|---|---|---|
| Producer | max.request.size |
送信リクエストの最大サイズ。超えるとProducer側でエラー | ≒1MB |
| Broker | message.max.bytes |
受け付けるメッセージの最大サイズ。超えると拒否 | ≒1MB |
| Topic | max.message.bytes |
Topic単位の上限。Brokerを通ってもここで引っかかる | Broker値を継承 |
これ、3つが互いに参照し合っていないんですよね。Producerが「Brokerの設定は何MBだから送信を止めよう」みたいな判断はしない。
各ゲートが自分の前を通るメッセージのサイズだけを見ています。
なぜこうなっているかというと、責任のレイヤーが違うからです。
flowchart TD
A[アプリケーション層] -->|"max.request.size"| G1[送信側のガードレール]
B[インフラ層] -->|"message.max.bytes"| G2[クラスタのリソース保護]
C[用途別] -->|"max.message.bytes"| G3["Topic単位の制御<br/>(ログ用は小さく、画像用は大きく)"]
分散システムとして各コンポーネントが自律的に判断する設計なので、こうなるのは理にかなっています。
設定方法
大きいメッセージを通したい場合、3箇所(+Consumer)を揃えて変更する必要があります。
# Producer max.request.size=10485760 # 10MB # Broker(server.properties) message.max.bytes=10485760 # 10MB # Topic(topic設定) max.message.bytes=10485760 # 10MB # Consumer max.partition.fetch.bytes=10485760 # 10MB
Topicの設定変更はこうです。
# 既存Topicの設定変更 kafka-configs.sh --bootstrap-server localhost:9092 \ --entity-type topics \ --entity-name my-topic \ --alter \ --add-config max.message.bytes=10485760
Consumer側の max.partition.fetch.bytes は厳密にはメッセージサイズ制限ではなく、1回のfetchで取得するデータの上限です。Kafkaはprogressを保証するため、この値を超える最初のレコードバッチは例外的に返却されるので、読み出し自体は失敗しません。
ただし、fetch効率が落ちてパフォーマンスに影響する可能性があるので、大きいメッセージを扱うなら揃えておくのが安全です。
注意点
ハマりやすいパターンが3つあります。
1つ目は、Producerだけ上げたケース。max.request.size を10MBにしても、Brokerの message.max.bytes がデフォルトの1MBのままだと、送信はできるけどBrokerで拒否されます。
2つ目は、BrokerとProducerは上げたけどTopicを忘れたケース。Topic作成時にデフォルト以外の max.message.bytes が設定されていると、そこで引っかかります。
Topic側の設定は必ずしもBrokerのデフォルトを継承するとは限らないので注意が必要です。
3つ目は、Producer・Broker・Topicは全部上げたけどConsumer側を忘れたケース。max.partition.fetch.bytes(デフォルト≒1MB)が小さいままだと、メッセージの保存はできていてもfetch効率が落ちてスループットが低下する可能性があります。
読み出し自体は失敗しませんが、パフォーマンスに影響します。
まとめ
Kafkaのメッセージサイズ制限は3つの独立したゲートで構成されています。1箇所だけ変更して「通った」と思っていると、別のTopicや別のConsumerで地雷を踏むことになります。
変更するときは「この設定を参照しているコンポーネントは全部どれか」を先に洗い出してから揃えて変更するのが安全です。