高性能外部関数の設計

このトピックでは、非同期外部関数の使用に関する情報を含む、外部関数の並行性、信頼性、およびスケーラビリティに関する情報を提供します。

このトピックの内容:

非同期リモートサービス対同期リモートサービス

リモートサービスは、同期的または非同期的に操作できます。

同期:

同期リモートサービスへの呼び出しは、ブロッキング呼び出しです。リモートサービスは、結果の準備ができるまで応答を送信しません。サービスはポーリングできません。

同期コードは、非同期コードよりも実装が簡単です。

非同期:

呼び出し元が結果を待つ間、非同期リモートサービスをポーリングできます。

非同期処理により、タイムアウトに対する感度は低下します。

非同期サービスの詳細については、Microsoftの 非同期要求-応答パターン の説明をご参照ください。(情報はMicrosoft Azureに限定されない。)

同期リモートサービスは HTTP POST リクエストを受信して処理し、結果を返します。データの処理にかかる時間によっては、リクエストが受信されてから結果が返されるまでに大幅な遅延が発生する可能性があります。

非同期リモートサービスは HTTP POST リクエストを受信し、リクエストが受信されたという確認応答を(通常はほぼ即時に)返します。次に、呼び出し元(Snowflake)は、1つ以上の HTTP GET リクエストを発行するポーリングループを実行し(通常、各リクエスト間に大幅な遅延あり)、非同期処理のステータスを確認します。GET はリクエスト本文でデータを送信しませんが、元の POST と同じヘッダーを含みます。

非同期リモートサービスは、リモートサービスが、プロキシサービスなど(例: Amazon API Gateway)のコンポーネントに組み込まれているタイムアウトを超えた場合に役立ちます。

リモートサービスは、必ずしも完全に同期または非同期である必要はありません。リモートサービスは、リクエスト内のデータの量、処理されている他のリクエストの数などの要因に応じて、異なる時間に同期および非同期で動作できます。

Snowflakeの外部関数の実装は、通常、同期および非同期の両方のサードパーティ関数ライブラリと互換性があります。

次の図は、同期処理と非同期処理を対比しています。上のパスは同期しています。下のパス(1つ以上の HTTP GET リクエストを含む)は非同期です。

非同期外部関数の HTTP POST および GET リクエストの図解。

同期および非同期の外部関数の例を表示するには、 Snowflakeサンプル関数 をご参照ください。

同期リモートサービス

ユーザーが外部関数を呼び出す前に、開発者とSnowflakeアカウント管理者は、プロキシサービスにアクセスするためにSnowflakeを構成する必要があります。通常、ステップはおおよそ以下の順序で実行されます(上の図の右側から開始して、Snowflakeに向かって左側に移動)。

  1. 開発者はリモートサービスを記述し、 HTTPS プロキシサービスを介してそのリモートサービスを公開する必要があります。たとえば、リモートサービスは、 AWS Lambdaで実行され、Amazon API Gatewayのリソースを介して公開されるPython関数である場合があります。

  2. Snowflakeでは、 ACCOUNTADMIN または CREATE INTEGRATION 権限を持つロールにより、Snowflakeがプロキシサービスと通信できるようにする認証情報を含む「API 統合」オブジェクトを作成する必要があります。API 統合は、 SQL コマンド CREATE API INTEGRATION で作成されます。

  3. Snowflakeユーザーは、 SQL コマンド CREATE EXTERNAL FUNCTION を実行する必要があります。ユーザーは、 API 統合に対する USAGE 権限と、関数を作成するための十分な権限を持つロールを使用する必要があります。

    注釈

    CREATE EXTERNAL FUNCTION コマンドは、「Snowflakeの外部で実行される」コードをロードするという意味で、実際には外部関数を作成しません。代わりに、 CREATE EXTERNAL FUNCTION コマンドは、Snowflakeの外部で実行されるコードを 間接的に参照する データベースオブジェクトを作成します。より正確には、 CREATE EXTERNAL FUNCTION コマンドは以下を含むオブジェクトを作成します。

    • リレー機能として機能する HTTPS プロキシサービスのリソースの URL。

    • プロキシサービスへの認証に使用する API 統合の名前。

    • 事実上リモートサービスのエイリアスである名前。このエイリアスは、たとえば SELECT MyAliasForRemoteServiceXYZ(col1) ...; といった SQL コマンドで使用されます。

