Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What is going on with this article?
@kimama-cloud

【小ネタ】 DynamoDBのTTLで一部だけ無期限にしたい時は0でOK

More than 1 year has passed since last update.

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時間を、人間向けの表記に変換してくれます。
dynamodb-ttl.png

データの削除を確認

あとは、時が経つのを待ちます。それぞれの有効期限を過ぎてしばらくすると、 BobCarol は自動削除されます。一方、 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 にした方がスッキリするかもしれません。

ケースバイケースで、うまく使い分けていただけたらと思います。

2
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kimama-cloud
テクニカルライターからインフラエンジニアに転職したおっさん。 私と同じ勉強中の人が親しみを覚える記事を書きたいと思っている。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
2
Help us understand the problem. What is going on with this article?