このエントリは2023/06/08現在の情報に基づいています。将来の機能追加や変更に伴い、記載内容からの乖離が発生する可能性があります(2024/01/23情報を更新)。
Azure OpenAI Service (以下、AOAI) を使ったシステム開発やコンポーネント配置について多く問い合わせをもらっているので、備忘録がてら記載しておく(実のところ、どのサービスであっても同じ考え方が適用できるのだが)。
問い合わせ
AOAIを使い、業務にAIの能力を組み込みたいと考えている。ただ、現在のAOAIの制約ではすぐにRate limitにヒットしそうなので、なんとか複数インスタンスへの負荷分散をしたい。おすすめの方法はないか?
AOAIのQuotaと、利用可能なモデルは以下に記載がある。
Azure OpenAI Service のクォータと制限 / Azure OpenAI Service quotas and limits
https://learn.microsoft.com/azure/cognitive-services/openai/quotas-limits
モデルの概要テーブルとリージョンの可用性 / Model Summary table and region availability
https://learn.microsoft.com/azure/cognitive-services/openai/concepts/models#model-summary-table-and-region-availability
例えばGPT-4モデルだと2024/01/21現在、1分間で20kもしくは40kまでのトークンを受け付け可能だが、それではちょっとつらい、という場合に、複数のAOAIインスタンスで負荷分散させたいと考えるのはよくある(もちろん上限の緩和申請も可能ではあるが、すぐに緩和されるとは限らない)。
しかも、リージョンでキャップがかかるため、同一リージョンにAOAIインスタンスを立てて上限を増やすことはできない。そのため、
- 複数のリージョンにAOAIインスタンスを立てる
- 異なるSubscriptionに同一リージョンにAOAIを立てる
のいずれかの方法をとった上で負荷分散する必要がある。
【2023/09/08更新】
Build 2023でProvisioned Throughputモデルが発表された。詳細はドキュメントに記述がないが、Microsoftの営業さんに尋ねると教えてくれる。Provisioned Throughputを使うと、Quotaで定義されているレートリミットから解放されるため、一つのインスタンスをグループ個社で共用することもできる。この場合、負荷分散はレートリミット稼ぎの目的ではなく、純粋な可用性向上のために寄与する。
Generative AI for Developers: Exploring New Tools and APIs in Azure OpenAI Service
https://techcommunity.microsoft.com/t5/ai-cognitive-services-blog/generative-ai-for-developers-exploring-new-tools-and-apis-in/ba-p/3817003
AOAIを利用するにあたって
AOAIのAPIを直接利用するのが一番シンプルでわかりやすい。
そのほか、API Managementを挟むことで、各アプリがAOAIのAPI Keyを意識せずに済ませる、という方法も考えられる。
いずれにしても、アプリケーションやAPI Managementで、AOAIのAPIを呼び出すために、HTTP HeaderにAPI KeyもしくはAzure AD認証 (RBAC) によるBearer tokenを渡す必要がある。
API KeyとAzure AD認証のどちらが推奨か?
Azure AD認証の利用を強く推奨する。理由はAPI Keyを使う必要がないのでAPI Key漏洩の心配がないこと、そして圧倒的に運用管理コストを下げられるため。
API ManagementでAzure AD認証を使う場合の具体的な構成を以下に記載しておく。
API ManagementのManaged Identityを生成し、それに対して各AOAIインスタンスのCognitive Services Userロールを付与する。その後、InboundパイプラインでManaged Identity認証ポリシーを使ってBearerトークンを取得し、バックエンドサービス(AOAI)呼び出し時に付加する。以下はその例。
<authentication-managed-identity resource="https://cognitiveservices.azure.com"
output-token-variable-name="msi-access-token" ignore-error="false" />
<set-header name="Authorization" exists-action="override">
<value>@("Bearer " + (string)context.Variables["msi-access-token"])</value>
</set-header>
対してAPI Keyを使う場合、接続先のAOAIインスタンスのAPI KeyをKey Vaultのシークレットとして格納するなどして、それを参照することになるだろう。この場合、API Key再作成時にはシークレットをアップデートする必要がある(しかも自動化されているわけではない)。
負荷分散
[1] 呼び出し元のアプリに基づいて負荷分散
文字通りで、呼び出し元を判断できるSubscription KeyをAPI Managementで発行できるので、このKeyを使い、バックエンドの呼び出し先を変える、というもの。ただ、均等な負荷分散にはならない点には注意が必要。
[2] リクエストに基づくユニークな値を使って負荷分散
より均等に分散するなら、リクエストIDなどのユニークな値を使って負荷分散することもできる。構成自体は[1]と同じで、Inboundセクションのポリシーでロジックを記載し、その値で振り分け先のバックエンドサービス (AOAI) を決める、というもの。
[3] API Managementの負荷分散機能を使う
【2024/01/23更新】API Managementに負荷分散機能が追加された(現在Preview)。
負荷分散プール (プレビュー) / Load-balanced pool (preview)
https://learn.microsoft.com/azure/api-management/backends?tabs=bicep#load-balanced-pool-preview
これを使うと、バックエンドプールとして複数のバックエンドサービスURLを指定できる。ただし2024/01/23現在、利用可能な負荷分散ルールはラウンドロビンのみ。
[4] 負荷分散サービスを使う
L4/L7 Load balancer、DNSによる負荷分散、リージョンローカルなのか、リージョンまたぎになるのかで様々なサービスがあるが、結論から言うとL7 Load balancer (Application GatewayもしくはFront Door) しか利用できない。理由は以下。
- Azure Standard Load Balancer
- Private Endpointに対する負荷分散はできない
- AOAIを呼び出す場合ホスト名が必須だが、ホスト名付きで呼び出せない
- HTTPリクエストの場合、接続を切らないことが多いので、L4 Load Balancerだと均等な負荷分散が難しい
- Traffic Manager
- ホスト名が変わってしまい、AOAIにアクセスできない
ということで、リージョン内であれば、Application Gateway、リージョン間であれば、Front Doorを使う。
サービス | L4/L7/DNS | リージョン間 or リージョン内 | 利用可否 |
---|---|---|---|
Load Balancer | L4 | Regional (cross regionもあり) | × |
Application Gateway | L7 | Regional | ○ |
Front Door | L7 | Global | ○ |
Traffic Manager | DNS | Global | × |
Application Gateway、Front Doorでは起こらないが、L7 Load BalancerによってはHTTP HeaderのAuthorizationを除去する場合があるので注意が必要。
Edgeの待機時間を短くするために
アプリケーションが様々なロケーションで利用される場合、Edgeから近いOriginにアクセスすることでレイテンシを短くする施策を取ることがある(もちろんDisaster Recovery目的に活用する可能性もある)。その場合、次のような方策も考えられる。
[1] API Managementのマルチリージョンデプロイを使う
API Managementをマルチリージョンにデプロイすると、API Gateway機能が複数のリージョンにデプロイされる(管理サービスはプライマリリージョンにのみ存在)。
複数の Azure リージョンに Azure API Management サービス インスタンスをデプロイする方法 / Deploy an Azure API Management instance to multiple Azure regions
https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region
以下の引用の通り、プライマリゲートウェイエンドポイントにはTraffic Managerに相当する機能があるので、待機時間が最短になり得るリージョンゲートウェイにリクエストをルーティングしてくれる。
API Management がプライマリ ゲートウェイ エンドポイントへのパブリック HTTP 要求を受信すると、最も短い待機時間に基づいてリージョン ゲートウェイにトラフィックがルーティングされるため、地理的に分散された API コンシューマーによって発生する待機時間が短縮されます。
https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region#about-multi-region-deployment
ただ、Premium SKU一択なので、お財布に優しくない(これが一番大きいかも)。さらに、リージョン内のバックエンドサービスを呼び出すように構成しておく必要がある。
既定では、各 API によって、1 つのバックエンド サービスの URL に要求がルーティングされます。 複数のリージョンに Azure API Management ゲートウェイを構成した場合でも、API ゲートウェイは、1 つのリージョンのみにデプロイされる同じバックエンド サービスに要求を転送します。 この場合、要求に固有のリージョンで Azure API Management 内にキャッシュされた応答でのみパフォーマンスが向上し、グローバルなバックエンドへの接続では引き続き長い待ち時間が発生します。
システムの地理的な分散を活用するには、Azure API Management インスタンスと同じリージョンにバックエンド サービスをデプロイする必要があります。 その後、ポリシーと
リージョンのバックエンド サービスに API 呼び出しをルーティングする / Route API calls to regional backend services@(context.Deployment.Region)
プロパティを使用して、バックエンドのローカル インスタンスにトラフィックをルーティングできます。
https://learn.microsoft.com/azure/api-management/api-management-howto-deploy-multi-region#-route-api-calls-to-regional-backend-services
[2] Basic/Standard SKUのAPI Managementを使う
Premium SKUだと予算に合わないということであれば、[1]を少々変更し、各リージョンのAPI Managementの前段にFront DoorもしくはTraffic Managerを配置して、トラフィックを分散させることも可能。
閉域化したい場合はどうすればいい?
ここまでの内容は特にVNetに閉じ込めることを意識していない。もし閉域化が必須であれば以下のようなパターンが考えられる。
[1]-a Global load balancerの振り分け先でVNetに入る (Application Gateway)
Front DoorもしくはTraffic Managerがリクエストを振り分ける先のApplication Gateway(Publicエンドポイントを公開)でVNetに入る、という構成。この絵ではApplication Gatewayを2個配置しているようにみえるが、実際には1個のApplication GatewayでPublic用とPrivate用のエンドポイントをホストできる。
現時点で残念なのは、Front DoorとApplication Gateway間はPrivate Linkで接続できないこと。これができると、Front DoorからVNetに入り、かつApplication GatewayにPublic IPを割り当てる必要がなくなる点で、よりセキュアではあるのだが…。
なお、API ManagementはPremium、もしくはv2 Standard (Preview) 。v2は現時点ではリージョンも限定されているため、実運用を考慮するとPremium一択である点には変わりなく、一番ゴージャスな構成である(お財布に優しくない)。
[1]-b Global load balancerの振り分け先でVNetに入る (API Management)
Front DoorでWAFも動作させるから、API Managementの前段にApplication Gatewayを配置せず、API ManagementでVNetに入る、という場合がこちら。
API ManagementはPremium、もしくはv2 Standard (Preview) 。[1]-aでも記載した通り、事実上Premium一択である点には変わりなく、そこそこゴージャスな構成である。
[2]-a API ManagementのバックエンドでVNetに入る
API Managementは最小限のコストで抑えたい、というのであれば、バックエンドサービスの負荷分散を司るApplication GatewayでVNetに入る、という選択肢も検討対象になるだろう。この場合、API ManagementはStandard/Basicも利用できる。ただ、Application GatewayでAPI Managementから到達するリクエストのみを拾うよう、Front DoorがHTTP Headerに付加するX-Azure-FDID
のようなものを使うとか、IPアドレスでフィルタリングする、といった設定が必要になる。
[2]-b API ManagementのバックエンドでVNetに入る (v2 Standardの利用)
現在Preview中のAPI Management v2 StandardはVNet統合が可能になっているので、Application Gatewayを挟まなくても、API Managementから直接VNetに接続できる。
ただ、まだPreviewなのと、日本リージョンはPreview提供リージョンではなく、機能制限もある点に注意が必要。詳細は以下を参照。
新しい Azure API Management レベル (プレビュー) / New Azure API Management tiers (preview)
https://learn.microsoft.com/azure/api-management/v2-service-tiers-overview
[3] オンプレミスからの接続
最後にAOAIをオンプレミスネットワークからセキュアに利用する場合のトポロジー例。Azureの入口がExpressRoute(もしくはVPN)になるだけで、[1]-aもしくはbの構成と同等であることがわかる。[1]-aおよびbと同様、この構成ではAPI ManagementのPremium SKU(もしくはv2 Standard)が必要。この例ではApp Serviceを含めているが、見慣れたトポロジーであることには変わりない。