TT Lab
はじめる
学ぶ 学習パス コース

LLMサービング

連続バッチングスケジューラのシミュレーション

TT Labで続きを見る

目標

静的バッチ処理と連続バッチ処理を、それぞれシミュレーションで実装して、スループットの差を数字で確認し、TTFTのSLOを満たす最大の同時実行数を探索する方法を身に付けます。

なぜ重要なのか

LLMの生成は、リクエストごとに出力長がまちまちです。あるリクエストは10トークン、あるリクエストは1,000トークンです。静的バッチ処理で32個をまとめると、31個が早く終わっても、最も長い1つが終わるまで、そのスロットが空いたままになります。GPUは、32個分のリソースを確保して、1個を処理します。連続バッチ処理は、デコードの反復ごとに、終わったスロットを、待機キューのリクエストで埋めます。コードでは1行の違いですが、スループットは2–5倍変わります。このラボは、GPUなしで、そのメカニズムだけをシミュレーションで再現します。最後のステップ8の順序が、実務の核心です。スループットを先に最大化して、レイテンシをあとで見ると、たいていSLOを守れません。TTFTの目標を先に決めて、それを満たす最大の同時実行数を探すのが、正しい順序です。

ステップ

  1. /root/lb2/static.pyで、静的バッチ処理をシミュレーションしてください。リクエストは、/opt/fixtures/llms/requests.json(100件、それぞれprompt_tokensとoutput_tokensを持つ)を使い、バッチサイズは16です。
  2. /root/lb2/static.txtに、total_steps=<n> throughput_tps=<수> slot_util=<0~1 소수>(プレースホルダーは数値と、0から1の小数です)を書いてください。slot_utilは、0.7未満である必要があります。
  3. /root/lb2/continuous.pyで、連続バッチ処理をシミュレーションしてください。反復ごとに、終わったシーケンスを外して、待機キューから埋めます。
  4. /root/lb2/compare.txtに、static_tps=<수> continuous_tps=<수> speedup=<수>(プレースホルダーは数値です)を書いてください。speedupは、1.8以上である必要があります。
  5. max_num_seqs=32の上限を適用してください。/root/lb2/maxseqs.txtに、max_num_seqs=32 peak_running=<n>を書き、peak_runningは32以下である必要があります。
  6. 流入率を、毎秒5、10、20、40件と変えながら、/root/lb2/queue.csvに、rps,avg_queue,p99_wait_msのヘッダーと4行を書いてください。rpsが上がるほど、p99_wait_msが単調増加する必要があります。
  7. /root/lb2/cost.pyは、prefill_ms = prompt_tokens * 0.05とdecode_ms = output_tokens * 8.0で、コストを分離してください。/root/lb2/cost.txtに、total_prefill_ms=<수> total_decode_ms=<수> decode_share=<0~1 소수>(プレースホルダーは数値と、0から1の小数です)を書いてください。
  8. /root/lb2/tune.txtに、target_ttft_ms=200 max_concurrency=<n> throughput_at_target=<수>(プレースホルダーは数値です)を書いてください。その同時実行数で、p99のTTFTが200以下である必要があります。

参考

静的バッチ処理のシミュレーターを作る

/root/lb2/static.pyで、静的バッチ処理をシミュレーションしてください。リクエストは、/opt/fixtures/llms/requests.json(100件、それぞれprompt_tokensとoutput_tokensを持つ)を使い、バッチサイズは16です。

バッチを埋めて、すべてが終わるまで待ちます。リクエストごとに出力長が違うという点が核心です。

静的バッチ処理の指標を測る

/root/lb2/static.txtに、total_steps=<n> throughput_tps=<수> slot_util=<0~1 소수>(プレースホルダーは数値と、0から1の小数です)を書いてください。slot_utilは、0.7未満である必要があります。

スループットとスロット利用率を、いっしょに見ます。遊んでいるスロットがどれだけあるかが、問題の大きさです。

連続バッチ処理のスケジューラーを作る

/root/lb2/continuous.pyで、連続バッチ処理をシミュレーションしてください。反復ごとに、終わったシーケンスを外して、待機キューから埋めます。

反復ごとに、終わったシーケンスを外して、待機キューから埋めます。この1行が、差のすべてです。

2つの方式のスループットを比較する

/root/lb2/compare.txtに、static_tps=<수> continuous_tps=<수> speedup=<수>(プレースホルダーは数値です)を書いてください。speedupは、1.8以上である必要があります。

同じリクエストの集合で比較して初めて、意味があります。改善の倍数を計算してください。

同時実行数の上限を適用する

max_num_seqs=32の上限を適用してください。/root/lb2/maxseqs.txtに、max_num_seqs=32 peak_running=<n>を書き、peak_runningは32以下である必要があります。

無限に入れることはできません。KVキャッシュが、上限を決めます。

キューの深さとp99の待ち時間の関係を見る

流入率を、毎秒5、10、20、40件と変えながら、/root/lb2/queue.csvに、rps,avg_queue,p99_wait_msのヘッダーと4行を書いてください。rpsが上がるほど、p99_wait_msが単調増加する必要があります。

流入率を上げながら測ると、どの地点でp99が崩れるのかが見えます。平均は、しばらくの間は問題なさそうに見えます。

prefillとdecodeのコストを分けてモデリングする

/root/lb2/cost.pyは、prefill_ms = prompt_tokens * 0.05とdecode_ms = output_tokens * 8.0で、コストを分離してください。/root/lb2/cost.txtに、total_prefill_ms=<수> total_decode_ms=<수> decode_share=<0~1 소수>(プレースホルダーは数値と、0から1の小数です)を書いてください。

2つのコスト関数は異なります。プロンプトの長さに比例するものと、トークン数に比例するものを分けてください。

TTFTの目標を満たす最大の同時実行数を探す

/root/lb2/tune.txtに、target_ttft_ms=200 max_concurrency=<n> throughput_at_target=<수>(プレースホルダーは数値です)を書いてください。その同時実行数で、p99のTTFTが200以下である必要があります。

目標を先に決めて、それを満たす最大値を探します。スループットから先に最大化すると、SLOを守れません。