Service Fabric での拡大縮小

Azure Service Fabric では、クラスター内のノードでサービス、パーティション、およびレプリカを管理することにより、スケーラブルなアプリケーションを簡単に構築できます。 同じハードウェアで多くのワークロードを実行することで、リソースを最大限に活用すると同時に、ワークロードを拡大縮小する方法も柔軟に選択できます。 この Channel 9 ビデオでは、スケーラブルなマイクロサービス アプリケーションを構築する方法について説明します。

Service Fabric は、さまざまな方法で拡大縮小できます。

  1. ステートレス サービス インスタンスの作成または削除による拡大縮小
  2. 新しい名前付きサービスの作成または削除による拡大縮小
  3. 新しい名前付きアプリケーション インスタンスの作成または削除による拡大縮小
  4. パーティション分割されたサービスの使用による拡大縮小
  5. クラスターのノードの追加または削除による拡大縮小
  6. Cluster Resource Manager のメトリックを使用した拡大縮小

ステートレス サービス インスタンスの作成または削除による拡大縮小

Service Fabric で拡大縮小を行う最も簡単な方法の 1 つが、ステートレス サービスを使用するものです。 ステートレス サービスを作成するときに、InstanceCount を定義することができます。 InstanceCount は、サービスの起動時に作成されるそのサービス コードの、実行中のコピーの数を定義します。 たとえば、クラスターに 100 個のノードがあるとします。 また、サービスを 10 の InstanceCount で作成するとします。 実行時、この 10 個の実行中のコード コピーすべてがビジー状態になる (または、ビジー状態でないが、十分とは言えない) 可能性があります。 ワークロードを拡大縮小するには、1 つの方法として、インスタンスの数を変更します。 たとえば、監視または管理コードを使用して、負荷に基づきワークロードをスケールインするかスケールアウトするかに応じて、既存のインスタンス数を 50 または 5 に変更できます。

C#:

StatelessServiceUpdateDescription updateDescription = new StatelessServiceUpdateDescription(); 
updateDescription.InstanceCount = 50;
await fabricClient.ServiceManager.UpdateServiceAsync(new Uri("fabric:/app/service"), updateDescription);

PowerShell:

Update-ServiceFabricService -Stateless -ServiceName $serviceName -InstanceCount 50

動的なインスタンス数の使用

特にステートレス サービスについては、Service Fabric には、インスタンス数を自動的に変更する方法が用意されています。 これにより、使用可能なノード数に合わせて、サービスを動的に拡大縮小することができます。 このビヘイビアーを有効にする方法は、インスタンス数を -1 に設定します。 InstanceCount = -1 は Service Fabric に対する命令で、"各ノードでこのステートレス サービスを実行する" ように指示します。ノード数が変更されると、その変更に合わせてインスタンス数が自動的に変更され、サービスは有効なすべてのノードで確実に実行されます。

C#:

StatelessServiceDescription serviceDescription = new StatelessServiceDescription();
//Set other service properties necessary for creation....
serviceDescription.InstanceCount = -1;
await fc.ServiceManager.CreateServiceAsync(serviceDescription);

PowerShell:

New-ServiceFabricService -ApplicationName $applicationName -ServiceName $serviceName -ServiceTypeName $serviceTypeName -Stateless -PartitionSchemeSingleton -InstanceCount "-1"

新しい名前付きサービスの作成または削除による拡大縮小

名前付きサービス インスタンスとは、クラスター内の一部の名前付きアプリケーション インスタンスにある、特別な種類のサービス インスタンスです (「Service Fabric アプリケーション ライフサイクル」を参照)。

サービスのビジー状態が変わると、新しい名前付きサービス インスタンスを作成 (または削除) できます。 これにより、さらに多くのサービス インスタンスに要求を分散し、多くの場合、既存のサービスへの負荷を軽減できます。 サービスを作成するとき、Service Fabric Cluster Resource Manager は、サービスをクラスターに分散させて配置します。 細かなことは、クラスター内のメトリックとその他の配置ルールによって決まります。 サービスを作成する方法は複数ありますが、最も一般的なのは管理アクションを使用する方法で、ユーザーが New-ServiceFabricService を呼び出すか、コードで CreateServiceAsync を呼び出します。 CreateServiceAsync は、クラスターで実行されている他のサービス内から呼び出すこともできます。