Snowflakeのエイリアス、 HTTPS プロキシサービスリソースの名前、およびリモートサービスの名前はすべて異なる場合があります。(ただし、3つすべてに同じ名前を使用すると、管理の簡略化が可能。)

上記のステップは外部関数を実行する最も一般的な方法ですが、いくつかのバリエーションが許可されています。例:

  • リモートサービスは、チェーンの最後のステップではない可能性があります。リモートサービスは、作業の一部を実行するためにさらに別のリモートサービスを呼び出す場合があります。

  • リモートサービスが JSON 形式のデータを受け入れずに返す場合、 HTTPS プロキシサービスのリソース(リレー関数)は、データを JSON 形式から別の形式に変換します(そして、返されたデータを JSON に変換)。

  • Snowflakeでは、リモートサービスの動作として、副作用がなく状態情報を保持しない真の関数(つまり、0以上の入力パラメーターを受け入れて出力を返すコード)とすることを推奨していますが、これは厳密な必須事項ではありません。リモートサービスは他のタスクを実行できます。たとえば、値(データの温度の読み取り値など)が危険なほど高い場合にアラートを送信します。まれに、リモートサービスが、発行されたアラートの総数などの状態情報を保持する場合があります。

非同期リモートサービス

非同期 リモートサービスは、リモートサービスがプロキシサービスなどのコンポーネントに組み込まれているタイムアウトを超えた場合に役立ちます。

非同期リモートサービスには、上記で説明したものと同じコンポーネント(クライアント、Snowflake、プロキシサービス、およびリモートサービス)、および同じ一般的な手順が含まれます。ただし、 HTTP リクエストとレスポンスの詳細は異なります。

非同期動作は、リモートサービスを作成する人(およびSnowflake)によって実装されます。SQL ステートメントは、非同期リモートサービスの場合と同期リモートサービスの場合で同じです。

独自のリモートサービスを作成していて、Snowflakeの非同期処理と互換性を持たせたい場合は、次のように動作するようにリモートサービスを作成します。

  • 最初に行の特定の バッチ の HTTP POST を受信すると、リモートサービスは HTTP コード202(「処理中...」)を返します。

  • リモートサービスが POST の後、出力の準備が整う前に HTTP GET リクエストを受信した場合、リモートサービスは HTTP コード202を返します。

  • リモートサービスは、すべての出力行を生成した後に、同じバッチ ID で次の HTTP GET を待ち、受信した行を HTTP コード200(「正常に完了しました...」)と一緒に返します。

つまり、受信したバッチごとに、リモートサービスは結果の準備ができるまで202を返し、その後、次の GET が結果と HTTP 200を受信します。

Snowflakeは、バッチごとに非同期リモートサービスと次のように連携します。

  1. Snowflakeは、処理するデータを含むHTTP POSTを、一意のバッチIDとともに送信します。

  2. SnowflakeがHTTP 202応答を受信すると、Snowflakeは次のいずれかがtrueになるまでループします。

    • SnowflakeがデータとHTTP 200を受信。

    • Snowflakeの内部タイムアウトに達する。

    • Snowflakeがエラーを受信(例: HTTP応答コード5XX)。

    ループの各反復で、Snowflakeは遅延し、対応する HTTP POST のバッチ ID と同じバッチ ID を含む HTTP GET を発行して、リモートサービスが正しいバッチの情報を返すことができるようにします。

    ループ内の遅延は最初は短く、Snowflakeのタイムアウトに達するまで、受信した HTTP 202応答ごとに長くなります。

  3. HTTP 200が返される前にSnowflakeのタイムアウトに達すると、Snowflakeは SQL クエリを中止します。

    現在、Snowflakeのタイムアウトは10分(600秒)であり、ユーザーが構成することはできません。このタイムアウトは将来変更される可能性があります。

