オンデマンドスケーリング:サーバーレスがトラフィックスパイクを簡単に処理する方法

オンデマンドスケーリング:サーバーレスがトラフィックスパイクを簡単に処理する方法

前回の記事では、Serverlessの2つのプロセスモデル、run-to-completionと長時間実行プロセスについて説明しました。これらのモデルの主な違いは、関数インスタンスが実行直後に終了するかどうかにあります。さらに、データオーケストレーションとサービスオーケストレーションの2つのシナリオについても考察しました。

これらのシナリオを長時間実行プロセスで実装できるのではないかと疑問に思うかもしれません。答えは「はい」ですが、run-to-completionがServerlessの最も純粋な形態であることに留意することが重要です。では、その根底にあるロジックは何でしょうか?

これを完全に理解するには、複雑なインターネットアプリケーションアーキテクチャの進化における重要な概念、すなわちスケーリングを導入する必要があります。この記事の焦点はここにあります。

あなたがローカルで開発したWebアプリケーションのindex.htmlホームページに200人のユーザーが同時にアクセスしたと想像してください。あなたのローカルWebサーバーインスタンスはどうなるでしょうか?

あなたのPCの状態を説明しましょう。まず、クライアントとあなたのPCの間に200のTCP/IP接続が確立されますが、これは辛うじて処理可能です。次に、200人のクライアント全員が同時にHTTP「GET/」リクエストを開始します。あなたのWebサーバーのメインプロセスは、「CPUコア数-1」の子プロセスを同時に生成してこれらのリクエストを処理します。メインプロセス用に1つ予約するため、CPUコア数から1を引いていることに注意してください。

例えば、4コアCPUでは3つの子プロセスが生成され、3つのクライアントリクエストを同時に処理し、残りのリクエストはキューに入れられます。子プロセスは「GET/」リクエストの処理を開始し、ルーティングルールに一致し、対応する制御関数に入り、index.htmlをクライアントに返します。子プロセスがindex.htmlファイルを送信すると、メインプロセスはそれを再利用し、新しい子プロセスを生成して次のリクエストを処理します。すべてのリクエストが処理されるまでこれが続きます。

これを理解すれば、次の質問は簡単です。クライアントキューの処理速度をどのように向上させるのでしょうか?

垂直スケーリング vs. 水平スケーリング

明白な解決策は、CPUコア数を増やすことです。これは、シングルマシンの構成を4コアから8コアにアップグレードすることで実現でき、その結果、7つの同時子プロセスが可能になります。

CPUコアを直接増やすだけでなく、マシン(それぞれ4コア)を追加することもできます。500人のクライアントを2台のマシンに分散することで、同時子プロセス数を6に増やすこともできます。

シングルマシンのパフォーマンスを増減させることは垂直スケーリングであり、パフォーマンスが向上するにつれてコスト曲線が急峻になることがよくあります。したがって、このアプローチを採用する際には慎重な検討が必要です。一方、マシンの台数を増減させることは水平スケーリングであり、より費用対効果の高いアプローチであり、デフォルトのスケーリング方法です。

ここで、もう少し複雑さを加えましょう。index.htmlは単一のファイルですが、データはどうでしょうか?垂直スケーリングでも水平スケーリングでも、マシンを再起動する必要があります。ToDoリストの例では、データはメモリに保存されており、再起動するたびにリセットされます。では、スケーリング中にデータを保持するにはどうすればよいでしょうか?

ステートフル vs. ステートレス

ネットワークトポロジのノードは、状態を保存するかどうかに基づいて、ステートフルまたはステートレスに分類できます。ステートフルノードは状態を保持する、つまりデータを保存します。そのため、追加の注意が必要であり、安定性が要求され、頻繁な変更に耐える必要があります。例えば、データベースは通常、マスタースレーブ構造を採用しており、マスターノードに問題が発生した場合でも即座にスレーブノードに切り替えることができ、サービスの継続的な可用性を確保します。

一方、ステートレスノードは状態を保存しないか、一時的に信頼性の低いデータのみを保持します。状態がないため、ステートレスノードは高同時実行性を処理するために水平スケーリングでき、トラフィックがない場合はゼロまでスケールダウンできます(おなじみですね?)。しかし、ステートフルノードはこれができません。ピーク時とオフピーク時のトラフィック変動が大きいシナリオでは、ステートフルノードを設計してピークトラフィックを処理しつつ、低トラフィック時でも運用コストを維持する必要があります。

データベースは、ユーザーのToDoタスクを永続的に保存するため、典型的なステートフルノードです。同様に、ロードバランサーもステートフルであり、私たちの思考実験でクライアントキューを維持するメインプロセスとよく似ています。Webアプリケーションが処理した結果をクライアントに返すために、クライアント接続を保存する必要があります。

プロセスモデルに戻ると、run-to-completionは本質的にステートレスであり、実行後に終了するため、それだけでは永続的なデータ保存に使用できません。長時間実行プロセスは、メインプロセスが終了しないため、本質的にステートフルであり、いくつかの値を保存できます。

しかし、Serverlessでは、長時間実行プロセスのメインプロセスに値を保存しても、クラウドプロバイダーがそれを回収する可能性があります。予約インスタンスを使用した場合でも、スケールアウトされたノードのメモリ内のデータは隔離されたままです。

