メモ:Exactly-once semanticsとKafkaとAWS Lambda

OSDIで行われた以下の発表の資料を読んでいて、「Exactly-once semanticsってなんだっけ?」と疑問に思い、調べたことのメモ。

Fault-tolerant and transactional stateful serverless workflows | USENIX

ApacheKafkaとexactly-once semantics

  • transactional message processingにおいては、「PublisherからSibscriverへmessageの伝送が重複も欠損もなしに届くことは保証可能か」という問題領域が存在する
  • 上記の「messageの伝送が重複/欠損なしに実行される」性質を exactly-once semantics と呼ぶ
    • 要するに、Publisherが1Messageを送信したら、Subscriverに重複も欠損もなしに1通だけが届いてほしい
  • Apache Kafkaにおいて、Confuent社が2017年にexactly-once semanticsを保証する機能を発表し話題になった

3種類のSemantics

Exactly-once semantics が成立するためには、以下の2つのsemanticsの両方が保証される必要がある。

  • (1)メッセージが最低1回は送信されること(at-least once semantics)
  • (2)メッセージが最大でも1回しか送信されないこと(at-most once semantics)

f:id:smatsuzaki:20201114205957p:plain
exactly-onceが成立するためには、 at-leaset onceとat-most onceの両方の性質が満たさされる必要がある

いずれか片方のみのが満たされる場合は以下の状態になる。

  • at-least onceのみの場合、メッセージの重複が許容される
  • at-most onceの場合、メッセージの欠損が許容される

保証の方法だが、at-least once を保証しようとすると、「処理失敗時の再送(再実行)は可能か?」みたいなことを考えていくことになる。また、at-most once は、「この処理は実行されました」的なフラグをDB等の外部サービスに保存することで実現可能である。

AWS LambdaとExactly once semantics

2020年11月現在、AWS Lambdaでは、At-least once semanticsのみが保証されている。つまり、Functionが複数回実行されてしまうことが起こりえるため、プログラムを 冪等(idempotent) に設計することが求められる。

冪等性(idempotent)の定義

  • 関数が1回実行された時もN(>0)回実行された時も結果が変わらない こと
    • 「ある変数(int)の値を10にする」 → 冪等な処理
    • 「10を加算する」→ 冪等な処理ではない ※但し、後述のAWS推奨の方法にように制御構文により1回しか更新が実行されないことが保証できるなら冪等

推奨される冪等性(idempotent)の実現方法

AWSのドキュメントでは以下のように、処理成功時にeventIdを外部DBに保存し、「処理完了フラグ」のように使う方法が推奨されている

Lambda 関数に冪等にする

  1. 入力イベントの固有属性の値を抽出します。入力イベントの固有属性の値を抽出します。
  2. 属性値がコントロールデータベース (Amazon DynamoDB テーブルなど) に存在するかどうかを確認します。 注: アーキテクチャAWS サービスを追加すると、追加費用が発生する場合があります。詳細については、「Amazon DynamoDB 料金」および「 AWS 料金」をご参照ください。
  3. 一意の値が存在する場合 (重複イベントを示す)、実行を正常に終了します (つまりエラーを発生することがない)。一意の値が存在しない場合は、通常の実行を継続します。
  4. 関数の動作が正常に終了したら、コントロールデータベースにレコードが含まれます。
  5. 実行を終了します。

FaaSにおいて、基盤側にてExactly-onceを保証することは可能か?

  • 冒頭の論文でやり方が提案されている。興味のある方はそちらを参照。
/* https://sunrise033.com/entry/hatena-blog-how-to-hierarchicalize-categories */