サービスの動的作成は、あらゆる種類のシナリオで使用できる一般的なパターンです。 たとえば、特定のワークフローを表すステートフル サービスについて考えてみます。 この作業を表す呼び出しはこのサービスに提示され、サービスは、そのワークフローへの手順を実行し、進捗状況を記録します。

この特別なサービスではどのように拡大縮小が行われるのでしょうか。 サービスはある種のマルチテナントであり、同じワークフローのさまざまなインスタンスについて、一度に呼び出しを受け入れ、手順を開始できます。 しかし、これによりコードが複雑になります。同じワークフローの多数の異なるインスタンスについて考慮する必要があり、しかも、そのインスタンスはすべて、段階も顧客もさまざまであるためです。 さらに、複数のワークフローを同時に処理しても、拡大縮小の問題は解決されません。 このサービスでは、一時的に過剰にリソースが使用されるため、特定のマシンでは対応できないからです。 また、第一にこのパターンに合わせて設計されていない多くのサービスが、コード自体のボトルネックや速度低下が原因で困難にぶつかります。 サービスが追跡している同時ワークフローの数が多くなると、こうした問題によりサービスも動作しなくなります。

これを解決するには、追跡するワークフローのインスタンスすべてについて、このサービスのインスタンスをそれぞれ作成します。このパターンは優れており、サービスがステートレスかステートフルかに関係なく機能します。 このパターンを機能させるために、"Workload Manager Service" として動作する別のサービスがあります。 このサービスのジョブは、要求を受信し、その要求を他のサービスにルーティングすることです。 メッセージを受信したマネージャーは、ワークロード サービスのインスタンスを動的に作成し、そのサービスに要求を渡します。 また、マネージャー サービスは、指定したワークフロー サービスがジョブが完了したときに、コールバックを受け取ることもできます。 このコールバックを受信したマネージャーは、ワークフロー サービスの当該インスタンスを削除できます。さらに呼び出しが予想される場合は、そのままにしておくこともできます。

この種の高度なバージョンのマネージャーは、管理対象のサービスのプールを作成できます。 このプールにより、新しい要求を受け取ったときに、サービスが開始するのを待つ必要がなくなります。 代わりに、マネージャーは、ビジー状態でないワークフロー サービスをプールから取得するか、ランダムにルーティングできます。 サービスのプールを常に使用可能にしておくと、新しい要求は新しいサービスが開始するのを待つことが少なくなるため、要求の処理がさらに速くなります。 新しいサービスをすばやく作成することはできますが、無料ではありません。また、瞬時には作成されません。 プールは、要求が処理されるまでの待機時間を最小限に抑えるのに役立ちます。 このマネージャーとプールのパターンは、応答時間が重要な場合によく使用されます。 また、バックグラウンドで要求をキューに格納してからサービスを作成し、"その後に" 渡す方法も一般的なマネージャー パターンで、サービスで現在保留になっている作業量追跡に基づいて、サービスが作成または削除されます。

新しい名前付きアプリケーション インスタンスの作成または削除による拡大縮小

アプリケーション インスタンス全体の作成と削除は、サービスの作成と削除のパターンに似ています。 このパターンでは、マネージャー サービスが、追跡している要求と、クラスター内の別のサービスから受け取った情報に基づいて決定を行います。

