回復性がある Event Hubs と Azure Functions の設計

エラー処理、べき等の設計、再試行の動作の管理は、Event Hubs でトリガーされた関数が回復性を備え、大量のデータを処理できるようにするために講じることができる、いくつかの重要な手段です。 この記事では、これらの重要な概念について説明し、サーバーレスのイベントストリーミング ソリューションのための推奨事項を紹介します。

Azure には、さまざまな固有のイベントドリブン シナリオをサポートするために Azure Functions で使用できる 3 つの主要なメッセージング サービスが用意されています。 Azure Event Hubs は、パーティション分割されたコンシューマー モデルと、データを高速に取り込む能力を備えているため、イベント ストリーミングとビッグ データのシナリオでよく使用されます。 Azure メッセージング サービスの詳細な比較については、「Azure メッセージング サービスの中から選択する - Azure Event Grid、Event Hubs、および Service Bus」を参照してください。

ストリーミングの利点と課題

ストリーミングの利点と欠点を理解することは、Event Hubs のようなサービスがどのように動作するかを理解するのに役立ちます。 また、影響の大きいアーキテクチャの決定、問題のトラブルシューティング、パフォーマンスの最適化を行う場合にも、このコンテキストが必要になります。 Event Hubs と Azure Functions の両方を利用するソリューションについて、次の重要な概念を考慮してください。

  • ストリームはキューではない: Event Hubs、Kafka、およびパーティション分割されたコンシューマー モデル上に構築されたその他の同様のサービスでは、Service Bus などのメッセージ ブローカーの一部の主要な機能が本質的にサポートされていません。 おそらくこれらの違いを最もよく示しているのは、読み取りが非破壊的であるということです。 これにより、Functions ホストによって読み取られたデータは、後で引き続き使用できるようになります。 代わりに、メッセージは変更されず、他のコンシューマーが読み取ることができるままになります。同じ顧客が再度読み取る可能性もあります。 このため、競合するコンシューマーなどのパターンを実装するソリューションは、Service Bus などのメッセージ ブローカーでより適切に提供される場合があります。

  • 見つからない継承の配信不能サポート: 配信不能チャネルは、Event Hubs や Kafka のネイティブ機能ではありません。 多くの場合、配信不能の "概念" は、処理できないデータに対応するという形で、ストリーミング ソリューションに統合されています。 この機能は意図的に、Event Hubs の本来の要素ではなく、同様の動作や効果を得るためにあくまでコンシューマー側で追加されます。 配信不能サポートが必要な場合は、ストリーミング メッセージ サービスの選択を確認してみることをお勧めします。

  • 作業単位はパーティションである: 従来のメッセージ ブローカーでは、作業単位は 1 つのメッセージです。 ストリーミング ソリューションでは、多くの場合、パーティションが作業単位と見なされます。 イベント ハブ内の各イベントが、注文処理または財務取引処理を必要とする個別のメッセージとして扱われる場合は、最適なパフォーマンスまたは処理のために、より適切なメッセージング サービスを探索する機会を提案します。

  • サーバー側のフィルター処理なし: Event Hubs が非常に大きなスケールとスループットに対応できる理由の 1 つとして、サービス自体のオーバーヘッドが低いことがあります。 サーバー側のフィルター処理、インデックス、クロスブローカー調整などの機能は、Event Hubs のアーキテクチャには含まれていません。 本文またはヘッダーの内容に基づいて他の Event Hubs にイベントをルーティングすることによって、イベントをフィルター処理するために関数が使用されることがあります。 この方法はイベント ストリーミングでは一般的ですが、初期関数が各イベントを読み取り評価されるという点に注意してください。

  • すべてのリーダーがすべてのデータを読み取る必要がある: サーバー側のフィルター処理が使用できないため、コンシューマーはパーティション内のすべてのデータを順番に読み取ります。 これには、関連性がなかったり、形式が正しくなかったりする可能性のあるデータが含まれます。 これらの課題を補うために使用できるいくつかのオプションと戦略があり、これについては本セクションの後半で説明します。

これらの重要な設計上の決定により、Event Hubs はそれが最も得意とする処理、つまり急増するイベントをサポートし、コンシューマーが読み取るための堅牢で回復力のあるサービスを提供します。 各コンシューマー アプリケーションは、これらのイベントに対する独自のクライアント側のオフセットまたはカーソルを維持する責任を担います。 オーバーヘッドが低いため、Event Hubs はイベント ストリーミング用の低価格で強力なオプションとなります。

べき等性

Azure Event Hubs の主要な原則の 1 つは、少なくとも 1 回の配信という概念です。 この方法により、イベントが常に確実に配信されます。 また、イベントは、関数などのコンシューマーによって複数回受信されたり、繰り返し受信されることさえもあります。 このため、イベント ハブによってトリガーされる関数は、べき等コンシューマー パターンをサポートすることが重要です。

