コレクターのバッチプロセッサーの非推奨化
OpenTelemetry コレクターにおけるバッチ処理とは、エクスポーターにとって適切なサイズのリクエストを生成するプロセスです。 圧縮の効率を高め、ラウンドトリップのレイテンシを償却するのに十分な大きさでありながら、制限を超えない大きさにします。 バッチ処理は、コレクターの運用におけるパフォーマンス、信頼性、コストに関わる複数の重要な関心事を統合します。
OpenTelemetry が 2019 年に始まって以来、コレクターには batch プロセッサーコンポーネントが含まれてきました。
このコンポーネントは、下流のコンシューマーに送信する前にリクエストの結合と分割を行い、インバウンドおよびアウトバウンドのタイムアウトを監視し、パイプラインが満杯のときに新しいリクエストを保留する役割を担っています。
TL;DR
batch プロセッサーを非推奨化します。
バッチ処理はエクスポーターで直接サポートされるようになりました。
これはエクスポーターレベルバッチ処理と呼ばれ、新しい queue_batch プロセッサーが元のプロセッサーコンポーネントを置き換えます。
キューとバッチの動作を統合することで、以下に説明する多くの改善がもたらされます。
エクスポーターレベルバッチ処理は、リリース v0.171.0(2027 年 2 月予定)でほとんどのエクスポーターにおいてデフォルトで有効になります。
ただし、新しいデフォルトを待つだけでは十分ではありません。
設定に batch プロセッサーが含まれている場合、プロセッサー自体が削除される前にパイプラインから取り除く必要があります。
以下に示すように設定を変更することで、今すぐエクスポーターレベルバッチ処理をオプトインできます。
変更前:
receivers:
host_metrics:
scrapers:
cpu: {}
processors:
batch:
exporters:
otlp:
...
sending_queue:
enabled: true
# バッチは有効化されていない
service:
pipelines:
metrics:
receivers: [host_metrics]
processors: [batch]
exporters: [otlp]
変更後:
receivers:
host_metrics:
scrapers:
cpu: {}
exporters:
otlp:
...
sending_queue:
enabled: true
batch:
enabled: true
service:
pipelines:
metrics:
receivers: [host_metrics]
exporters: [otlp]
batch プロセッサーのコアリポジトリおよびディストリビューションからの削除は、リリース v0.177.0(2027 年 5 月)に予定されています。
ほとんどの場合、ユーザーはキューの後にバッチ処理を行うエクスポーターレベルバッチ処理を選択するでしょう。
ご安心ください、プロセッサーでのバッチ処理は、代替となる queue_batch プロセッサーを使用すれば引き続き可能です。
なぜ batch プロセッサーを置き換えるのか
コレクターのプロセッサーは、OpenTelemetry データのインメモリ表現を消費し、生成します。
そのため、batch プロセッサーはアイテム数、つまり個々のログレコード、メトリクスデータポイント、トレーススパンの数で設定されます。
デフォルト設定は以下の通りです。
processors:
batch: # 非推奨のプロセッサー
timeout: 200ms # 最大遅延
send_batch_size: 8192 # 最小アイテム数
# send_batch_max_size: # 最大アイテム数は無制限
基本設定では、batch プロセッサーは最大アイテム数を制限しません。
両方の制限を設定すると、バッチ処理ロジックはリクエストの分割や結合を行います。
たとえば、以下のようになります。
processors:
batch: # 非推奨のプロセッサー
timeout: 200ms # 最大遅延
send_batch_size: 1000 # 最小アイテム数
send_batch_max_size: 5000 # 最大アイテム数
2021 年までに、基本的な動作とデフォルト設定は事実上安定していました。
その頃までに、batch プロセッサーのユーザーは設計上の 3 つの大きな制限を特定し、以下を求めていました。
- サイズ制限の制御:バイト単位での制限設定
- 並行性の制御:同時リクエスト数の制限設定
- バックプレッシャーとエラー伝搬の制御
batch プロセッサーには小さなインメモリキューが含まれています。
プロデューサー側は Go のチャネルへブロッキング書き込みを行い、以下のように呼び出し元に成功を返します。
batch.pending <- request
return nil
これは標準的な動作です。
問題は、batch プロセッサーの組み込みキューが、並行性、バックプレッシャー、エラー伝搬に対する設定可能なサポートを持たないことであり、キューを永続化するためのストレージエクステンションもサポートしていません。
エクスポーターレベルのキューとバッチの統合動作
エクスポーターレベルバッチ処理は、共通の sending_queue 動作を使用するエクスポーターで一般提供されています。
キューイングとバッチ処理の動作は統合されています。
- リクエストはまずキューへの入力を試みます。 キューには容量制限があります。 キューが満杯の場合、即座に失敗するか、呼び出し元をブロックできます。 通常、キューは受け入れ時に呼び出し元に成功を返します。 ただし、レスポンスを待つオプションもあります。
- 複数のコンシューマーがキューからリクエストを同時にプルします。 バッチ処理が有効な場合、サイズが小さすぎるリクエストや大きすぎるリクエストは結合・分割されてからコンシューマーに渡されますが、適切なサイズのリクエストはバッチャーをそのまま通過します。
結合されたキューとバッチのロジックを通過したリクエストは、エクスポーターに設定されたタイムアウトおよびリトライ設定に渡されます。 デフォルト設定は以下の通りです。
exporters:
<exporter>:
sending_queue: # エクスポーターの queue_batch 動作
queue_size: 1000 # サイズ制限
sizer: requests # サイズはリクエスト数
block_on_overflow: false # バックプレッシャーなし
wait_for_result: false # エラー伝搬なし
num_consumers: 10 # 並行数の制限
batch:
enabled: false # バッチ処理はデフォルト無効
sizer: items # テレメトリーのアイテム数で計測
min_size: 8192 # 最小アイテム数
flush_timeout: 200ms # 最大遅延
詳細は以下の通りです。
num_consumers:同時エクスポート数を決定しますqueue_sizeとsizer:保留中のデータの上限を決定しますblock_on_overflow:false はフェイルファスト、true はデッドラインまで待機を意味しますwait_for_result:false は確認応答を待たない、true は成功または失敗を待つことを意味しますstorage:永続キューのためのオプションのストレージエクステンション
デフォルトでは、キューはブロックせず、結果も待たないため、呼び出し元に即座に成功または失敗を返します。
エクスポーターレベルバッチ処理はキューイング動作が安定した後に導入されたため、バッチ処理はデフォルトで無効のままです。
エクスポーターレベルバッチ処理を有効にすると、sizer、min_size、flush_timeout のデフォルト値は元の batch プロセッサーと一致します。
今日のほとんどのエクスポーターでは、デフォルトの batch プロセッサー設定からの移行は、パイプラインからプロセッサーを削除してエクスポーターレベルバッチ処理を有効にするだけで行えます。
これにより、上記のデフォルト設定でバッチ処理が有効になります。
exporters:
<exporter>:
sending_queue:
batch:
enabled: true
詳細は以下の通りです。
enabled:エクスポーターレベルバッチ処理を有効化sizer:バッチサイズの計測方法:items、bytesmin_size:送信前のバッチの最小サイズmax_size:バッチの最大サイズ(オプション)flush_timeout:送信前の最大遅延partition:以下で詳述
移行後のキュー容量
バッチ処理を sending_queue に移すことは、キューを挟んでバッチ処理を反対側へ移すことでもあります。
一般的な batch プロセッサーのパイプラインでは、エクスポーターの sending_queue は batch プロセッサーの後に配置されます。
既存の batch プロセッサーがパイプラインにある場合、デフォルトサイズのキューはバッチ処理済みのリクエストを最大 1000 個保持するため、既存の設定を変換する際は注意が必要です。
エクスポーターレベルバッチ処理では、バッチ処理はキューの後に行われます。
この場合、キューはパイプラインから到着する個々のリクエスト(通常ははるかに小さいリクエスト)を保持します。
リクエスト数で計測される同じ queue_size: 1000 では、保持できるデータ量がかなり少なくなる可能性があります。
パイプラインから batch を削除すると、キューの保持データ量が減り、オーバーフローにつながる可能性があります。
sending_queue のバッチ処理に移行する際は、バッチ処理前のリクエストを適切な数だけ保持できるように queue_size の引き上げを検討してください。
インメモリキュー(storage エクステンションなし)の場合、理想的には num_consumers を忙しく保つのに十分なデータをキューで保持すべきです。
呼び出し元がブロックするかどうかに応じて、断続的なエクスポート失敗に耐えるための追加のキュースペースも確保すべきです。
queue_size を items または bytes で計測する場合、リクエストサイズの影響は小さくなります。
たとえば、以下のキューは最大 100,000 アイテムを格納します。
バッチあたり最小 5,000 アイテムの場合、10 個のコンシューマーが 50,000 以上のアイテムを同時に送信できます。
キューにはさらに 50,000 アイテムが入る余地があり、ブロックまたはリクエスト失敗の前に送信完了を待ちます。
exporters:
<exporter>:
sending_queue:
sizer: items # キューをリクエスト数ではなくアイテム数で計測
queue_size: 100_000 # SDK サイズのバッチで約 50〜100 個分
num_consumers: 10 # 10 ワーカーがバッチをエクスポート
batch:
enabled: true
sizer: items # エクスポートサイズをアイテム数で計測
min_size: 5_000 # 最小エクスポートサイズ
アイテム数またはバイト数でサイズ管理されたキューは、sending_queue のメモリコストを明示的にします。
一方、リクエスト数でサイズ管理されたキューは、大きいリクエストも小さいリクエストも保持でき、メモリ使用量が変動します。
バックエンドの制限もバイト単位の場合、バイト数での計測が役立ちます。
max_size を使用して、すべてのリクエストを制限内に収めます。
exporters:
<exporter>:
sending_queue:
sizer: bytes # キューをバイト数で計測
queue_size: 100_000_000 # 100 MB のバッファ
batch:
enabled: true
min_size: 1_000_000 # 1 MB のバッチ
max_size: 10_000_000 # バックエンドのメッセージ制限を超えないようにする
items と bytes のサイザーはどちらも requests より CPU コストが高く、bytes はエンコードされたサイズを計算するため最もコストがかかります。
切り替え後は otelcol_exporter_queue_size を監視し、otelcol_exporter_queue_capacity と比較してください。
その他の機能
batch プロセッサーと同様に、sending_queue メカニズムはメタデータによるパーティショニングをサポートしており、選択されたヘッダーの異なる組み合わせが独立したバッチを形成します。
exporters:
<exporter>:
sending_queue:
<...>
batch:
enabled: true
<...>
partition:
enabled: true
metadata_keys: # リクエストヘッダーのリスト
- x-auth-token
cache_size: 100 # 最大 100 の同時バッチ
idle_timeout: 100s # 100 秒後にメモリから削除
コレクターのストレージエクステンションは、すべての sending_queue 設定で利用可能であり、永続キューの設定をサポートしています。
たとえば、以下のようになります。
exporters:
<exporter>:
sending_queue:
<...>
storage: file_storage/persistent
extensions:
file_storage/persistent: # ファイルベースのストレージ
directory: <...> # ディレクトリパス
<...>
Queue/Batch プロセッサー
ほとんどの場合、エクスポーターで sending_queue を設定するのがユーザーにとって最良の選択肢ですが、プロセッサーでのバッチ処理が適切なケースもいくつかあります。
たとえば、以下のような場合です。
- 大きなバッチで性能が向上する集約プロセッサーの前段
- メモリを節約できるシナリオで、複数のエクスポーターがプロセッサーを共有する場合
このようなケースに対応するため、batch プロセッサーの代替として新しい queue_batch プロセッサーを導入しました。
sending_queue と同じ設定構造を使用し、デフォルトのアイテム閾値とフラッシュタイムアウトは元の batch プロセッサーと一致します。
processors:
queue_batch: # プロセッサーのキューとバッチ
num_consumers: 1 # 単一の同時エクスポート
sizer: requests # リクエスト数で制限
queue_size: 10 # キュー内の上限は 10
block_on_overflow: true # キューが満杯のときブロック
wait_for_result: false # キュー入力時に成功を返す
batch:
enabled: true # バッチ処理有効
sizer: items # アイテム数で計測
min_size: 8192
flush_timeout: 200ms
プロセッサーにおけるキューとバッチの統合動作により、ユーザーはバッチ処理、バックプレッシャー、永続ストレージ、エラー伝搬を、プロセッサーでもエクスポーターでも一貫して適用できるようになりました。
2027 年のデフォルトバッチ処理
sending_queue の設定は v0.126.0 前後から安定しており、代替機能は完全に準備ができています。
残りのタスクの一つは、ほとんどのエクスポーターでバッチ処理をデフォルトで有効にすることです。
コレクターのバッチ処理移行計画のフェーズ 2 に入ります。
batch プロセッサーは公式に非推奨となりました。
今後のコレクターリリースで、batch プロセッサーは非推奨の警告を発し始めます。
何もしないユーザーには、計画されたデフォルトの変更が適用されます。
バッチ処理はリリース v0.171.0(2027 年 2 月)でデフォルトで有効になり、batch プロセッサーはリリース v0.177.0(2027 年 5 月)にコアリポジトリおよびディストリビューションから削除される予定です。
それまでの間、ユーザーにはいくつかの即座に利用可能な手段があります。
batchプロセッサーのかわりにエクスポーターのsending_queueを設定する。 ほとんどのエクスポーターはすでにこの機能をサポートしています。 自分で設定を行えば、デフォルトの変更の影響を受けません。batchプロセッサーのかわりにqueue_batchプロセッサーを使用する。
バッチ処理がデフォルトで有効になる前に、いくつかの緩和策を今日から利用できます。
pkg.exporterhelper.queueBatchEnabledフィーチャーフラグにより、バッチ処理がデフォルトで有効な状態でテストできます。- コレクターのパイプラインセットアップは、パイプラインに
batchプロセッサーとバッチ処理が有効なsending_queueの両方がある場合を検出しようとします。 この場合、警告が発せられ、batchプロセッサーを単純に削除できます。
コンポーネント開発者向け
コレクターの mdatagen コマンドは、コンポーネントの metadata.yaml で sending_queue の設定を宣言できます。
これにより、sending_queue がデフォルトの動作を取るか、特定のオーバーライドを持つか、完全に省略されるかを指定できます。
謝辞
キューイングとバッチ処理のコードベースには、初期のイシューから仕上げの段階まで、多くのコントリビューターがいました。
queue_batch のリード著者は Bogdan Drutu と Dmitry Anoshin であり、パーティショニングサポートは Sindy Li によるものです。
以下をはじめとする多くのコントリビューターに感謝します。 Adii、 Aditya Amol Kuchekar、 Alan Lee、 Alex Boten、 Andrew Gizas、 Andrew Wilkins、 Andrzej Stencel、 Anitha Vadla、 Antoine Toulme、 Chethan、 Damien Mathieu、 Evan Bradley、 Gergely Madarasz、 Israel Blancas、 Jade Guiton、 Jan Korona、 Joshua MacDonald、 Matthieu Morel、 Mike Terhar、 Pablo Baeyens、 Paulo Dias、 Ravishankar Gnanaprakasam、 Roger Coll、 Semih Serhat Karakaya、 simpleqt、 Tyler Helmuth、 Vengal Rao、 Vibhanshu Singh、 Vihas Makwana、 Vinicius Azevedo、 Vishal Raj、 Yang Song、 Yiquan Zhou。