はじめに:MLサービングにおいてルーティングが重要な理由
MLモデルをサービスとして提供する際、最も厄介な問題の一つは 「どのモデルを、どのユーザーに、どのバージョンで見せるか」 です。特にNetflixのように数百のモデルが秒間100万のリクエストを処理する環境では、この問題がインフラアーキテクチャの中核課題となります。
この記事はNetflix Tech Blogの「State of Routing in Model Serving」シリーズを基に、MLモデルサービングプラットフォームでトラフィックをどのようにインテリジェントにルーティングするのか、そしてその過程でどのようなアーキテクチャ上の課題があったのかを詳しく見ていきます。
核心的な問い: 単一のAPIエントリポイントで数百のモデルを安全にサービングしながら、研究者(モデル開発者)とクライアント(サービス開発者)の両方に最適な抽象化を提供するにはどうすればよいのか?
背景:Netflixの「モデル」は単なる推論ではない
一般的なMLサービングシステムは、infer(features) -> score 形式の単純な推論関数を提供します。しかしNetflixにおける「モデル」とは、前処理、特徴量計算、後処理、そしてオプションのML推論コンポーネントをすべて含む一つのワークフローです。
例えば「視聴中コンテンツ(Continue Watching)行のパーソナライゼーション」ユースケースを見てみましょう:
- 入力: UserId、国、デバイスID
- 出力: ソートされた映画/シリーズIDのリスト
クライアントは単に userId とコンテキストを渡すだけで、モデルサービングプラットフォームが内部的に必要な特徴量を収集し、適切なモデルを選択して推論を実行し、結果を返します。この過程で、クライアントはモデルのバージョン、実験の有無、クラスタの場所などを全く知る必要がありません。
これを実現するために、Netflixは Switchboard という中央ルーティングサービスを導入しました。
第1世代:Switchboard — 単一エントリポイントの始まり
SwitchboardはすべてのML推論リクエストが必ず通過する 中央プロキシレイヤ です。このサービスは以下のような中核的な役割を果たします:
1. Objective抽象化
Netflixはユースケースを Objective という列挙型で定義します。例えば ContinueWatchingRanking というObjectiveが一つのビジネス要件を表します。クライアントはObjectiveだけを指定すればよく、内部的にどのモデルが使用されるかはSwitchboardが決定します。
2. コンテキストベースのルーティング
Switchboardはリクエストのコンテキスト(userId、デバイス、ロケール、A/Bテストの割り当てなど)を分析し、適切なモデルインスタンスにルーティングします。このとき、研究者(ML開発者)はJavaScriptベースの Switchboard Rules を作成してルーティングルールを定義します。
/**
* モデル研究者がA/B実験のために作成するルーティングルールの例
* Cell 1: 現在のプロダクションモデル(デフォルト)
* Cell 2, 3: 実験モデル(候補)
*/
function defineAB12345Rule() {
const abTestId = 12345;
const objectives = Objectives.ContinueWatchingRanking;
const abTestCellToModel = {
1: {name: "netflix-continue-watching-model-default"},
2: {name: "netflix-continue-watching-model-cell-2"},
3: {name: "netflix-continue-watching-model-cell-3"}
};
return {
cellToModel: abTestCellToModel,
abTestId: abTestId,
targetObjectives: [objectives],
modelInputType: constants.TITLE_INPUT_TYPE,
modelType: 'SCORER'
};
}
3. トラフィック分割とライフサイクル管理
Switchboardはカナリアデプロイ、シャドウモードテスト、即時ロールバックなどをサポートします。研究者は新しいモデルを全トラフィックの1%だけに露出させ、安全に検証することができます。
Switchboardの限界
しかし規模が大きくなるにつれて、三つの主要な問題が明らかになりました:
| 問題 | 影響 |
|---|---|
| 単一障害点(SPOF) | Switchboardにバグが発生すると全MLサービスが停止 |
| 追加レイテンシ (10〜20ms) | シリアライズ/デシリアライズのコスト + テールレイテンシの増幅 |
| クライアントの柔軟性低下 | サービングクラスタで実際のトラフィックと人工トラフィックの区別が困難 |
実務インサイト: 中央集権型ルーティングは初期の開発速度を高めますが、規模が大きくなるにつれてレイテンシと障害伝播のリスクが大きくなります。これはマイクロサービスアーキテクチャにおけるAPIゲートウェイ設計でも同様に考慮すべきポイントです。
第2世代:Lightbulb — 分離と委任の知恵
NetflixはSwitchboardの利点を維持しつつ欠点を解決するために、Lightbulb アーキテクチャへと進化しました。核となるアイデアは ルーティング決定のためのメタデータ解釈(Control Plane)と実際のトラフィック転送(Data Plane)を分離する ことです。
新しいアーキテクチャの構成
-
Lightbulb(軽量サービス): リクエストコンテキストを受け取り、
routingKeyとObjectiveConfig(モデルIDなど)を返します。このサービスは実際のリクエストペイロードを一切見ず、最小限のメタデータだけで判断を下します。 -
Envoy Proxy: すでにNetflixの全サービス間通信で使用されているEnvoyが実際のルーティングを担当します。Lightbulbが生成した
routingKeyをHTTPヘッダに含めて、Envoyが該当するVIPにリクエストを転送します。
// Lightbulbの応答例
{
"routingKey": "continue-watching-v2-us-east",
"objectiveConfig": {
"modelId": "netflix-continue-watching-model-cell-2",
"experimentId": 12345
}
}
利点
- レイテンシ削減: Switchboardを経由しないため、シリアライズ/デシリアライズのコストが不要
- 障害の分離: Lightbulbに障害が発生しても、Envoyがキャッシュされたルーティング情報でフォールバック可能
- テナント分離: 各ユースケース(テナント)ごとにルーティングクラスタを分離し、エラー伝播を防止
このアーキテクチャの限界と注意点
Lightbulbアーキテクチャが完璧な解決策というわけではありません。以下のような限界を認識しておく必要があります:
- Envoyへの依存: Envoyのルーティング能力とカスタマイズ範囲によって実装が制限される可能性があります。Envoyがサポートしない複雑なルーティングロジックが必要な場合は、再び中央サービスを検討する必要があります。
- メタデータキャッシュの一貫性: Lightbulbのルーティングキーが変更された際、Envoyのキャッシュが即座に更新されないと、誤ったルーティングが発生する可能性があります。
- 運用の複雑化: 単一サービス(Switchboard)から二つのコンポーネント(Lightbulb + Envoy設定)に分離されたことで、運用ポイントが増えました。
まとめ:アーキテクチャに正解はなく、トレードオフである
Netflixの事例は 「初期はシンプルに、成長後は分離と委任を」 選択する典型的なアーキテクチャ進化のパターンを示しています。
- Switchboard は迅速な革新のための抽象化を提供しましたが、規模が大きくなるにつれてレイテンシと障害リスクという代償を払いました。
- Lightbulb は同じ抽象化を維持しながら、Control PlaneとData Planeを分離することで、それぞれの問題を解決しました。
MLモデルサービングアーキテクチャを検討されている方へのアドバイス:
- まず必要な抽象化レベルを定義しましょう。 クライアントが知るべきことと知らなくてよいことを明確に区別してください。
- 初期はシンプルに始めましょう。 Switchboardのような中央ルーティングから始めても十分です。
- 成長の痛みを感じたときに分離しましょう。 性急な分散化はかえって複雑性を増すだけです。
元記事でも述べられているように、このシリーズは今後も続きます。次回は 推論エンジンの最適化 と 特徴量フェッチ戦略 を扱う予定とのことですので、MLインフラにご興味のある方はぜひチェックしてみてください。


