メインコンテンツへ移動
JA
ホーム / 技術ブログ / オートスケールの前に1リクエストを軽くする
2026年4月09日 · Z-SOFT Admin · 読了目安 5 分

オートスケールの前に1リクエストを軽くする

重い処理をキューへ移し、正しい指標に基づいて必要な分だけスケールします。

記事一覧へ戻る

要点: サーバーを増やしても、一つのリクエスト自体が重いという問題は解決しません。

この記事の用語: Backpressure:処理能力を超える前に受付を減らす仕組み。オートスケール:需要に応じて実行数を増減すること。

現場の課題

メール送信、帳票生成、ファイル処理を応答前に行えば、利用者は長く待たされます。さらにサーバーを増やすほどDB接続も増え、下流のボトルネックを悪化させます。

単純な対策だけでは不十分な理由

オートスケールは閾値を超えた後に反応し、重いリクエストを軽くはしません。同期経路を短くし、遅延可能な仕事を分け、下流に上限を置くことが先です。

処理フロー

リクエスト
検証して保存
API
早く応答
キュー
急増分を吸収
ワーカー
副次処理を実行
利用者が待つ経路は短く保ち、非同期処理のワーカーは独立して拡張します。

アーキテクチャ上の判断

同期処理の契約を定義する

利用者の操作を受付済みにするために必要な状態だけをCommitします。副作用はTransactional Outboxで発行し、業務データを保存した後にジョブだけを静かに失う事態を防ぎます。

安全に再試行できるワーカーにする

業務操作ごとに1つの冪等キーを使い、試行状態を保存し、Transient エラーと恒久的なValidation エラーを分けます。At-least-once配信で請求やメールを重複させてはいけません。

需要と飽和度からスケールする

APIは同時実行数と遅延を追えます。ワーカーは最古ジョブの待ち時間、Arrival Rate、サービス Rateを追うべきです。ワーカーの同時実行数は、DBと外部APIが実際にさばける範囲に収めます。

さらに深く考える

BackpressureはAPI契約の一部

キューは無限容量ではありません。即時のOverloadを遅延Workへ変換するだけです。ですから、許容できる最大の最古ジョブの待ち時間を決め、そこから受付 ルールを導きます。予測待機が目標を超えるときは、守れない約束を受付ける前に、低Priorityの処理を拒否または縮退させます。曖昧にTimeoutさせるのではなく、再試行-Afterや再開可能なStatus Resourceを返します。顧客向けPriorityと技術的Fairnessは分けましょう。テナントごとのQuotaで1つのBulk Importが全ワーカーを占有するのを防ぎ、Weighted Schedulingで小さなInteractive ジョブ用の処理能力を確保します。

Exactly-onceはブローカーの機能ではなく業務上のEffect

多くのブローカーは、特にCrash前後ではAt-least-once配信です。1つの業務Effectを実現するには、Durable 冪等性 レコードと状態遷移を、Outputと同じトランザクションでCommitします。キーはDelivery 試行ではなく業務操作を識別するものにします。トランザクションに参加できない外部副作用では、Intentを保存し、提供側の冪等キーで呼び出し、不明な結果をReconcileします。Timeoutは失敗の証明ではありません。再試行の前に提供側の状態を確認することこそが、重複した課金、Message、データ出力を防ぎます。

実装手順

  1. リクエスト時間を測り、利用者が完了を待つ必要のない処理を同期経路から外します。
  2. キュー ジョブは複数回実行されても結果が一つになるよう設計します。
  3. CPUだけでなく、最古ジョブの待ち時間と下流サービスの上限でワーカーを増減します。

コード例: キュー容量とScaling Signal

arrivalRate = jobsAdded / windowSeconds
serviceRate = jobsCompleted / windowSeconds
backlogTime = queueDepth / max(serviceRate, 1)

desiredWorkers = ceil(arrivalRate / jobsPerWorker)
desiredWorkers = clamp(desiredWorkers, minWorkers, maxWorkers)

if backlogTime > objectiveSeconds:
  desiredWorkers = min(desiredWorkers + burstStep, maxWorkers)

Little's Lawは、すべての計測を同じ時間枠で行い、系が比較的安定しているときにだけ成り立ちます。Burst時には、最古ジョブの待ち時間が利用者影響に最も近いGuardrailになります。

想定しておく障害

  • キューへのジョブ投入がDBのCommit能力を上回ります。ワーカー追加は障害を悪化させるため、同時実行上限と受付制御でDBを守ります。
  • デプロイが実行中のワーカーを終了させます。処理権限の有効時間、Heartbeat延長、冪等 Handlerを使い、未完了ジョブを安全に再取得します。
  • 外部APIが特定の1種類のジョブをレート制限します。キューまたは同時実行数 プールを分離し、その依存が無関係な処理へ波及しないようにします。

監視すべきこと

指標何が分かるか
最古ジョブの待機時間利用者が実際に受ける遅延を測り、件数が少なくてもDrainの遅れを検出します。
Arrival RateとCompletion Rate滞留ジョブが一時的なものか、数学的に増え続ける状態かを判断します。
ワーカー利用率とジョブ p95純粋な容量不足と、遅いジョブや偏った分布とを区別します。
DB プール飽和度と外部Throttle安全な上限を定めます。上限を超えるスケールは、Bottleneckを移すだけです。

設計の検証方法

  • 各ジョブを複数回再実行し、Business Row、通知、外部呼び出しがそれぞれ1件だけであることを確認します。
  • Arrival Rateをサービス Rate以上に上げ、DBが飽和する前に受付制御が作動するか確認します。
  • Claim前、処理中、Commit後の各段階でワーカーを停止させ、Lease 復旧を検証します。
  • 1つの外部依存をThrottleし、分離したキューが無関係なジョブの遅延を維持することを確認します。
  • 長時間の障害後、全滞留ジョブと通常の流入を合わせた復旧 Timeを測定します。

本番導入の進め方

メールや帳票などの副作用を一つずつOutboxとキューへ移します。同期結果と比較した後、最古ジョブの待ち時間とDBの安全上限に基づいてワーカーを増やします。

本番前チェックリスト

  • キューは耐障害性を高めますが、その分だけ完了は即時ではなく非同期になります。
  • 滞留ジョブの増加は、利用者が遅延に気づく前に通知しましょう。
  • 接続数と同時実行数の上限でDBを保護します。

まとめ

オートスケールは、仕事の単位、非同期境界、需要を表す指標が明確になって初めて効果を発揮します。

Z-SOFTとの協業

今日のテクノロジーに関する一つひとつの判断が、その後の何年にも影響を与えます。

現状を評価し、目標を明確にし、企業の成長方針に合ったアーキテクチャを選定するために、Z-SOFTのチームにご相談ください。

相談を予約する