特にイベントドリブン アーキテクチャのコンテキスト内で、少なくとも 1 回の配信を想定して処理することは、イベントを確実に処理するための責任あるアプローチです。 同じイベントを複数回処理した結果が、1 回だけ処理したものと同じになるようにするには、関数がべき等である必要があります。

重複イベント

重複イベントが関数に配信される可能性があるシナリオには、さまざまなものがあります。

  • チェックポイント処理: Azure Functions ホストがクラッシュした場合、またはバッチ チェックポイントの頻度に設定されたしきい値を満たしていない場合、チェックポイントは作成されません。 その結果、コンシューマーのオフセットは先へ進まず、次に関数が呼び出されたときに、最後のチェックポイントから再開されます。 チェックポイントは、各コンシューマーのパーティション レベルで実行されることに注意してください。

  • 重複するイベントのパブリッシュ: 多くの手法では、同じイベントがストリームに発行される可能性を減らすことができますが、コンシューマーは重複をべき等的に処理する必要があります。

  • 受信確認がない: 場合によっては、サービスへの送信要求は正常に行われた可能性があるが、サービスからの受信確認 (ACK) が受信されないことがあります。 これにより、送信呼び出しが失敗したと認識され、関数から一連の再試行またはその他の結果が開始される場合があります。 最終的には、重複するイベントが発行されたり、チェックポイントが作成されなかったりする可能性があります。

重複除去の手法

同一の入力に備えて関数を設計することは、Event Hubs トリガー バインドと組み合わせる場合の既定のアプローチとする必要があります。 次の手法について検討してください。

  • 重複を検索: 処理する前に、イベントを処理する必要があることを検証するために必要な手順を実行します。 場合によっては、これがまだ有効であることを確認するための調査が必要になることがあります。 また、データの鮮度やイベントを無効にするロジックによって、イベントの処理が不要になる可能性もあります。

  • べき等のためのイベントの設計: イベントのペイロード内に追加情報を提供することにより、これを複数回処理しても悪影響が生じないようにできる場合があります。 銀行口座からの引き出し金額を含むイベントの例を考えてみます。 適切に処理しないと、口座残高を複数回減らしてしまう可能性があります。 ただし、同じイベントに口座の更新後残高が含まれている場合は、銀行口座の残高に対してアップサート操作を実行するために使用できます。 このようなイベントによる状態変化のアプローチでは、プロデューサーとコンシューマーの間で調整が必要になる場合があります。参加するサービスにとって意味がある場合には、使用する必要があります。

エラー処理と再試行

エラー処理と再試行は、分散型のイベントドリブン アプリケーションの最も重要な資質の 1 つであり、Azure Functions も例外ではありません。 イベント ストリーミング ソリューションの場合、適切なエラー処理のサポートの必要性は不可欠です、何千ものイベントが正しく処理されない場合、それらはすぐに同じ数のエラーに変化します。

エラー処理に関するガイダンス

エラー処理を使用しないと、再試行を実装し、ランタイム例外を検出して、問題を調査することが困難になることがあります。 すべての関数には、少なくとも一定レベルのエラー処理が必要です。 推奨されるガイドラインをいくつか次に示します。

  • Application Insights を使用する: Application Insights を有効にして使用し、エラーをログに記録して、関数の正常性を監視します。 大量のイベントを処理するシナリオでは、構成可能なサンプリング オプションに注意してください。

  • 構造化エラー処理の追加: 各プログラミング言語の適切なエラー処理コンストラクトを適用して、関数コード内で予期されるおよびハンドルされない例外をキャッチし、ログに記録し、検出します。 たとえば、C#、Java、JavaScript の try/catch ブロックを使用したり、Python の try と except のブロックを利用したりして、例外を処理します。

  • ログ記録: 実行中に例外をキャッチすることによって、問題を確実に検出、再現、修正するために使用できる重要な情報をログに記録できます。 例外、メッセージだけでなく本文、内部例外、および後で役立つその他の便利な成果物をログに記録します。

  • 例外をキャッチして無視しない: 最も悪いことは、例外をキャッチして何も実行しないことです。 汎用的な例外をキャッチした場合は、どこかにログを記録します。 エラーをログに記録しないと、バグを調査して問題を報告することが困難になります。

[再試行の回数]

イベント ストリーミング アーキテクチャでの再試行ロジックの実装は、複雑になる場合があります。 キャンセル トークン、再試行の回数、および指数バックオフ戦略をサポートすることは、考慮すべき困難な課題の一部にすぎません。 幸いなことに、Azure Functions には通常は自分でコーディングするこれらの多くのタスクを補うことができる再試行ポリシーが用意されています。