注釈

クエリがタイムアウトに達する頻度は、リモートサービスのスケーラビリティに一部依存します。リモートサービスが頻繁にタイムアウトする場合gは、 スケーラビリティ の説明もご参照ください。

スケーラビリティ

リモートサービス、プロキシサービス、およびSnowflakeとリモートサービスの間の他のステップは、それらに送信されるピークワークロードを処理できる必要があります。

一部のクラウドプラットフォームプロバイダーには、プロキシサービスとリモートサービスのデフォルトの使用制限またはその他のクォータあり、外部関数呼び出しのスループットを制限する可能性があります。

Snowflake ウェアハウスのサイズ が大きくなるほど、リクエスト送信の同時実行が多くなり、プロキシサービスのクォータを超える可能性があります。

ユーザーは、クエリプロファイルの Retries due to transient errors の値を確認することで、Snowflakeがクエリのリクエストバッチの送信を(スロットリングまたはその他のエラーが原因で)再試行する必要があった回数を確認できます。

リモートサービスのスケーラビリティ

リモートサービスを作成する開発者は、以下を検討する必要があります。

  • リモートサービスが呼び出される頻度。

  • 呼び出しごとに送信される行数。

  • 各行の処理に必要なリソース。

  • 呼び出しの時間分布(ピーク対平均)。

発信者が、少数の開発者とテスターから組織全体に変わるにつれて、時間の経過とともに容量を増やす必要が生じる可能性があります。リモートサービスが複数の組織で使用されている場合は、組織の数が増えるにつれて容量を増やす必要が生じる場合があります。さらに、組織の数と多様性が増加するにつれて、ワークロードのサイズとタイミングを予測することがより困難になる可能性があります。

リモートサービスプロバイダーは、ピークのワークロードを処理するために十分な容量を提供する責任があります。さまざまな手法を使用してサービスをスケーリングできます。リモートサービスがリモートサービスの作成者によって管理されている場合、作成者は、ピークを処理するのに十分な容量を持つサービスを明示的にプロビジョニングする必要がある場合があります。あるいは、作成者は AWS Lambdaといった、ホストされた自動スケーリング/弾性サービスの使用を決定する場合があります。

リモートサービスは、過負荷時に HTTP 応答コード429を返す必要があります。Snowflakeが429の HTTP を検出した場合、Snowflakeは行を送信する速度を低減し、正常に処理されなかった行のバッチの送信を再試行します。

スケーラビリティの問題に関するトラブルシューティングの詳細については、 スケーラビリティとパフォーマンスの問題のトラブルシューティング をご参照ください。

システムが一般的に過負荷になっているためではなく、個々の呼び出しに時間がかかるためにリモートサービスの呼び出しがタイムアウトする場合は、 非同期リモートサービス の作成方法の説明をご覧ください。

プロキシサービスのスケーラビリティ

プロキシサービスもスケーラブルでなければなりません。幸い、主要なクラウドプロバイダーが提供するプロキシサービスは、一般にスケーラブルです。

ただし、Amazon API GatewayやAzure API Managementなどの一部のプロキシサービスには、デフォルトの使用制限があります。リクエストレートが制限を超えると、これらのプロキシサービスはリクエストをスロットルします。必要に応じて、プロキシサービスのクォータを増やすように AWS またはAzureに依頼する必要が生じる場合があります。

外部関数を開発または管理するユーザーは、次のプラットフォーム固有の情報を念頭に置く必要があります。

Amazon API Gateway:

Amazon API Gateway自体がマネージド AWS サービスであり、ユーザーのワークロードに合わせて自動スケーリングされます。ユーザーは、 API Gatewayの制限 に精通している必要があります。

Amazon API Gatewayは、リモートサービスのスケーリングに役立つように構成できます。具体的には、必要に応じてリモートサービスの負荷を軽減するため、リクエストのキャッシュやスロットリングを有効化するように API Gatewayを構成できます。

