DynamoDBのTTLが何分で消えるのか調査してみた
※この調査は2020年10月に行ったものです。現在は挙動が異なる場合があるのでご参考までにお願いします。
【前置き】TTL機能の難点:何分で消えるか分からない
DynamoDBのTTL機能とは、アイテム(DynamoDBではレコードのことをアイテムという)に削除する時間を持たせて、その時間になったら削除させる機能。
Dynamoって一気にデータを削除するのが簡単ではなく、テーブルごと削除してテーブルを再生成する...とか、Lambdaの関数用意して削除する...とか。そんな方法がとられています。
Lambdaで実現するのもそんなに簡単じゃなく、タイムアウトの設定やら課金額を気にしなきゃいけないので、できれば使いたくない。
TTLは、そんな問題を解決してくれます。
ウェブサイトにアクセスしたユーザーのセッションデータなど、一定期間で削除したいデータに使うのが便利です。今までバッチを使って削除処理していたデータを、TTL機能を使うことによってバッチ要らずの削除ができるようになります。
こちらの機能は無料&DynamoDBの読み書き処理速度に影響を与えないという、【使い得】な機能になっています。
ところが...
問題点があります。それは
TTLで指定した時間に必ず消えるわけではない!
公式ドキュメントにも以下のように書いてあります。
通常、TTL は期限が切れた項目を期限切れから 48 時間以内に削除します。
データが消える時間をぴったり設定できるわけではないということです。
こうなってくると、お客さんから
「ユーザーのセッション情報をDynamoDBに登録したあと、24時間で削除してね」
って要件が出たとき、TTLで対応できなくなっちゃいますよね。
この48時間以内というのが曲者で、ネットで調べてみるとTTLで指定した時間から10分くらいで大体消えてくれるようです。
先ほどのお客さんも
「24時間プラスおおよそ10分で消えるならTTLでいいな!」
って思うかもしれない。
というわけで、前置きが長くなりましたが、今回はデータ件数を増やしてみるなど条件を変えてみて、TTLの時間から何分後にデータが削除されるかを見ていこうと思います。
調査の流れ
1. データの用意~Lambda関数、Dyanamoテーブルの準備~
2. TTLの時間まで待つ
3. DynamoDBのTTLメトリクスから、何分くらいで消えたか確認
用意① データ投入用のLambda関数を準備
用意なのでこの辺りは飛ばして、調査結果をみてもらって大丈夫です。興味がある方だけ見てください。
Dynamoに上手いこと大量データを投入する方法が分からなかったので、Lambdaでループさせてデータをどんどん投入していきます。
(※ちなみに、【AWS Data Pipeline】を使用してS3に上げたデータをDynamoDBに取込むのが好ましいようです。私はまだ使いこなせておらず...)
Dynamoに一気に入れられるデータは25件という縛りがあるので、boto3のbatch_writer()をつかってこんな感じで書くと、よしなにやってくれますね。
ほとんどネットのソースコピペです。ttlには現在時刻の1時間後を設定しました。
Lambdaのマネジメントコンソールで、TARGET_TABLEの環境変数に今回データを投入するDynamoテーブル名を入れます。
import json
import os
import logging
import boto3
TARGET_TABLE = os.getenv('TARGET_TABLE', None)
DYNAMO = boto3.resource('dynamodb')
LOGGER = logging.getLogger()
LOGGER.setLevel(logging.INFO)
def lambda_handler(event, context):
try:
table = DYNAMO.Table(TARGET_TABLE)
with table.batch_writer() as batch:
for i in range(0,100):
batch.put_item(
Item={
'userId': i,
'ttl': 1602649200
}
)
except Exception as e:
LOGGER.error(e)
else:
LOGGER.info('SUCCESS')
用意② DynamoDBテーブルを作成
今回はuserIdを主キーとして、TTL属性はそのままttlと設定します。
以下のようにTTLの設定をマネジメントコンソールから行います。
ここで作ったテーブルに、先ほどのLambda関数でデータを投入してく感じですね。Lambda関数で放り込みたい数をループのrangeの値で指定して、投入していきます。
用意③ データの投入
今回は全部で3つのテーブルを作成。
A:データが100件のテーブル
B:データが1000件のテーブル
C:データが10000件のテーブル
データ数でTTLの性能が変わるという話はなかったですが、一応比較のために用意しました。
データ投入用Lambdaは単にマネジメントコンソールの【テスト】で実行するだけです。データ投入にかなり時間がかかるので、タイムアウト時間を長く設定します。
これがゴリゴリ時間かかるので、心臓に悪い。料金いくらかかってるのか確認しないと...
10000件の投入では15分×2回ほどかかったので、メモリ最小128MBで、0.3744円くらいっぽい。
計算はこちらのミリ秒の表を参考でやりました。
Dynamoの嫌なところがどんどん見えてくるけど、もっと簡単でお金のかからない方法があるのでしょうね。。勉強不足です。
調査① A:100件のデータにTTL設定
現在時刻から1時間後(すべて13:30に設定しました)をTTLとして設定した100件のデータを用意し、様子をみましょう。
関係あるかは分かりませんが、DynamoDBは一番値段の安くなるこちらに設定。
プロビジョンド読み込みキャパシティーユニット 1 (Auto Scaling 無効)
プロビジョンド書き込みキャパシティーユニット 1 (Auto Scaling 無効)
結果:
TTLで指定した時間から...
<1回目>11分経過で100件全てのデータが消えた
<2回目>12分経過で100件全てのデータが消えた
<3回目>12分経過で100件全てのデータが消えた
<4回目>12分経過で100件全てのデータが消えた
<5回目>13分経過で100件全てのデータが消えた
調査② B:1000件のデータにTTL設定
現在時刻から1時間後(すべて13:30に設定しました)をTTLとして設定した1000件のデータを用意し、様子をみましょう。
関係あるかは分かりませんが、DynamoDBは一番値段の安くなるこちらに設定。
プロビジョンド読み込みキャパシティーユニット 1 (Auto Scaling 無効)
プロビジョンド書き込みキャパシティーユニット 1 (Auto Scaling 無効)
結果:TTLで指定した時間から...
<1回目>12分経過で100件全てのデータが消えた
<2回目>12-13分経過で100件全てのデータが消えた
<3回目>19分経過で100件全てのデータが消えた
2回目は12分で450件、13分で550件消えました。
調査③ C:10000件のデータにTTL設定
現在時刻から1時間後(すべて13:30に設定しました)をTTLとして設定した10000件のデータを用意し、様子をみましょう。
関係あるかは分かりませんが、DynamoDBは一番値段の安くなるこちらに設定。
プロビジョンド読み込みキャパシティーユニット 1 (Auto Scaling 無効)
プロビジョンド書き込みキャパシティーユニット 1 (Auto Scaling 無効)
結果:10000件だと段階的に消えていきました。TTLで指定した時間から..
<1回目> 11-13分で全てのデータが消えた。
11分:2528件
12分:3225件
13分:4247件
<2回目> 10-13分で全てのデータが消えた。
10分:1190件
11分:3920件
12分:2988件
13分:1902件
<3回目> 12-15分で全てのデータが消えた。
12分:1872件
13分:3860件
14分:3878件
15分:390件
10000件だと順々にデータが消えていきました。とはいえ削除の開始時間は100件,1000件のときと変わりませんね。
まとめ
ネット上の情報と同じように、データ数に関わらず11分程度でデータの削除が行われていくことが分かりました。
データ数が10000件までいくと、何回かに渡ってデータ削除が実行されている様子も確認できました。
これを見せれば、
「48時間って書いてあるけど11分程度で消えますよ」
と説明できるようになるかも。
本当はもう少し回数や時間帯で試したいのですが、サンプルデータ投入の手間と課金が気になるので、今回の検証はこのくらいでまとめたいと思います。
追加調査 TTLに現在時刻を入れると...?
TTLに現在時刻をいれても11分程度で削除されるのか気になり、調べてみたところ23分かかりました。
確か、TTLの内部の仕組みは以下のような二段階構成になっていたはず。
1.TTLの時間が過ぎているデータを削除可能データとしてメモ。
2.削除する処理を流す。
なので、1の処理を行うクローラーみたいなものが今回のDynamoを見に来る機会がなかったんでしょう。
データ作成から10分くらい経過後に1の処理を行う→15分後に2の削除処理が流れる
というステップだったのかな。この通りだとすると、
「そこそこ未来の時間を設定されていたTTLの場合は時間ぴったりに消すことも可能だが、わざと10分程度置いてから消している」
という感じにも見えますね。