Event Hub バインドで再試行ポリシーを使用するときに考慮する必要があるいくつかの重要な要素を次に示します。

  • 無限の再試行を避ける: 最大再試行回数の設定が -1 の値に設定されている場合、関数は無限に再試行します。 一般に、無限の再試行は、Azure Functions では使用を控え、Event Hubs のトリガー バインドではほとんど使用しないようにする必要があります。

  • 適切な再試行戦略を選択する: 他の Azure サービスからのプレッシャーを受けるシナリオでは、固定遅延戦略が最適な場合があります。 このような場合、遅延はこれらのサービスによって発生する調整やその他の制限を回避するのに役立ちます。 指数バックオフ戦略は、再試行の遅延間隔に柔軟性を持たせ、サードパーティのサービス、REST エンドポイント、およびその他の Azure サービスと統合するときによく使用されます。

  • 間隔および再試行回数を少なく保つ: 可能な場合は、再試行間隔を 1 分より短くしてください。 また、最大再試行回数は適度に低い値にしてください。 これらの設定は、Functions 従量課金プランで実行する場合に特に意味を持ちます。

  • サーキット ブレーカー パターン: 一時的な障害エラーがときどき発生することが予想され、再試行のための自然のユースケースです。 ただし、関数の処理中に大量のエラーや問題が発生した場合は、関数を停止し、問題に対処して後で再起動することが合理的な場合もあります。

Azure Functions での再試行ポリシーについての重要事項は、これはイベントを再処理するためのベスト エフォート機能だということです。 これは、コードへの回復性を提供するエラー処理、ログ、およびその他の重要なパターンの必要性に代わるものではありません。

障害やデータの破損に関する戦略

イベント ストリーム内のエラーや不正データが原因で生じる問題を補うために使用できるいくつかの注目すべき方法があります。 基本的な戦略は次のとおりです。

  • 送信および読み取りを停止する: 基本的な問題を修正するには、イベントの読み取りと書き込みを一時停止します。 この方法の利点は、データが失われず、修正がロール アウトされた後に操作を再開できることです。この方法ではアーキテクチャにサーキット ブレーカー コンポーネントが必要になる場合があり、一時停止を実現するために、影響を受けるサービスへの通知が必要になる場合があります。 場合によっては、問題が解決されるまで関数の停止が必要になることがあります。

  • メッセージの削除: メッセージが重要でない場合や、ミッションクリティカルでないと見なされる場合は、それらを処理せずに続行することを検討してください。 この方法は、チェスの試合で動きを記録する、または財務ベースのトランザクションなど、強力な整合性を必要とするシナリオでは機能しません。 処理できないメッセージをキャッチおよび削除するには、関数内でエラー処理を行うことをお勧めします。

  • 再試行: イベントの再処理が必要になる多くの状況があります。 最も一般的なシナリオは、別のサービスまたは依存関係を呼び出すときに発生する一時的なエラーです。 ネットワーク エラー、サービスの制限と可用性、および強力な一貫性は、再処理の試行を正当化する最も頻繁なユースケースです。

  • 配信不能: ここでの考え方は、イベントを別のイベント ハブに発行し、既存のフローが中断されないようにすることです。 認識としては、ホットパスから移動され、後でまたは別のプロセスによって処理される可能性があるということです。 このソリューションは、有害なメッセージやイベントの処理に頻繁に使用されます。 異なるコンシューマー グループを使用して構成されている各関数では、それでもストリーム内に不正なまたは破損したデータが検出されるため、それを適切に処理する必要があります。

  • 再試行および配信不能: 何度か再試行を行い、しきい値に達したら最終的には配信不能ストリームに発行することも、よく使用される方法の 1 つです。

  • スキーマ レジストリを使用する: スキーマ レジストリは、整合性とデータ品質を向上させるための事前対応ツールとして使用できます。 Azure スキーマ レジストリでは、スキーマの進化に伴って、バージョンおよびさまざまな互換性モードと共にスキーマの移行がサポートされます。 スキーマの中心は、プロデューサーとコンシューマーの間のコントラクトとしての役割であり、無効または破損したデータがストリームに発行される可能性を削減することができます。

最終的に、完全な解決策はないため、各戦略の結果とトレードオフを徹底的に調査する必要があります。 要件に基づいて、これらの手法のいくつかを組み合わせて使用することが、最適な方法である場合もあります。

共同作成者

この記事は、Microsoft によって保守されています。 当初の寄稿者は以下のとおりです。

プリンシパル作成者:

  • David Barkol | プリンシパル ソリューション スペシャリスト (GBB)

パブリックでない LinkedIn プロファイルを表示するには、LinkedIn にサインインします。

次のステップ

続行する前に、次の関連記事を確認してください。

サーバーレスなイベント処理」は、この種類の一般的なアーキテクチャを詳述する参照アーキテクチャです。コード サンプルと重要な考慮事項について説明しています。