スロットルはタイムアウトと再試行に影響を与える可能性があるため、Snowflakeがタイムアウトと再試行を処理する方法に関する情報を確認する必要がある場合があります。

Azure API Managementサービス:

Azure API 管理の場合、制限はサービスに選択された SKU によって異なります。制限は、 Azureサブスクリプションサービスの制限 の API Management制限セクションに記載されています。

スロットルはタイムアウトと再試行に影響を与える可能性があるため、Snowflakeがタイムアウトと再試行を処理する方法に関する情報を確認する必要がある場合があります。

スケーラビリティとパフォーマンスの問題のトラブルシューティング

  • QUERY_HISTORY , QUERY_HISTORY_BY_* 関数を使用してパフォーマンス特性を観察し、パフォーマンスの問題のデバッグを支援します。

  • クエリプロファイルページ ページを使用して、リクエストごとに遅延の平均を確認します。

  • クエリプロファイルページ ページを使用して、 リモートサービスが各行に1回だけ渡されると思い込まない というタイトルのセクションにリストされたものを含む一時的なエラーが原因により、リクエストが再試行された回数を確認します。

  • リモートサービスのリソース使用状況をモニターして、負荷に合わせてスケーリングする方法を確認し、リモートサービスにピーク負荷に対応できる十分な容量があることを確認します。

  • Amazon API Gatewayまたはリモートサービスのロギングを利用して、リクエストごとの詳細を取得します。

  • Snowflakeがリモートサービスにリクエストを送信する際の同時実行性を制御します。詳細については、 同時実行 をご参照ください。

  • リモートサービスが過負荷状態のときに、リモートサービスから HTTP 応答コード429を返します。レイテンシが長くなるのを待つのではなく、できるだけ早くこれを返します。

  • プロキシサービスのタイムアウトを考慮してください。たとえば、2020年7月現在、Amazon API Gatewayのタイムアウトは30秒です。タイムアウトは、リモートサービスの過負荷など、さまざまな要因によって発生する可能性があります。

Snowflakeは妥当な時間内に一時的なエラー/タイムアウトを再試行しますが、サービスが引き続き過負荷になり、再試行が成功しない場合、最終的にクエリは中止されます。

同時実行

リソース要件は、行が複数の呼び出しに分散される方法に依存します(各行が数行ある多数の並列呼び出しに対し、同じ行数の1つの呼び出し)。大容量をサポートするシステムが、必ずしも高い同時実行性をサポートするわけではなく、その逆も同様です。同時実行で必要となるピークと、妥当と思われる各最大ワークロードを見積もり、両方のタイプのピークを処理するために十分なリソースを提供する必要があります。

さらに、同時実行の見積もりでは、Snowflakeが外部関数呼び出しを並列化できることを考慮に入れる必要があります。単一のユーザーからの単一のクエリにより、リモートサービスへの複数の呼び出しが並行して発生する場合があります。Snowflakeからプロキシサービスまたはリモートサービスへの同時呼び出しの数には、次のようないくつかの要因が影響します。

  • 外部関数でクエリを実行している同時ユーザーの数。

  • 各ユーザーのクエリのサイズ。

  • 仮想ウェアハウス内のコンピューティングリソースの量(つまり、 ウェアハウスサイズ)。

  • ウェアハウス の数。

外部関数に 副作用 がある場合は、同時実行を適切に処理することが特に複雑になる可能性があります。結果は、ユーザーの行が処理される順序によって異なります。(Snowflakeでは、副作用のあるリモートサービスの作成や使用を避けることを推奨。)

信頼性

リモートサービスが実行されている場所に応じて、次のことを考慮する必要があります。

  • 信頼性。

  • エラー処理。

  • デバッグ。

  • アップグレード(リモートサービスにより新機能が追加されるか、バグ修正が必要な場合)。

リモートサービスがステートレスでない場合は、障害後の回復も検討する必要があります。(Snowflakeでは、リモートサービスをステートレスにすることを強く推奨。)

タイムアウトと再試行の詳細については、 タイムアウトエラーの説明 および リモートサービスが各行に1回だけ渡されると思い込まない をご参照ください。