web-dev-qa-db-ja.com

Amazon KinesisおよびAWS Lambdaの再試行

私はAmazon Kinesisに非常に慣れていないので、これは私の理解の問題にすぎないかもしれません AWS Lambda FAQ it言う:

AWS Lambda関数に送信されるAmazon KinesisおよびDynamoDB Streamsレコードは、シャードごとに厳密にシリアル化されます。つまり、2つのレコードを同じシャードに配置した場合、Lambdaは、2番目のレコードで呼び出される前に、最初のレコードでLambda関数が正常に呼び出されることを保証します。 1つのレコードの呼び出しがタイムアウトするか、制限されるか、その他のエラーが発生した場合、Lambdaは成功する(またはレコードが24時間の有効期限に達する)まで再試行してから、次のレコードに移動します。異なるシャードにわたるレコードの順序は保証されておらず、各シャードの処理は並行して行われます。

私の質問は、何らかの理由で不正なデータがプロデューサーによってシャードに配置され、Lambda関数がそれを取得したときにエラーが発生し、常に再試行し続ける場合はどうなりますか?これは、その特定のシャードの処理がエラーによって24時間ブロックされることを意味します。

このようなアプリケーションエラーを処理するには、問題をカスタムエラーにラップし、このエラーを正常に処理されたすべてのレコードと一緒にダウンストリームに送信して、コンシューマーに処理させることをお勧めしますか?もちろん、これは、nullポインターのようにプログラムをクラッシュさせる回復不可能なエラーの場合にはまだ役に立ちません。次の24時間は、ブロックしている再試行ループに戻ります。

22
Stefano

考えすぎないでください。Kinesisは単なるキューです。次のレコードに進むには、レコードを正常に消費する(つまり、キューからポップする)必要があります。 FIFOスタックのように。

適切なアプローチは次のとおりです。

  • ストリームからレコードを取得します。
  • Try-catch-finallyブロックで処理します。
  • レコードが正常に処理されれば、問題ありません。 <-試す
  • ただし、失敗した場合は、別の場所にメモして、失敗した理由を調査してください。 <-キャッチ
  • そして、ロジックブロックの最後では、常にDynamoDBの位置を維持します。 <-ついに
  • システム内で内部(メモリエラー、ハードウェアエラーなど)が発生した場合、それは別の話です。 1つだけでなく、すべてのレコードの処理に影響を与える可能性があるため。

ちなみに、レコードの処理に1分以上かかる場合は、何かがおかしいのは明らかです。 Kinesisは1秒あたり数千件のレコードを処理するように設計されているため、それぞれのそのような長いジョブを処理するという贅沢はありません。

あなたが質問しているのは、キューシステムの一般的な問題で、「有害なメッセージ」と呼ばれることもあります。安全のために、ビジネスロジックでそれらを処理する必要があります。

http://www.cogin.com/articles/Sur​​vivingPoisonMessages.php#PoisonMessages

32
az3

これは、Kinesisでのイベントの処理に関する一般的な質問です。「破損した」データに関するこのような問題を処理するためにLambda関数を構築するためのポイントをいくつか示します。システムの一部をKinesisストリームに書き込み、その他の部分をKinesisストリームから読み取るようにすることがベストプラクティスであるため、このような問題が発生することはよくあります。

まず、なぜこのような問題のあるイベントがあるのですか

Kinesisを使用してイベントを処理することは、フロントエンド処理(エンドユーザーにサービスを提供する)と、同時に/バックエンド処理(イベントの分析)の両方を実行する複雑なシステムを2つに分割する良い方法です- 独立システムの一部。フロントエンドの人々はビジネスに集中できますが、分析的なユースケースに対応する機能を追加したい場合、バックエンドの人々はコードの変更をフロントエンドにプッシュする必要はありません。 Kinesisは、同期の必要性をなくし、ビジネスロジックコードを簡素化するイベントのバッファーです。

したがって、ストリームに書き込まれるイベントは「schema」で柔軟になり、フロントエンドチームがイベント形式を変更する場合は、フィールドを追加し、フィールドを削除します、プロトコルまたは暗号化キーを変更します。必要に応じて何度でも変更できるはずです。

現在、このような柔軟なイベントを効率的に処理でき、そのような変更が発生するたびに処理を中断しないのは、ストリームから読み取るチーム次第です。したがって、Lambda関数が処理できないイベントを確認することは一般的であり、「poison-pill」は、ごくまれなイベントではありません。

第二に、このような問題のあるイベントをどのように処理しますか?

Lambda関数は、処理するイベントのbatchを取得します。イベントを1つずつ取得するのではなく、大量のイベントを取得する必要があることに注意してください。バッチが小さすぎると、ストリームで大きな遅延がすぐに発生します。

各バッチについて、イベントを反復処理して処理し、DynamoDBでバッチの最後のシーケンスIDをチェックポイントします。 Lambdaはこれらのステップのほとんどを自動的に実行しています(詳細はこちらをご覧ください: http://docs.aws.Amazon.com/lambda/latest/dg/walkthrough-kinesis-events-adminuser-create-test-function。 html ):

console.log('Loading function');

exports.handler = function(event, context) {
    console.log(JSON.stringify(event, null, 2));
    event.Records.forEach(function(record) {
        // Kinesis data is base64 encoded so decode here
        payload = new Buffer(record.kinesis.data, 'base64').toString('ascii');
        console.log('Decoded payload:', payload);
    });
    context.succeed();
};

すべてのイベントが問題なく処理された場合、これは「ハッピーパス」で何が起こっているかです。ただし、バッチで問題が発生し、成功通知でイベントを "commit"しない場合、バッチは失敗し、バッチ内のすべてのイベントを取得します再び。

次に、処理の失敗の理由を判断する必要があります。

  • 一時的問題(スロットリング、ネットワークの問題...)-少し待って、数回再試行しても問題ありません。多くの場合、問題は自動的に解決します。

  • 不定期問題(メモリ不足...)-Lambda関数のメモリ割り当てを増やすか、バッチサイズを減らすことをお勧めします。多くの場合、そのような変更は問題を解決します。

  • 定数失敗-問題のあるイベントを無視する(DLQに入れる-デッドレターキュー)か、コードを変更して処理する必要があることを意味します。

問題は、コード内の障害のタイプを識別し、それを異なる方法で処理することです。 Lambdaコードは、それを識別して(たとえば、例外のタイプ)異なる方法で記述する必要があります。

CloudWatchとの統合を使用して、このような障害をコンソールに書き込み、関連するアラームを作成できます。 CloudWatch Logsを「dead-letter-queue」のログを記録し、問題の原因を確認する方法としても使用できます。

16
Guy