したがって、長時間実行プロセスをステートレスにするには、メインプロセスに値を保存しないか、一時変数のみを保存する必要があります。永続データは、データベースのような専用のステートフルノードに移動する必要があります。

データストレージをメインプロセスノードから分離し、メインプロセスがデータを保持しないようにすることで、アプリケーションはステートレスになります。データは別のステートフルなデータベースノードに保存します。この例は、前回の記事で説明した長時間実行Serverlessシナリオに変換されます。このシナリオでは、メインプロセスの起動中にデータベースに接続し、子プロセスを介してデータにアクセスします。ただし、このアプローチには重大な欠点があります。コールドスタート時間が直接増加することです。より良い解決策はあるでしょうか?

データ永続化への別のアプローチを考えてみましょう。なぜ自分たちでデータベースに接続する必要があるのでしょうか?データに対するCRUD(作成、読み取り、更新、削除)操作は、基本的に、子プロセスがメインプロセスによって確立されたTCP接続を再利用し、データベースステートメントを送信してデータを取得することです。もし、HTTPリクエスト(POST、DELETE、PUT、GET)を使用してデータベースに命令を送信できるとしたらどうでしょうか?そうすれば、前回のレッスンで学んだデータオーケストレーションとサービスオーケストレーションの概念を活用できるのではないでしょうか?

BaaSとは

実際、ここまでの準備はすべて、今日の主役であるBaaS化につながっています。データインターフェース操作のPOST、DELETE、PUT、GETは、RESTful APIのセマンティックHTTPメソッドに対応しています。MySQLを例にとると、POSTはCREATEコマンド、DELETEはDELETE、PUTはUPDATE、GETはSELECTに対応します。このセマンティックな1対1の対応により、MySQL操作をRESTful API操作に自然に変換できます。

従来のデータベースアプローチは、TCP接続の再利用と通信オーバーヘッドの低さから、同じ操作でもHTTPと比較して高速です。Serverlessはデータベースに直接接続できますが、VPCセグメンテーションが存在するクラウド環境では、IPアドレスを使用して従来のデータベースに接続することはしばしば困難です。したがって、Serverlessのデータベース接続では、通常、クラウドプロバイダーが提供するBaaSサービスに依存しますが、多くのBaaSサービスはまだ成熟していません。

さらに一歩進んで、Serverlessがステートフルノードに適さないのであれば、すべてのステートフル操作をデータインターフェースとして外部化してみてはどうでしょうか?これにより、Serverless関数は前回のレッスンで説明したデータオーケストレーションアプローチを活用し、自由にスケーリングできるようになります。

まとめ

run-to-completionモデルが長時間実行プロセスモデルよりも純粋であると考えられる理由は、後者が誤解を招きやすく、PaaSのように扱い、永続的なデータ保存のためのステートフルノードとして使用したくなる誘惑にかられるためです。しかし、Serverlessでは、長時間実行プロセスであっても、クラウドプロバイダーが関数インスタンスを回収する可能性があります。

メモリにデータを保存すると再起動のたびにリセットされてしまう例で見たように、データオーケストレーションの考え方を採用し、バックエンドデータベース操作をデータインターフェースに変換することで、Serverlessでのデータ保存をバックエンドアプリケーションにオフロードし、前回のレッスンで説明したデータオーケストレーションを使用してそれらと対話できます。ただし、バックエンドアプリケーション用のデータインターフェースを作成するだけでは不十分です。BaaS化を受け入れ、バックエンドエンジニアが開発中にサーバー側の運用上の懸念から解放されるようにする必要があります。

スケーリングに関しては、垂直スケーリングと水平スケーリングのどちらかを選択できます。垂直スケーリングはシングルマシンのパフォーマンス向上に焦点を当てていますが、コストの急激な増加を伴うことが多く、慎重な選択が必要です。水平スケーリングはマシンの台数を増やすことであり、より緩やかなコスト曲線を提供し、デフォルトのスケーリング方法です。

ステートフルノードはデータを保存し、ステートレスノードはデータを保持せずに処理します。自由にスケーリングできるのはステートレスノードだけです。重要なデータの保存を担当するステートフルノードは、注意深い取り扱いが必要です。ネットワークトポロジのノードを自由にスケーリングできるようにするには、そのデータ操作を専用のステートフルノードに外部化する必要があります。

Serverless関数がステートフルノードにアクセスする場合、データベースコマンドのみに依存するのではなく、これらのノードがデータインターフェースを提供することが望ましいです。データベース接続はServerless関数に追加のオーバーヘッドをもたらすからです。さらに、バックエンドエンジニアの開発を簡素化するために、ステートフルノードのBaaS化に努めるべきです。BaaS化については、後続の記事で詳しく掘り下げます。

Novita AI は、AIの野望を実現するオールインワンのクラウドプラットフォームです。統合API、サーバーレス、GPUインスタンス——コスト効率の高いツールを提供します。インフラストラクチャを排除し、無料で始めて、AIのビジョンを現実にしましょう。

おすすめの記事

変革のベールを剥ぐ:サーバーレスコンピューティングの世界を探る

サーバーレス分析、データモデルから始める