DynamoDBのTTL機能
DynamoDBにはTTLという便利な機能があり、有効期限を過ぎると、そのデータだけ自動的に削除してくれます。
注意1:48時間以内に削除
注意点としては、有効期限後「48時間以内の削除」のため、すでに期限が切れたデータを読み出すこともあるということです。
通常、DynamoDB は期限が切れた項目を期限切れから 48 時間以内に削除します。期限切れの後で項目が実際に削除されるまでの期間は、ワークロードの特性とテーブルのサイズによって異なります。期限が切れたが削除されていない項目は、読み取り、クエリ、およびスキャンで引き続き表示されます。
単に、データの保管期限としてTTLを設定する場合は問題ありませんが、データ自体の有効性の期限という意味も兼ねている場合は、要注意です。読み出し時に、期限切れのデータは除外するよう、フィルタなどを設定する必要があります。
注意2:期限が5年以上昔なら削除しない
ところで、期限のあるデータと無期限のデータが混在する場合は、どうしましょうか。無期限のデータの期限を、遥か未来に設定するというのが、1つの解決方法です。
今回、DynamoDBでホワイトリストを作成するにあたって、オペレーターが手動入力する一部のものだけは、無期限にしたいという要望がありました。TTLはUNIX時間(エポック秒)でなければなりません。日付からUNIX時間に変換してくれるような専用入力画面は用意せず、AWSの管理コンソールを使用して直接入力するという話です。 3999999999
(2096年10月2日)などと入力しもらえばよいのですが、オペレーターが9を1つ入力し忘れるなどの事件が起きそうだと思っていました。
有効期限が 5 年以上前の項目は削除されません。
実は、上記の条件より、期限に 0
を入力すれば、TTLによる削除はされません。 3999999999
より間違いにくく、また、今回のシステムが、何かの間違いで2096年まで使用され続けても誤作動することもありません。
一部のデータだけ無期限にしたい場合は、値を0にするのがよさそうです。
実際に試してみよう
それでは、実際の動作を確認してみます。
テーブルを作成
id
というパーティションキーをもったテーブル test_whitelist
を作成します。
$ aws dynamodb create-table \
--table-name test_whitelist \
--attribute-definitions \
AttributeName=id,AttributeType=S \
--key-schema \
AttributeName=id,KeyType=HASH \
--provisioned-throughput \
ReadCapacityUnits=5,WriteCapacityUnits=5
次のコマンドでステータスが ACTIVE
になったら作成完了です。
$ aws dynamodb describe-table --table-name test_whitelist |
jq -r '.Table.TableStatus'
データを作成
3つの項目(データ)を作成し、有効期限としてそれぞれ、無期限、2時間後、明日を指定しましょう(ちなみに、TTLの機能が有効になるには、最大1時間かかります)。
現在、2時間後、明日のUNIX時間は、下記のコマンドで調べることができます。
$ date +%s
1568603731
$ date -d '2 hours' +%s
1568610936
$ date -d '1 day' +%s
1568690149
id
にユーザー名(文字列)、 expiration
に有効期限(数値)を指定して、データを書き込みます。
$ aws dynamodb put-item \
--table-name test_whitelist \
--item '{"id": {"S": "Alice"}, "expiration": {"N": "0"}}'
$ aws dynamodb put-item \
--table-name test_whitelist \
--item '{"id": {"S": "Bob"}, "expiration": {"N": "1568610936"}}'
$ aws dynamodb put-item \
--table-name test_whitelist \
--item '{"id": {"S": "Carol"}, "expiration": {"N": "1568690149"}}'
データを確認
全データを表示して確認します。
$ aws dynamodb scan --table-name test_whitelist
{
"Count": 3,
"Items": [
{
"id": {
"S": "Alice"
},
"expiration": {
"N": "0"
}
},
(後略)
TTLを有効に
準備ができたので、TTL機能を有効にします。TTLに expiration
を指定します。
aws dynamodb update-time-to-live --table-name test_whitelist \
--time-to-live-specification "Enabled=true, AttributeName=expiration"
ちなみに、管理コンソールでは
TTL機能を有効にすると、AWSの管理コンソールでは、TTLを設定した属性に (TTL)
という表記がつきます。また、項目にマウスカーソルを近づけると、期限のUNIX時間を、人間向けの表記に変換してくれます。
データの削除を確認
あとは、時が経つのを待ちます。それぞれの有効期限を過ぎてしばらくすると、 Bob
と Carol
は自動削除されます。一方、 0
を設定した Alice
は、永遠に残ります。
48時間以内の削除という話ですが、私が試した範囲では、期限の数十分後には削除されていました。
なお、すでに期限切れになったもの(期限が過ぎても、まだ削除されていないもの)を除外して表示したいときは、次のようにフィルタを設定して、読み出します。
$ now=$(date +%s)
$ aws dynamodb scan --table-name test_whitelist \
--filter-expression "expiration > :num OR expiration = :zero" \
--expression-attribute-values "{\":num\":{\"N\":\"$now\"}, \":zero\":{\"N\":\"0\"}}"
{
"Count": 2,
"Items": [
{
"id": {
"S": "Alice"
},
"expiration": {
"N": "0"
}
},
{
"id": {
"S": "Carol"
},
"expiration": {
"N": "1568690149"
}
}
],
"ScannedCount": 3,
"ConsumedCapacity": null
}
実際に試して気づいたこと
無期限の場合にTTLの値を 0
にすると、前述したとおり、期限が過ぎても、まだ削除されていないものを除外するフィルターが、やや複雑になりました(条件を2つ設定)。
一方、無期限の場合にTTLの値を 0
にせず、 3999999999
にした場合は、次のようなフィルターで済みます(条件は1つのみ)。
$ now=$(date +%s)
$ aws dynamodb scan --table-name test_whitelist \
--filter-expression "expiration > :num" \
--expression-attribute-values "{\":num\":{\"N\":\"$now\"}}"
オペレーターが直接操作する場合は 0
の方がわかりやすいと思いますが、専用の入力画面があって、オペレーターは「無期限」を選ぶだけの場合は、内部的には 3999999999
にした方がスッキリするかもしれません。
ケースバイケースで、うまく使い分けていただけたらと思います。