1 並行リクエストの概要
1.1 定義と目的
1.1.1 待ち時間短縮
並行リクエストは、複数の要求を重なり合う形で送受信し、個々の待機(ネットワーク遅延、処理待ち、応答受信待ち)を互いに埋め合わせることで、体感の応答時間や完了までの時間を縮めることを狙う技術的な考え方である。単一要求を順番に実行すると、前の処理が終わるまで後続の要求が待たされやすいが、同時に進めれば待ちの総和を圧縮できる場合がある。特に複数の独立した取得(複数API呼び出し、複数マイクロサービス問い合わせ、複数のデータソース参照)をまとめて行う場面で効果が出やすい。
1.1.2 スループット向上
待ち時間の短縮に加え、並行実行は同一時間あたりに処理できる要求数(作業量の総体)を押し上げる方向に働くことが多い。通信待ちが主因でアイドル状態が発生しやすい環境では、並行化によりワーカーや接続の利用率を高められる。結果として、ピーク時の処理能力を引き上げたり、同じ計算資源でより多くの利用者の要求をさばいたりすることが可能になる。
1.2 関連する概念との違い
1.2.1 並列処理との関係
並行リクエストは、時間軸上での重なり(同時進行や進行の取り回し)を重視する概念であり、必ずしも物理的な同時実行(複数コアでの実処理)を前提としない。対して並列処理は、複数の処理単位が同時に実行されることを主眼とする。並行実行は、単一スレッドのイベントループのように見かけ上の進行を切り替える形でも成立する一方、並列処理は複数スレッドや複数CPUでの同時性を伴いやすい。両者は重なり得るが、焦点は異なる。
1.2.2 同期・非同期との関係
同期・非同期は「呼び出し元が応答を待つか、待たずに先へ進むか」に関する性質として説明されることが多い。並行リクエストは、非同期実行やイベント駆動によって実現される場合が一般的だが、並行性そのものは「要求が重なる形で扱われるか」という運用特性である。したがって、非同期でなくても工夫により並行性を得ることはあり得るが、実装では非同期と組み合わせて管理する設計が多い。
2 実装方式
2.1 クライアント側の制御
2.1.1 同時接続数の管理
2.1.1.1 リクエスト数上限とバックプレッシャー
クライアントが無制限に並行化すると、ネットワークやサーバ、周辺の依存サービスに過負荷が波及しやすく、結果として全体の応答品質が下がる。そこで、同時接続数や同時実行数に上限を設け、待ち行列が膨張しないように調整する。バックプレッシャーは、受け手の処理能力に応じて送信側のペースを制御し、溢れを未然に抑える考え方である。クライアント側では、キューに入れた要求の数を監視し、しきい値を超える場合には新規要求の抑制、遅延投入、あるいは低優先度の破棄を行う設計が採られる。
2.1.2 タイムアウトとリトライ方針
並行リクエストでは、個々の要求が部分的に失敗し得るため、タイムアウト設定と再試行のルールが重要になる。タイムアウトは、遅延が長引いた要求がシステム資源を占有し続けることを防ぐ。リトライ方針は、短時間の一時的障害に対しては効果がある一方、原因が持続的である場合は負荷を増やす。再試行を行う場合は、指数バックオフやジッタを用いて同時に再実行が集中することを避けるほか、リトライ上限回数、全体の猶予時間(総タイムアウト)を定めることが望ましい。
2.2 サーバ側の制御
2.2.1 キューイングとスレッド/ワーカー管理
サーバは並行要求を受け取るため、処理待ちが増えると遅延が連鎖しやすい。そこで、受理後のキューイング戦略と、処理を担当するスレッドやワーカー数を適切に設計する必要がある。キューの長さには上限を設け、上限を超えた場合の挙動(拒否、待機、または低優先度の処理)を決める。ワーカー数が不足すれば待ちが増え、過剰であればコンテキスト切り替えや競合コストが増えるため、実測に基づくチューニングが求められる。
2.2.2 レート制限と公平性
並行性の高い環境では、特定の利用者や処理経路に負荷が偏ると、他の要求の遅延が極端に悪化することがある。レート制限は、要求の発生頻度や帯域、同時実行数を制御し、過剰なトラフィックが系全体を支配するのを防ぐ仕組みである。公平性の観点では、優先度や割当てを用いて同一クラス内の扱いを揃えたり、重み付きのスケジューリングでリソース配分の偏りを抑えたりすることがある。これにより、並行リクエストがもたらす「効率化」の副作用としての不均衡を緩和できる。
3 通信プロトコルとアーキテクチャ
3.1 HTTPにおける並行性
3.1.1 接続再利用と多重化
HTTPでは、TCPコネクションの確立に伴う往復遅延が性能に影響する。接続再利用(同一ホストへの通信で既存コネクションを使い回す)を行うと、新規接続のオーバーヘッドを削減できる。さらに多重化は、1つの接続の上で複数の通信を同時に扱うことで、複数要求の重なりを作りやすくする。結果として、往復の積み上げを減らし、同時実行の恩恵を引き出しやすくなる。
3.1.2 HTTP/2・HTTP/3の考え方(概要)
HTTP/2は、ストリームの概念により1接続内で複数のリクエストを扱う設計が中心にある。これにより、単一接続を用いつつ通信を効率化しやすい。HTTP/3は、通信基盤として別のトランスポートを用い、損失時の挙動などで体感遅延の改善が期待される。どちらも並行性の設計と親和性が高く、アプリケーションが要求を重ねる際の基盤として活用されることが多い。
3.2 API設計と並行実行
3.2.1 冪等性と重複排除
並行リクエストでは、ネットワークエラーやタイムアウトにより同じ操作が重複して発生する可能性がある。冪等性は、同一の呼び出しが複数回行われても結果が変わらない性質を指し、再試行や並行実行の安全性を高める。重複排除の観点では、クライアント側のリトライに備えてサーバが操作キーや要求識別子を使い、すでに処理済みのものを再計算しない仕組みが検討される。これにより、並行性の導入がデータの不整合や副作用の増幅につながるリスクを抑えられる。
3.2.2 部分失敗への対応
並行実行では、複数処理のうち一部だけが成功し、他が失敗する「部分失敗」が起こり得る。API設計では、どの段階で失敗が観測されるのか、返却形式に成功・失敗の内訳をどう表現するかが重要になる。クライアントは、失敗した要求のみを再試行するのか、全体を中止してやり直すのか、代替手段を適用するのかを判断する必要がある。サーバ側は、エラーの分類(リトライ可能か、不可か)や、必要な情報を返すことで、クライアントの分岐を単純化しやすくする。
4 性能・信頼性・運用
4.1 性能指標
4.1.1 レイテンシとスループット
並行リクエストの評価では、平均的な応答時間だけでなく分位点(例:中央値、95パーセンタイル)を追うことが多い。レイテンシは、要求が処理を終えて返るまでの遅れであり、並行化によって改善する場合と、過負荷で悪化する場合の両方がある。スループットは、単位時間あたりに完了する要求数、あるいは処理量で表される。並行数を増やせば直線的に伸びるとは限らず、ある点を超えると競合や待ちが増えて頭打ちになることがあるため、段階的な検証が必要になる。
4.1.2 エラー率とリソース使用量
並行性を上げると失敗率が上がることがあるため、エラー率の増減は重要な指標である。対象としては、タイムアウト、サーバ側の5xx系応答、クライアント側の中断などが含まれる。あわせてCPU使用率、メモリ消費、ソケット数、キュー長、GC頻度といったリソース使用量を観測すると、どの要因がボトルネックになっているかを切り分けやすい。性能の改善が、別の資源を圧迫していないかを確認することで、長期運用の安定性が高まる。
4.2 失敗時の挙動
4.2.1 キャンセルと中断
並行実行では、不要になった処理を止めることで無駄な負荷を減らせる。例えば上位の条件が成立して結果が確定した場合、残りの要求をキャンセルする設計がある。中断の扱いは、サーバ側での後処理、部分的に書き込まれたデータ、外部依存への影響といった観点で難しさがあるため、キャンセル要求が安全に反映されるようにAPIや内部処理を設計する必要がある。
4.2.2 フォールバック戦略
フォールバック戦略は、特定の経路が不調なときに別の取得方法や簡易応答に切り替える考え方である。並行リクエストの文脈では、成功した要求だけで成立する「部分組み立て」を行ったり、古いキャッシュに切り替えたり、低コストな代替サービスへ誘導したりすることが含まれる。重要なのは、切り替え条件と品質劣化の許容範囲を明確にすることであり、無秩序な切替は別の障害形態(カスケード)を生む可能性がある。
4.3 モニタリングとチューニング
4.3.1 ログ相関とトレーシング
並行化すると、要求の流れが複数に分岐し、時系列の追跡が難しくなる。ログ相関IDやトレーシング技術を用いて、クライアントからサーバ、さらに依存サービスまでの経路を結び付けることで、遅延の発生箇所や失敗の原因を特定しやすくなる。特に並行で実行された複数要求について、どれが待ちを生んでいるのか、どのコンポーネントがボトルネックになっているのかを可視化することが運用上の価値につながる。
4.3.2 目標値(SLO)に基づく調整
SLO(サービスレベル目標)は、可用性や応答品質などの達成基準を定量化する枠組みである。並行リクエストのチューニングは、単に並行数を増やすだけではなく、レイテンシ分位やエラー率、タイムアウト頻度といった指標がSLOに収まるように制御するプロセスとして設計される。運用では、負荷変動に合わせて上限値やワーカー数を調整し、設定の変更がどの指標に影響したかを検証しながら改善サイクルを回すことが一般的である。
5 セキュリティとガバナンス
5.1 誤用対策
5.1.1 濫用(過剰並行)への抑制
並行リクエストは攻撃や不正利用の踏み台になり得る。例えば多数の要求を同時に発行することで、処理資源や接続枯渇を誘発できるため、設計として上限や検査を組み込む必要がある。具体的には、同時実行数の上限、要求単位の制御(ユーザ別、API別)、短時間の集中に対する抑制、そして不正なパターンの検知が挙げられる。利用者への公平性を保ちながら、全体の安定性を守ることがゴールになる。
5.1.2 認証・認可と同時実行の整合
認証・認可は、要求ごとに権限を判定することが基本であるが、並行実行では判定結果をまたいだ整合性が問題になる場合がある。例えば権限が短時間で変化するケースでは、同時に処理された要求が異なる権限状態に基づいて実行される可能性がある。これを扱うために、要求処理時点の権限スナップショットの考え方、トークン有効性の扱い、再検証の有無などを明確にすることで、予期せぬ許可や拒否を抑えられる。
5.2 データ一貫性
5.2.1 競合更新の扱い
同一データへの更新が複数の並行要求から発生すると、競合が生じる。競合の管理には、楽観的ロック(更新前に版数や条件を確認する)、悲観的ロック(競合を前提に排他制御する)、あるいはイベント駆動で順序を保証する設計などがある。並行実行が増えるほど競合確率は上がるため、更新の設計段階から衝突しにくい粒度への分割や、再試行時の整合性確保を考慮することが望ましい。
5.2.2 トランザクション境界の設計
トランザクションは一貫性を担保するために重要だが、並行リクエストでは境界の設計が性能と整合性の両立を左右する。単一の大きなトランザクションにすると競合が増え、待ち時間やロック保持が長くなりやすい。逆に境界を細かくしすぎると、途中状態を外部に見せたり、整合性の検証が分散したりする。結果整合性の前提(強い整合か、最終的な整合か)を定めたうえで、どの操作を同一境界にまとめ、どこから分離するかを決めることが必要になる。