既存のアプリケーションに新しい名前付きサービス インスタンスを作成するのではなく、新しい名前付きアプリケーション インスタンスを作成するのは、どのような場合でしょうか。 こうした状況はいくつかあります。

  • 新しいアプリケーション インスタンスが、特定の ID またはセキュリティ設定で実行する必要があるコードを使用している顧客を対象としている。
    • Service Fabric では、さまざまなコード パッケージを、特定の ID で実行できるように定義できます。 異なる ID で同じコード パッケージを起動するには、異なるアプリケーション インスタンスでアクティブ化する必要があります。 既存の顧客のワークロードがデプロイされている場合を考えてみましょう。 こうしたワークロードは、リモート データベース、その他のシステムなど、他のリソースへのアクセスを監視および制御できるように、特定の ID で実行されている場合があります。 この場合、新しい顧客がサインアップしたときに、同じコンテキスト (プロセス空間) でコードをアクティブ化することは避けたいと思うでしょう。 同じコンテキストでのアクティブ化は不可能ではありませんが、これにより、サービス コードが、特定の ID のコンテキストで動作するのがさらに困難になります。 通常、追加のセキュリティ、分離性、および ID 管理コードが必要になります。 同じアプリケーション インスタンス、つまり同じプロセス空間内で異なる名前付きサービス インスタンスを使用するのではなく、異なる名前付き Service Fabric アプリケーション インスタンスを使用できます。 これによって、異なる ID コンテキストを定義するのが簡単になります。
  • 新しいアプリケーション インスタンスが構成手段としても機能する
    • 既定では、アプリケーション インスタンス内にある、特定のサービスの種類である名前付きサービス インスタンスはすべて、指定されたノードの同じプロセスで実行されます。 つまり、各サービス インスタンスは異なる方法で構成できますが、その方法は複雑です。 サービスには、構成パッケージ内での構成の検索に使用するトークンが必要です。 通常、これは単なるサービスの名前です。 これでも正常に機能しますが、構成は、そのアプリケーション インスタンス内にある個別の名前付きサービス インスタンスの名前に関連付けられています。 これが紛らわしく、管理しずらい可能性があります。構成は、通常、デザイン時の成果物であり、アプリケーション インスタンス固有の値を持っているからです。 他のサービスを作成するということは、アプリケーションをアップグレードして、構成パッケージ内の情報を変更するか、新しいものをデプロイして、新しいサービスが特定の情報を検索できるようにすることです。 多くの場合、まったく新しい名前付きアプリケーション インスタンスを作成する方が簡単です。 アプリケーション パラメーターを使用すると、サービスに必要なすべての構成を設定することができます。 このようにして、名前付きアプリケーション インスタンス内で作成されたサービスはすべて、特定の構成設定を継承できます。 たとえば、シークレットや顧客ごとのリソース制限など、すべての顧客の設定とカスタマイズが含まれる 1 つの構成ファイルではなく、こうした設定がオーバーライドされた、顧客ごとに異なるアプリケーション インスタンスを使用できます。
  • 新しいアプリケーションがアップグレード境界として機能する
    • Service Fabric 内では、さまざまな名前付きアプリケーション インスタンスが、アップグレードの境界として機能します。 ある名前付きアプリケーション インスタンスのアップグレードが、別の名前付きアプリケーション インスタンスによって実行されているコードに影響を及ぼすことはありません。 アプリケーションが異なる場合、実行されるのは、同じノード上の同じコードの異なるバージョンになります。 新しいコードが他のサービスと同じアップグレードに従うようにするかどうかを選択できるため、拡大縮小の決定を行う必要がある場合は、これが決め手になります。 たとえば、サービスを動的に作成および削除することで特定の顧客のワークロードを拡大縮小するマネージャー サービスへの呼び出しがあったとします。 ただし、この場合、呼び出しは、"新しい" 顧客に関連付けられているワークロードを対象としています。 顧客が相互に切り離されていることを望む理由は、既に説明したセキュリティおよび構成のためだけではありません。切り離すことで、特定バージョンのソフトウェアの実行や、アップグレードのタイミングの選択に関して、柔軟性を高めることもできるからです。 また、新しいアプリケーション インスタンスを作成し、そこでサービスを作成して、いずれかのアップグレードが影響を及ぼすサービスの量をさらに分割できる場合もあります。 個別のアプリケーション インスタンスにより、アプリケーションのアップグレード時の細分性を高め、さらに A/B テストや Blue/Green デプロイを実施することもできます。
  • 既存のアプリケーション インスタンスがフルである
    • Service Fabric では、アプリケーション容量は、特定のアプリケーション インスタンスで使用できるリソース量を制御するための概念です。 たとえば、拡大縮小のために、指定されたサービスで別のインスタンスを作成する必要があるとします。 ただし、このアプリケーション インスタンスは、特定のメトリックについて容量が不足しています。 この特定の顧客またはワークロードにリソース追加の権限が付与されている場合は、そのアプリケーションの既存の容量を増やすか、新しいアプリケーションを作成することができます。

