Service Mesh (ASM) では、特定のクライアントが大規模言語モデル(LLM)サービスを呼び出す際に消費できるトークン数を制限します。このレート制限は、TCP 属性、HTTP ヘッダー、パス、ホスト、ルート送信先などのリクエスト属性に基づいて適用されます。クライアントが割り当てられたトークン予算を超えると、サイドカープロキシは上流の LLM サービスへリクエストを転送せず、代わりにレート制限応答を返します。
適用範囲
LLM API のコスト管理:外部の LLM サービスは通常、トークン消費量に基づいて課金されます。トークンレート制限により、クライアントまたはユーザータイアごとの支出を上限付きで制御でき、予期せぬコスト増加を防止できます。
共有推論サービスの保護:外部クライアントがクラスター内の推論サービスを呼び出す場合、トークンレート制限により、単一のクライアントによる計算リソースの独占を防ぎ、他のユーザの可用性低下を回避できます。
仕組み
ASM では、WebAssembly(Wasm)上で構築された 2 つのコンポーネントにより、LLM トークンレート制限を実装します。
レート制限プラグイン -- サイドカーフィルターとしてデプロイされる Wasm プラグインです。このプラグインは、送信される各 LLM リクエストをインターセプトし、レート制限キー(例:
user-typeヘッダーの値)を抽出して、レート制限サービスに照会し、リクエストを許可するか拒否するかを判断します。レート制限サービス — クライアントが運用・管理するバックエンドサービスで、トークン消費量の追跡およびレート制限ルールの適用を行います。ASM のレート制限プラグインは、標準的な HTTP インターフェイスを用いてこのサービスを呼び出します。ASM では、Redis をストレージバックエンドとするトーケンバケットアルゴリズムを採用したデフォルト実装を提供しています。カスタムロジックを実装する場合は、任意のアルゴリズム(トーケンバケット、リークバケット、スライドウィンドウ)を用いた独自サービスを構築できます。また、バックエンドサービスの負荷に応じて、レート制限ルールを動的に調整することも可能です。
リクエストフロー:
クライアントがサイドカープロキシを経由して LLM リクエストを送信します。
Wasm プラグインがリクエストヘッダーからレート制限キーを抽出します。
プラグインがレート制限サービスに照会し、該当キーのトークン予算超過状態を確認します。
予算に余裕がある場合は、リクエストが LLM サービスへ転送されます。予算が超過している場合は、プロキシがレート制限応答(例:
regular-user is being rate-limited)を返します。LLM サービスがリクエストを処理し、応答の `
usage` フィールドにトークン使用量データ(例:prompt_tokens、completion_tokens、total_tokens)を含めて応答を返します。プラグインが消費されたトークン数をレート制限サービスへ報告し、記録を更新します。
ステップ 6 は非同期で実行され、LLM 応答がクライアントに届くことをブロックしません。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
ASM インスタンス(バージョン 1.23 以降)が存在し、クラスターが追加済みであること
LLMProvider および関連リソースが、トラフィックルーティング:ASM を用いた LLM トラフィックの効率的管理の手順 1 および 2 を完了することでデプロイ済みであること
クラスターからアクセス可能な Redis サービスが存在すること。マネージドインスタンスを作成する場合は、「Tair(Redis OSS 対応)クイックスタート」をご参照ください。
手順 1:レート制限サービスのデプロイ
この手順では、ユーザーごとのトークン予算を適用するトーケンバケットアルゴリズムを用いたレート制限サービスをデプロイします。例では、異なるトークン割り当てを持つ 2 つのユーザータイア — regular-user および subscriber — を定義しています。
以下の内容で
token-limit.yamlというファイルを作成します。以下のプレースホルダーを実際の値に置き換えてください。
プレースホルダー 説明 例 ${redis-address}Redis ホストアドレス r-bp1xxxxxx.redis.rds.aliyuncs.com${redis-port}Redis ポート番号 6379${redis-user}Redis ユーザー名 default${password}Redis パスワード MyP@ssw0rdRATE_LIMIT_CONFIG環境変数には、トーケンバケットルールが定義されています。各ルールは正規表現でレート制限キーをマッチさせ、個別のバケットを適用します。パラメーター 説明 rate_limit_key_regexリクエストヘッダーから抽出されたレート制限キーと一致させる正規表現パターン。 max_tokensトーケンバケットの最大容量。この上限を超えるリクエストは拒否されます。 tokens_per_fill各充填間隔でバケットに追加されるトークン数。 fill_interval_secondトークンの充填間隔(秒単位)。 redis_expired_secondsRedis 内のレート制限レコードの有効期限(TTL)。この期間が経過すると、レコードは期限切れとなり、バケットはリセットされます。 以下に、この例で設定されたレート制限ルールを示します。
ルール キー正規表現 バケット容量 充填レート Redis TTL 一般ユーザ regular-user.*200 トークン 30 秒ごとに 50 トークン 300 秒 サブスクライバー subscriber.*1,000 トークン 60 秒ごとに 100 トークン 600 秒 サブスクライバーは、一般ユーザより 5 倍大きなバケット容量と充填トークン数を享受し、継続的な高ボリュームな LLM 利用をサポートします。
データプレーン クラスターの kubeconfig を用いて、構成を適用します。
kubectl apply -f token-limit.yaml
これは ASM が提供するデフォルトのレート制限実装です。異なるアルゴリズムやストレージバックエンドなど、カスタム要件がある場合は、「GitHub 上のソースコード」をご参照ください。
手順 2:Wasm プラグインのデプロイ
この手順では、サイドカープロキシを構成して LLM リクエストをインターセプトし、user-type ヘッダーからレート制限キーを抽出し、レート制限サービスに対して照会を行う WasmPlugin をデプロイします。
以下の内容で
wasm.yamlというファイルを作成します。apiVersion: extensions.istio.io/v1alpha1 kind: WasmPlugin metadata: name: llm-token-ratelimit namespace: default spec: failStrategy: FAIL_OPEN imagePullPolicy: IfNotPresent selector: matchLabels: app: sleep match: - mode: CLIENT ports: - number: 80 phase: STATS pluginConfig: matches: - host: exact: "dashscope.aliyuncs.com" rateLimitKeys: - "{{request.headers.user-type}}" rateLimitService: service: asm-llm-token-rate-limit-example.default.svc.cluster.local port: 80 priority: 10 url: registry-cn-hangzhou.ack.aliyuncs.com/acs/asm-wasm-llm-token-ratelimit:v1.23.6.34-g92d6a4b-aliyun以下の表に、主要な構成フィールドの説明を示します。
フィールド 説明 .spec.pluginConfig.matchesレート制限を適用するリクエストを定義します。マッチしないリクエストは、レート制限チェックなしで通過します。 .spec.pluginConfig.rateLimitKeysレート制限キーの抽出方法を指定します。Envoy リクエスト属性 構文を使用します。本例では、 {{request.headers.user-type}}により、user-typeヘッダーの値が抽出されます。.spec.pluginConfig.rateLimitServiceレート制限サービスのエンドポイントを指定します。Kubernetes Service の完全修飾ドメイン名(FQDN)を指定してください。 コントロールプレーン クラスターの kubeconfig を用いて、構成を適用します。
kubectl apply -f wasm.yaml
手順 3:構成の検証
両方のユーザータイアでテストリクエストを送信し、レート制限が正しく機能することを確認します。
以下の各コマンドを、データプレーン クラスターの kubeconfig を用いて複数回実行します。
一般ユーザとして:
kubectl exec deployment/sleep -it -- curl 'http://dashscope.aliyuncs.com' \
--header 'Content-Type: application/json' \
--header "user-type: regular-user" \
--data '{
"messages": [
{"role": "user", "content": "自己紹介をお願いします"}
]
}'サブスクライバーとして:
kubectl exec deployment/sleep -it -- curl 'http://dashscope.aliyuncs.com' \
--header 'Content-Type: application/json' \
--header "user-type: subscriber" \
--data '{
"messages": [
{"role": "user", "content": "自己紹介をお願いします"}
]
}'期待される動作:
両方のユーザータイアからの初期リクエストでは、トークン数を含む `
usage` フィールドを含む通常の LLM 応答が返されます。数回のリクエスト後に、
regular-userが最初にレート制限に達し、「regular-user is being rate-limited」という応答を受け取ります。subscriberは、レート制限に達するまでより多くのリクエストを送信でき、高いトークン予算が正しく適用されていることが確認できます。
これにより、レート制限サービスがユーザータイアを区別し、設定されたトークン予算を適切に適用していることが検証されます。
次のステップ
レート制限ルールのカスタマイズ:本番環境のトラフィックパターンに合わせて、
max_tokens、tokens_per_fill、fill_interval_secondをRATE_LIMIT_CONFIGで調整します。カスタムレート制限サービスの構築:「サンプル実装」をフォークし、カスタムアルゴリズム(リークバケット、スライドウィンドウ)の実装や、異なるストレージバックエンドの利用を実現します。
対象属性の拡張:レート制限キーの抽出元を、パス、ホスト、TCP 属性などの他のリクエスト属性に変更するには、
rateLimitKeysを編集します。「Envoy 属性」で利用可能なオプションをご確認ください。