LASSIC Media らしくメディア
バックプレッシャーとは|処理の詰まりを防ぐ制御
データを送り出す仕組みと、受け取って処理する仕組みの間には、速度の差がしばしば生じます。取り込みのペースに処理が追いつかないと、いったんためておく領域(バッファ)が膨らみ続け、確保していたメモリを使い切ってしまうのです。行き着く先は、処理そのものが止まる事態でしょう。処理を止めずに動かし続けるには、速い側から遅い側への流れを、どこかで意図的に調整する仕組みが要ります。
この記事で扱うのは、送り出す側(生産者)と受け取る側(消費者)の速度差によってバッファがあふれる問題と、その流量調整の仕組みです。外部から届く流入自体に上限を設ける仕組み(レートリミット)や、データを一時的に貯めておく仕組み(メッセージキュー)そのものの解説は、別記事に譲ります。発注担当者やプロジェクトマネージャーの方に向けて、開発会社とのレビューで押さえておきたい勘所を整理します。
この記事のポイント
- バックプレッシャーは、送り手が受け手の処理速度を超えて流し込むときに、送出量を抑えて調整する仕組みです。
- ストリーム処理やデータ取り込みなど、流れの速さがそろわない場面で起きやすく、放置するとメモリ枯渇や処理停止を招きます。
- あふれたときにどうふるまうか(緩める・間引く・一時退避・破棄)を、発注の段階で合意しておくことが欠かせません。
バックプレッシャーとは、生産者と消費者の速度差が生む詰まり
バックプレッシャーとは、データを送り出す側の速度が受け取って処理する側の速度を上回り、あふれそうになったときに、送り手へ流量を緩めるよう伝えて全体の流れを調整する仕組みです。
送り出す側を生産者、受け取って処理する側を消費者と呼びます。ネットワーク越しに届くイベントや、複数の入力元から集まるログなど、外部の都合で流入量が変わる場面は少なくありません。生産者の方が速いケースは、むしろ日常的といえるでしょう。
消費者が処理しきれない分は、いったんバッファにためておくのが一般的な対処です。ただしバッファの大きさに上限を設けずにいると、詰まりが続くほど中身が膨らみ続けます。確保していたメモリを使い切り、システム全体が止まる引き金にもなりかねません。
消費者側の処理能力を増やせば解決する、と考えたくなりますが、話はそう単純ではありません。処理能力を増やすにも準備の時間がかかりますし、瞬間的な流入の山にあわせて常に余分な能力を確保しておくのは、費用の面でも見合わないでしょう。だからこそ、あふれそうなときに流れそのものを調整する仕組みが要るのです。
バックプレッシャーという言葉自体は、配管を流れる液体や気体が逆向きの圧力を受ける現象に由来します。ソフトウェアの世界ではこの比喩を借り、受け手から送り手へ「抑えて」という信号が逆向きに伝わるようすを表しているのです。
バックプレッシャーが無い設計では、あふれた分を無条件に受け止め続けるか、逆に問答無用でエラーを返すか、両極端になりがちです。あいだを取り、送り手のペースを段階的に落としながら処理を続けられる点に、この仕組みの値打ちがあるといえるでしょう。
起きやすい場面はストリーム処理・非同期取り込み・ログ集約
バックプレッシャーが表面化するのは、流れの速さがそろいにくい処理の連なりです。代表的な場面を整理します。
- ストリーム処理:センサーの計測値や利用者の行動ログを、リアルタイムに集計・分析する処理です。
- 非同期のデータ取り込み:外部APIやIoT機器から届くイベントを、順次受け付ける窓口です。
- キュー連携:複数のサービス間でメッセージを橋渡しする経路で、送り手と受け手の処理速度が異なる場合に生じます。
- ログ集約:複数のサーバから同時に送られてくるログを、一か所にまとめて保管する仕組みです。
ストリーム処理では、瞬間的なアクセスの急増や、複数のセンサーが同時にデータを送ってくる場面で、処理側の集計が追いつかなくなることがあります。非同期のデータ取り込みでは、外部サービス側の仕様変更やリトライの重なりで、想定を超える量のイベントが一気に届く場合もあるでしょう。
キュー連携では、受け手側のサービスが一時的に遅くなったときに、送り手からの送信だけが続くと、経路の途中にデータが積み上がっていきます。ログ集約では、障害の発生時にエラーログが一斉に増え、平常時の何倍もの量が短時間に押し寄せることもあるのです。
これらの場面はいずれも、システム間の連携が広がるほど頻度が増えていく傾向にあります。連携先が増えるほどピーク時の流入が読みにくくなり、受け手側の設計だけでは吸収しきれない場面が出てくるためです。
たとえば工場設備のIoTセンサーからデータを集める仕組みを考えてみましょう。複数の生産ラインが同時に稼働するタイミングでは、平常時とは桁違いの量の計測値が一斉に届くケースもあるでしょう。受け手側の処理能力を固定的に見積もっていると、稼働状況が変わるたびに詰まりが起きかねません。
これらに共通するのは、流入元の勢いを受け手側だけではコントロールしきれない点です。アクセスの集中や、複数拠点からの同時送信が重なると、平常時には表に出なかった速度差が急に顕在化します。キューを使う経路の場合、キュー自体の設計や選び方は別の論点になるため、本記事ではあくまで流入と処理の速度差に絞って触れます。
緩める・間引く・退避・破棄 — あふれ時の4方式
仕組みの中心にあるのは、受け手が「これだけなら受け取れる」と要求量を伝える、需要ベースのやり取りです。この考え方はプル型(受け手が要求してはじめてデータが流れる方式)と呼ばれます。Reactive Streamsという仕様には、受け手が要求量を伝える手順が定義されているのです。
具体的には、受け手が「次はn件まで受け取れる」と伝え、送り手はその範囲でだけデータを送り出す、というやり取りをくり返します。受け手が次の要求を出すまで、送り手は待つ形になるのです。仕様の中では、送り手が伝えられた数を超えて送ってはならない、という取り決めも明記されています。
こうした仕組みでは、需要のやり取りに加えてバッファと閾値を組み合わせるのが一般的です。バッファの残り容量があらかじめ決めた閾値を下回ると、あふれが近いと判断し、送り手側へ抑制の合図を出す設計になります。あふれそうになったときの具体的なふるまいには、いくつかの方式があるのです。
受け手が明示的に要求量を伝えるプル型とは別に、バッファの残量があらかじめ決めた上限に近づいた段階で送り手へ通知する、しきい値ベースの伝え方を採る実装もあります。呼び方は実装によって異なりますが、狙いはどちらも同じで、あふれる前に送り手の勢いを落とすことにあるのです。
| 方式 | 特徴 | 留意点 |
|---|---|---|
| プル型(要求ベース) | 受け手が要求した数だけ、送り手が送り出す。 要求を出していない分は送られてこない。 |
要求のやり取りが増える分、往復の手間が生じる。 遅延が大きい経路では反応が遅れることもある。 |
| しきい値型(通知ベース) | バッファの残量が上限に近づいたら、送り手へ通知する。 通知が届くまで、送り手はペースを変えない。 |
しきい値の設定しだいで、反応の早さが変わる。 低すぎると頻繁に発動し、高すぎるとあふれてから気づく。 |
実装ではプル型を基本にしつつ、しきい値による通知を組み合わせる例も見られます。あふれそうになったときの具体的なふるまいには、次の4つの方針が挙げられるでしょう。
| 方針 | 挙動 | 向く場面 |
|---|---|---|
| 送信を緩める(スロットリング) | 受け手の要求量に合わせて送出のペースを落とす。 急に流入が増えても、受け手の処理能力を超えない範囲に収まる。 |
データを一件も失いたくない場合。 多少の遅れより、欠落を避けたいときに向く。 |
| 間引く(サンプリング) | 一定間隔で間引き、代表的な値だけを送る。 残りのデータは処理せずに読み捨てる。 |
全件の精度より傾向の把握を優先する場合。 センサー値の監視など、直近の傾向が分かれば足りる用途に向く。 |
| 一時退避(バッファリング) | あふれた分をディスクや退避先へ一時的に逃がす。 落ち着いてから、あらためて取り込み直す想定である。 |
短時間のピークが想定される場合。 退避先の容量や、取り込み直す仕組みもあわせて用意しておく必要がある。 |
| 破棄(ドロップ) | 受け取りきれない分を切り捨てる。 最新の値だけを残す方式もある。 |
古いデータの値打ちが薄い場合。 件数より最新の状態を優先したい用途に向く。 |
送信を緩める方式は、データを失わない代わりに、送り手側の処理も遅くなる影響を受け入れる必要があります。間引く方式や一時退避、破棄は、送り手側の速度を保ったまま受け手側の負荷を抑えられる一方、何らかの形でデータの完全性を犠牲にする判断が伴うでしょう。どの方式が向くかは、失って困るデータかどうかで変わってきます。
具体例で考えてみましょう。外部の決済サービスから届く入金通知を処理するシステムでは、月末や大型セールの前後には通知が急増しがちです。処理側の能力を超えて通知が届き続けると、通知を一時的に保持する領域があふれ、最悪の場合は通知の取りこぼしにつながりかねません。緩める・間引く・退避・破棄のどれを選ぶかは、入金通知という「一件も失えないデータ」の性質を踏まえて判断することになるでしょう。
一方、工場のセンサーから届く振動データのように、直近の傾向さえ分かればよい場合は、間引く方式が向きます。全件を処理しようとして詰まらせるより、代表値だけを着実に処理できる設計の方が、システム全体の安定につながるでしょう。
ReactiveXが公開するドキュメントでは、バッファリング・破棄・最新値保持といった複数の方策が説明されています。どれを選ぶかは、業務上その値が持つ意味の重さによって判断が分かれるでしょう。
放置するとメモリ枯渇から処理停止に至る
あふれた分を際限なく受け止め続けると、影響は次の順番で広がっていきます。順を追って見ていきましょう。
- バッファの中身が膨らみ、確保しているメモリを圧迫する。
- 空きメモリが減るにつれて、他の処理も含めた応答が遅くなる(レイテンシの増大)。
- メモリを使い切ると、プロセスが落ちるなどして処理そのものが止まる。
厄介なのは、詰まりの兆候が見えにくい点です。序盤はバッファが吸収してくれるため、外からは正常に動いているように見えます。ところが閾値を超えたあたりから応答が急に重くなり、最後は停止に至る、という経過をたどりやすいのです。
処理が止まると、たまっていた未処理データを失う恐れもあります。原因の切り分けにも時間がかかり、復旧までの間、後続の処理が滞ることも考えられるでしょう。バッファを無限に確保できる設計にしないことが、こうした事態を避ける前提になります。
バッファのあふれは、単独のシステムだけにとどまらないこともあります。処理が遅れた消費者への呼び出しが積み残ると、呼び出し元がリトライを重ね、流入がさらに増える悪循環に陥ることもあるでしょう。一つの詰まりが、つながっている別のシステムにまで影響を広げる恐れがあるのです。
運用の現場では、バッファの残り容量や応答時間の推移を継続的に見ておくことが、詰まりの兆候を早めにつかむ手がかりになります。閾値に近づいた段階で対処できれば、処理停止に至る前に手を打てる可能性が高まるでしょう。
詰まりへの対処は、システムを止めないための最後の一線でもあります。あふれた分をどう扱うかを決めておけば、負荷が高まった場面でも、性能を落としながら動き続ける状態を保ちやすくなるでしょう。設計をしないまま迎えると、手を打つ余地がないまま、いきなり停止に至ることもあり得ます。
法人向けのシステムでは、処理停止がそのまま契約上のサービスレベルに影響することもあります。バッファのあふれに気づかないまま稼働を続けると、想定していたよりも早く許容範囲を超えてしまう恐れがあるでしょう。
障害対応にかかる時間や人手は、検知が早いほど抑えやすくなります。反対に、あふれに気づかないまま稼働を続けるほど影響範囲は広がりやすく、復旧にかかる負担も増していく傾向があるでしょう。
身近な実装例:リアクティブ・ストリームと受信制御
バックプレッシャーの考え方は、いくつかの技術基盤にすでに組み込まれています。身近な実装例を見てみましょう。
Reactive Streamsの仕様は、JavaやScala向けのライブラリを中心に、複数の実装で採用されてきました。Java言語自体にも、バージョン9以降でこの仕様に沿った標準APIが組み込まれています。
リアクティブ・ストリーム(複数の非同期処理を規格化してつなぐ仕組み)を採用するライブラリでは、受け手が要求量を伝えるやり取りが標準の動作として備わっているのです。代表的な実装であるRxJavaやProject Reactorには、バッファリング・破棄・最新値保持といった方策が用意されています。扱うデータの性質に応じて選べるでしょう。分散処理の基盤に、同じ考え方を組み込んだ製品も見られます。
メッセージング基盤の中にも、受け手からの応答をもとに送出のペースを合わせる受信制御を備えるものがあります。受け手が処理を終えたと知らせるまで、次のデータを送らないようにする仕組みも、広い意味では同じ考え方の応用です。キューそのものの仕組みや選び方は範囲外とし、ここでは受け手主導でペースを合わせる考え方に絞って触れています。
たとえば外部システムからのWebhook(イベント発生時に自動で送信される通知)を受け取るエンドポイントを考えてみましょう。送信側の再送設定次第で、短時間に通知が集中することがあります。受信側でリアクティブ・ストリームの仕組みを使っていれば、要求量に応じて受け取りペースを調整し、後続の処理に負荷を波及させずに済むでしょう。
同じような発想は、ネットワークの通信制御の分野でも古くから使われてきました。たとえばTCP通信のウィンドウ制御も、受信側の余力に応じて送信量を調整する、よく似た考え方に基づいています。ソフトウェアに限った発想ではなく、分散システム全般に通じる考え方だといえるでしょう。
発注・レビューで押さえておきたい論点
バックプレッシャーの仕組みを一から作り込む場面は、実のところ多くありません。ほとんどは、対応する製品やライブラリを選び、正しく設定して活かす形になるはずです。既製品を使う場合でも、設定しだいで挙動は大きく変わるため、導入前の確認が欠かせません。発注・レビューの段階で押さえておきたい点を、以下に挙げます。
- 流入ピークの見積もりを共有できているか。
- あふれた時にどうふるまう設計か。
- 落としてよいデータかどうかを合意しているか。
- モニタリング指標を決めているか。
流入ピークの見積もりを開発会社と共有する
平常時の流入量だけでなく、キャンペーンや繁忙期など、ピーク時にどれだけの量が届きうるかを、事前にすり合わせておくことが大切です。見積もりが甘いと、想定外の負荷でバッファがあふれ、稼働後にはじめて問題が表面化することにもなりかねません。
過去の利用実績があれば、その推移を根拠として共有するとよいでしょう。見積もりに幅がある場合は、幅の上と下、双方での挙動を確認しておくと見通しが立ちます。
あふれた時にどうふるまうかの設計を確かめる
緩める・間引く・一時退避・破棄のどれを、どの順番で組み合わせる設計なのかを確認しましょう。方式の説明だけを聞いて終わらせず、実際にどの条件で切り替わるのかまで、資料や動作確認で見せてもらうのが手堅い進め方です。あわせて、あふれが起きたことをどう検知し、誰に知らせる設計なのかも確かめておきましょう。
落としてよいデータかどうかを事前に合意する
破棄(ドロップ)の方針を選ぶ場合は、どのデータなら失ってよいのかを、業務の視点から合意しておく必要があります。この判断には、仕組みそのものの知識だけでなく、業務要件と組み合わせて考えられる人材が要るでしょう。
合意なしに実装側の判断だけで決めてしまうと、後になって「そのデータは残しておくべきだった」という食い違いが生じかねません。専門的な知見を持つパートナーであれば、想定される流量やデータの特性を踏まえて、緩める・間引く・退避・破棄のどれを組み合わせるかを設計段階で提案できます。
内製で一から検討する場合は、必要な知識の幅が広く、想定外の負荷でシステムが止まってから対処に追われるケースも見られるでしょう。設計の初期段階から相談できる相手を確保しておくことが、後々の手戻りを抑える近道になります。
モニタリング指標をあらかじめ合意する
バッファの残り容量や応答時間、方式ごとの発動回数など、どの指標を継続的に見るのかを、稼働前に開発会社とすり合わせておきましょう。指標が決まっていないと、詰まりの兆候が出ても気づく手段がなく、対応が後手に回りかねません。
指標をダッシュボードなどで日常的に確認できる状態にしておけば、閾値に近づいた段階で早めに手を打てます。運用に入ってから指標を後付けするのは手間もかかるため、設計段階での合意が望ましいでしょう。
まとめ
本記事では、バックプレッシャーの仕組みと、発注・レビューで押さえておきたい点を整理しました。生産者と消費者の速度差はどのシステムにも起こりうるからこそ、あふれ時の設計をあらかじめ決めておくことが大切です。要点をあらためてまとめます。
- バックプレッシャーは、生産者と消費者の速度差でバッファがあふれそうなときに、流量を調整する仕組みである。
- ストリーム処理やデータ取り込み、ログ集約など、流れの速さがそろわない場面で起きやすい。
- 放置するとメモリ枯渇からレイテンシ増大、最終的な処理停止へと影響が広がっていく。
- あふれ時のふるまいには、緩める・間引く・一時退避・破棄という代表的な方式がある。
- 発注段階では、流入ピークの見積もり・あふれ時の設計・データを落としてよいかの合意が欠かせない。
よくある質問
発注前後によく寄せられる質問を4つ取り上げます。
バックプレッシャーとレートリミットは、同じ仕組みですか。
別の仕組みです。バックプレッシャーは受け手の処理速度に応じて送り手が調整する仕組みで、レートリミットは外部からの流入自体に上限を設ける仕組みになります。両者は組み合わせて使われることもありますが、役割は異なります。外部からの流入自体を絞りつつ、内部の処理速度に応じてさらに調整する、という二段構えの設計もよく見られるでしょう。レートリミットの詳しい設定方法は別記事で扱っています。
バッファを大きくすれば、あふれの問題は解決しますか。
一時的には猶予が増えますが、根本の解決にはなりません。生産者と消費者の速度差が続くかぎり、バッファをどれだけ広げてもいずれ埋まってしまいます。バッファのサイズをどう決めるかより、あふれたときにどうふるまうかの設計のほうが、止まりにくさへの影響は大きいといえるでしょう。むやみにバッファを広げると、詰まりの発覚が遅れ、あふれたときの影響がかえって大きくなることもあります。
データを破棄(ドロップ)する方針は、どんな場合に選びますか。
直近の値だけに意味があり、古いデータの値打ちが薄い場合に向きます。一定間隔で取得し直せる計測値などが当てはまるでしょう。反対に、注文データや決済の記録のように、一件でも欠けると業務に支障が出る情報には不向きな方針です。
導入を検討する際、まず何を確認すればよいですか。
ピーク時にどれだけの流入が見込まれるか、あふれたときにどうふるまう設計か、どのデータなら失ってよいかの3点です。これらを発注前に整理しておくと、開発会社とのレビューがスムーズになります。あふれを検知したときに誰にどう知らせる設計かも、あわせて確認しておくとよいでしょう。既製品を採用する場合も、初期設定のままでよいのかどうかは、あらためて確認しておきたいところです。
著者:テレリモ総研編集部 鈴木 亮佑
LASSICでは、要件定義からアーキテクチャ設計、実装、リリース後の運用・保守までを一貫して支援する体制です。流量が読みにくいシステムのバッファ設計や、あふれた時のふるまいの検討でも、工程を分けずに相談いただけます。国内ニアショア開発体制を活かした対応も可能です。
ご不明な点はお問い合わせフォームからもご連絡いただけます。
出典
- Reactive Streams 公式サイト
- Reactive Streams JVM Specification(仕様書)
- ReactiveX「Backpressure」公式ドキュメント
- Wikipedia「Back pressure」(英語版)