OSDIで行われた以下の発表の資料を読んでいて、「Exactly-once semanticsってなんだっけ?」と疑問に思い、調べたことのメモ。 https://twitter.com/MarcJBrooker/status/1326216462680289280?s=20 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を保証する機能を発表し話題になった https://jp.techcrunch.com/2017/07/01/20170630confluent-achieves-holy-grail-of-exactly-once-delivery-on-kafka-messaging-service/
3種類のSemantics
Exactly-once semantics が成立するためには、以下の2つのsemanticsの両方が保証される必要がある。
- (1)メッセージが最低1回は送信されること(at-least once semantics)
- (2)メッセージが最大でも1回しか送信されないこと(at-most once semantics)

いずれか片方のみのが満たされる場合は以下の状態になる。
- 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 関数をべき等にする | AWS re:Post
- 入力イベントの固有属性の値を抽出します。入力イベントの固有属性の値を抽出します。
- 属性値がコントロールデータベース (Amazon DynamoDB テーブルなど) に存在するかどうかを確認します。 注: アーキテクチャに AWS サービスを追加すると、追加費用が発生する場合があります。詳細については、「Amazon DynamoDB 料金」および「 AWS 料金」をご参照ください。
- 一意の値が存在する場合 (重複イベントを示す)、実行を正常に終了します (つまりエラーを発生することがない)。一意の値が存在しない場合は、通常の実行を継続します。
- 関数の動作が正常に終了したら、コントロールデータベースにレコードが含まれます。
- 実行を終了します。
FaaSにおいて、基盤側にてExactly-onceを保証することは可能か?
- 冒頭の論文でやり方が提案されている。興味のある方はそちらを参照。