Amazon Kinesis Streams documentation によると、レコードは複数回配信できます。
すべてのレコードを確実に1回だけ処理する唯一の方法は、整合性チェックをサポートするデータベース(DynamoDB、Elasticache、MySQL/PostgreSQLなど)に一時的に保存するか、各KinesisシャードのRecordIdをチェックポイントすることです。
重複を処理するためのより良い/より効率的な方法を知っていますか?
モバイルアプリ用のテレメトリシステムを構築するときに、まさにその問題が発生しました。私たちの場合、プロデューサーが各メッセージを1回だけ送信するかどうかもわかりませんでした。したがって、受信したレコードごとにMD5をその場で計算し、永続ストレージの形式で表示されるかどうかを確認しましたが、実際に使用するストレージは最もトリッキーなビット。
最初に、些細なリレーショナルデータベースを試しましたが、Kinesisを通過するデータの量が非常に多かったため、読み取りが多いだけでなく書き込みも多いため、すぐにシステム全体の大きなボトルネックになりました。
最終的に、一意のメッセージごとにMD5を格納するDynamoDBテーブルができました。私たちが抱えていた問題は、メッセージを削除するのがそれほど簡単ではなかったということでした-テーブルにパーティションキーとソートキーが含まれていても、DynamoDBは特定のパーティションキーを持つすべてのレコードをドロップすることを許可していません、取得するためにすべてをクエリする必要がありましたキー値を並べ替えます(時間と容量が無駄になります)。残念ながら、たまにテーブル全体を削除するだけで済みました。最適ではない解決策のもう1つの方法は、メッセージ識別子を格納するDynamoDBテーブルを定期的にローテーションすることです。
ただし、最近、DynamoDBは非常に便利な機能-- Time To Live を導入しました。これは、レコードごとに自動有効期限を有効にすることで、テーブルのサイズを制御できることを意味します。その意味では、DynamoDBはElastiCacheに非常に似ているようですが、ElastiCache(少なくともMemcachedクラスター)は耐久性がはるかに低く、冗長性がないため、運用中のスケールや障害が発生した場合、終了したノードにあるすべてのデータが失われます。
あなたが言及したことは、「少なくとも1回」のアプローチによるすべてのキューシステムの一般的な問題です。また、キューシステムだけでなく、プロデューサーとコンシューマーの両方が同じメッセージを複数回処理する可能性があります(ReadTimeoutエラーなどが原因で)。 KinesisとKafkaはどちらもそのパラダイムを使用しています。残念ながら、そのための簡単な答えはありません。
より厳密なトランザクションアプローチで、「正確に1回」のメッセージキューを使用することもできます。たとえば、AWS SQSは次のことを行います: https://aws.Amazon.com/about-aws/whats-new/2016/11/Amazon-sqs-introduces-fifo-queues-with-exactly-once-processing -and-lower-prices-for-standard-queues / 。 SQSスループットはKinesisよりはるかに小さいことに注意してください。
問題を解決するには、アプリケーションドメインを認識し、提案したように内部的に解決する必要があります(データベースチェック)。特に外部サービス(たとえば電子メールサーバー)と通信する場合は、二重処理を防ぐために操作状態を回復できる必要があります(電子メールサーバーの例では二重送信すると、複数のコピーが作成される可能性があるため)受信者のメールボックス内の同じ投稿)。
次の概念も参照してください。