パーティション レベルでのスケーリング

Service Fabric はパーティション分割をサポートしています。 パーティション分割により、サービスが、それぞれが独立して動作する複数の論理セクションと物理セクションに分割されます。 これはステートフル サービスで役に立ちます。どのレプリカ セットも、一度にすべての呼び出しを処理したり、すべての状態を操作したりする必要がなくなるためです。 「 パーティション分割の概要 」では、サポートされているパーティション構成の種類に関する情報を提供します。 各パーティションのレプリカが、クラスター内のノードに分散されます。これにより、サービスの負荷が分散され、サービス全体にもパーティションにも単一障害点がなくなります。

ここでは、範囲指定されたパーティション分割構成をあるサービスに使用し、低値キーを 0、高値キーを 99、パーティション数を 4 とした場合について考えてみましょう。 3 ノード クラスターでは、サービスを次に示すように、各ノード上のリソースを共有する 4 つのレプリカでレイアウトする可能性があります。

3 つのノードを使用したパーティション レイアウト

ノード数を増やすと、Service Fabric は既存のレプリカの一部をそこに移動します。 たとえば、ノード数を 4 つに増やし、レプリカを再分散させるとします。 サービスでは各ノードで 3 つのレプリカが実行され、それぞれが異なるパーティションに属しています。 新しいノードはコールドでないため、リソースの使用率が向上します。 通常は、各サービスで使用できるリソースが増えるため、パフォーマンスも向上します。

4 つのノードを使用したパーティション レイアウト

Service Fabric Cluster Resource Manager とメトリックの使用による拡大縮小

サービスは、メトリックによって Service Fabric にリソース使用量を伝えます。 メトリックを使用することで、Cluster Resource Manager は、クラスターのレイアウトを再構成および最適化できます。 たとえば、たくさんのリソースがクラスターにあるのに、そのリソースが、現在稼働しているサービスに割り当てられていない場合があります。 メトリックを使用すると、利用可能なリソースにサービスが確実にアクセスできるように、Cluster Resource Manager がクラスターを再編成できます。

クラスターのノードの追加または削除による拡大縮小

Service Fabric には、クラスターのサイズを変更して拡大縮小するオプションも用意されています。 クラスターのサイズを変更するということは、クラスターにある 1 つ以上のノード タイプのノードを追加または削除することです。 たとえば、クラスターのすべてのノードがホットである場合を考えます。 つまり、クラスターのリソースのほぼすべてが使用されています。 この場合は、最善の方法として、クラスターにノードを追加して拡大することをお勧めします。 新しいノードがクラスターに参加すると、Service Fabric Cluster Resource Manager は、サービスをそのノードに移動するため、既存のノードの合計負荷が軽減されます。 インスタンス数が -1 に設定されているステートレス サービスについては、サービス インスタンスが自動的に作成されます。 これにより、一部の呼び出しが、既存のノードから新しいノードに移動できます。

詳細については、 クラスター スケーリングに関するセクションを参照してください。

プラットフォームの選択

オペレーティング システムによって実装が異なることから、Service Fabric と共に Windows を使用するか、Linux を使用するかという選択はアプリケーションのスケーリングにおいて非常に重要な部分を占めることがあります。 潜在的な障壁の 1 つに、段階的なログの記録方法があります。 Windows 上の Service Fabric では、コンピューターごとに 1 つのログについてカーネル ドライバーが使用されます。このログは、ステートフル サービス レプリカ間で共有されます。 このログの容量は約 8 GB です。 一方、Linux の場合、レプリカごとに 256 MB のステージング ログが使用されます。特定のノードで実行される軽量サービスの数を最大化するアプリケーションの場合、最適ではありません。 Service Fabric クラスター デプロイで最適なプラットフォームは、一時的ストレージ要件におけるこのような違いからわかることもあります。

