このポストは個人の意見/メモであり、私が所属する会社を代表するものではありません。
DynamoDBのConditional Update
DynamoDBには Conditional Updateという機能があり、これを利用することによりアトミックな更新オペレーションができる。
例えば下記のような感じだ。
- 特定のキーのアイテムがなければPut
- 特定のアイテムの特定のアトリビュートがある値であればUpdate
詳細が知りたい人はDynamoDBのDeveloper Guideを。
Conditional Updateでロック管理
この **「特定のキーのアイテムがなければPut」**を応用して、アイテムの有無を以下のように読み替えるとロック管理を実装することができる。
DynamoDBにAというキーでアイテムをPutしにいく。このときにキーAのアイテムが
- 存在する:既に他の誰かがロック済み。Putオペレーションは失敗する(させる)。
- 存在しない:誰もロックしていない。ロックのためのマーキングとしてキーAのアイテムをPutする。
Pythonとbotoで実装するならこんな感じ。
def lock_key(key):
try:
dynamodb.put_item(
'TABLE_NAME',
{'key' : { "S" : key }},
expected = {
'key' : { "Exists" : False }
}
)
return True
except Exception,e:
return False
ファイル名をキーにしてテーブルにアイテムをPutしに行く。既存アイテムが存在せずにPutに成功したらTrueを返し、そうでなければFalseを返している。
S3へのファイルアップロードの管理に応用する
この仕組を利用してS3へのファイルアップロードを管理するツールを書いてみた。
https://gist.github.com/imaifactory/6132f8a60461584b4613
一度アップロード済みのファイルが再度アップロードされる心配がないので、大量のファイルを並列でアップロードしたり、途中で処理が失敗したときにも何度でもやり直しをすることができる。実際、この仕組みを使って1日に約8,000〜10,000くらいのログファイルをS3に転送する、というのを3〜4ヶ月運用してたことがあるが、漏れも重複もゼロで運用できたよ。
awscliのs3 syncは便利だけど、プロダクションに利用するには漏れ/重複対策が心配、という人はこんな感じに実装してみるといいかも。
冪等!冪等!