まとめ

それでは、ここまでに説明した内容を、例を挙げながらまとめてみてみましょう。 次のサービスについて考えてみてください。あなたは、名前情報や連絡先情報を保持できる、アドレス帳のサービスを構築しようとしています。

まずは、スケールに関する質問が山ほどあります。ユーザー数がどれくらいになるかや、 各ユーザーの連絡先がどれくらいになるのかなど、 サービスの立ち上げにあたって必要な情報をすべて確認することは大変です。 たとえば、1 つ静的サービスをパーティション数を指定して使用するとします。 パーティション数を間違ったりすると、後でスケーリングの問題が生じる可能性があります。 また、正しい数がわかったとしても、必要な情報がすべてあるとは限りません。 たとえば、ノード数とサイズの両方の観点から、クラスターのサイズを事前に決定する必要もあります。 通常、サービスがその有効期間にわたってどのくらいのリソースを使用するかを予測するのは困難です。 サービスの実際のトラフィック パターンを前もって知ることも大変です。 たとえば、連絡先の追加と削除を朝一番にしか行わない人がいれば、1 日にわたって行う人もいます。 したがって、スケールアウトとスケールインは、動的でなければならない可能性があります。 スケールアウトとスケールインのタイミングは予測できるようになるかもしれませんが、いずれにしても、サービスによるリソース使用量の変化に対処する必要があります。 たとえば、既存のリソースの使用を再編成するだけでは不十分なときは、さらにリソースを提供するために、クラスターのサイズを変更する必要があります。

だからと言って、すべてのユーザーに 1 つのパーティション構成を当てはめるのは合理的ではありません。 1 つのサービス、そして 1 つの静的クラスターに縛られる理由はありません。 現実は、大抵、もっと動的なものです。

拡大縮小に対応するには、次のような動的なパターンを検討してください。 このパターンは、ご自身の状況に合わせて適宜変更してください。

  1. すべてのユーザーにあらかじめパーティション構成を選択するのではなく、"マネージャー サービス" を構築するのです。
  2. このマネージャー サービスの役割は、サービスへのサインアップ時に顧客情報を確認することです。 その後、その情報に応じて、マネージャー サービスによって、"その顧客専用" の "実際の" contact-storage サービスのインスタンスが作成されます。 特定の構成、分離性、またはアップグレードが必要な場合は、この顧客に対してアプリケーション インスタンスを開始することもできます。

この動的作成パターンには、さまざまな利点があります。

  • すべてのユーザーについて、適切なパーティション数を事前に推測する必要はなく、無限に自動拡張されるスケーラブルな 1 つのサービスの作成も不要です。
  • ユーザーごとに、同じパーティション数、レプリカ数、配置制約、メトリック、既定の負荷、サービス名、または DNS 設定を使用する必要がありません。サービス レベルまたはアプリケーション レベルで指定された、その他のプロパティも同じである必要はありません。
  • データをさらにセグメント化できます。 それぞれの顧客に専用のサービス コピーが作成されます
    • 顧客サービスごとに異なる構成を適用し、許可するリソース数を調整できます。また、予想されるスケールに基づいて、パーティションやレプリカの数を増減できます。
      • たとえば、"Gold" レベルの料金を支払った顧客については、メトリックやアプリケーション容量によって、レプリカやパーティション、場合によっては、サービス専用のリソースを増やすことができます。
      • 提供された情報で、必要な連絡先の数が "Small" と指定されていた場合は、パーティション数を少なくできます。また、他の顧客との共有サービス プールに配置することもできます。
  • 顧客がサインアップする前に、多数のサービス インスタンスやレプリカを実行する必要がありません
  • 顧客がサービスの利用をやめる際は、作成したサービスまたはアプリケーションをマネージャーで削除するだけなので、サービスの情報削除も簡単です。

次のステップ

Service Fabric の概念について詳しくは、次の記事をご覧ください。