DynamoDB の設計とクエリ
DynamoDB がとても難しかったので軽いまとめと備忘録
大事なこと
テーブル設計をするとき、まずは目的や用途から考える
スキャンではなくクエリを使う
実際にやったもの
各メンバーの SR の ID とその情報を DynamoDB に保存
使用用途
- 特定期間(最大1か月)以内に各メンバーにアサインされた SR 情報の取得
- SR アサイン時にその SR がリアサインかの確認(リアサインの場合は前アサイン者の名前を取得)
各設定(キー/インデックス)
プライマリキー
パーテーションキー:メンバー名
ソートキー:アサイン時間
インデックス
グローバルセカンダリインデックス:SR の ID
ローカルセカンダリインデックス:なし
はまりポイント
DynamoDB のキーは Datetime 型に対応していないので String にする必要がある
数値型にしてエポック時間で登録することでも対応可能だがコード側で処理を変えなければいけなかったので今回は Datetime 型を使用しました
※ただ特定フォーマットであればソートすることが可能
良くまとめてくださっている記事
自分がはまった個所
ソートキーに使用するアサイン時間にタイムゾーンを含めてしまっていた
DynamoDB 的には問題なくソートできたのですが、コード側でタイムゾーンが入っていると処理がめんどくさくなることに気づいてませんでした。。。
既存ではすでに 2000 エントリくらい登録されていたので手動で更新するのは現実的ではなかったため、SDK を使用し対応しました。
※最初はアップデートアイテムで修正しようとしたのですが、ソートキーで使用していたためうまくいかなかったです(私のコードが悪かったかもですが)
なので一度スキャンを行いすべてのアイテムを取得し、タイムゾーンを削除した新しい値でアイテムの再作成し終わった後に既存の誤った値をすべてDeleteするという対応をしました。。。。
もっとスマートな対応をしたかったですが一度だけでいいので Lambda でサクッとやりました(Lambdaはほんとに便利)
2023/03/07:追記
"%z"付ければよかっただけ説が濃厚に。。。
%Y-%m-%dT%H:%M:%S.%f%z
キーワードのおさらい
機能系
プライマリキー
データを一意に識別するためのキーで、「パーティションキー」または「パーティションキーとソートキーの複合キー」のこと
パーテーションキー
データをどのパーティションに配置するか決定する。
各パーティションへのアクセスがなるべく均一になるようパーティションキーを設計すると良い
ソートキー
ソートキーによってデータはパーティション内で並べ替えられて物理的に近くなるように配置される
QueryAPIではソートキーを指定して取り出すデータの範囲をフィルタ可能
ソートキーの設定は任意
GSI (グローバルセカンダリインデックス)
ベースのテーブル上で異なるパーティションキー・ソートキーのテーブルを作成する仕組み
保持する情報も選択可能
キャパシティユニットも GSI 用に確保
LSI (ローカルセカンダリインデックス)
ベースのテーブル上でパーテーションキーは同じもののままで異なるソートキーのテーブルを作成する仕組み
保持する情報も選択可能
テーブル作成時のみ作成可能
GSI vs LSI
GSI | LSI | |
---|---|---|
新しく設定するキー | パーティションキー、ソートキー(任意) | ソートキー |
キーの重複 | 可 | 可 |
インデックス数の上限 | 5 | 5 |
項目コレクションのサイズ制限 | なし | 10GB以下 |
テーブル作成後の追加 | 可 | 不可 |
読み込み整合性 | 結果整合性 | 結果整合性、強い整合性 |
キャパシティユニットの消費 | GSIから消費 | ベーステーブルから消費 |
関連ワード
クエリ
パーテンションキーを使用して特定のデータを取得すること
ソートキーを使用することで取得範囲のフィルターが可能
スキャン
テーブルのすべてのデータを取得すること
キャパシティユニット
読み込み・書き込み処理が発生した際に使用されるものの
GSI は独自のものを持ち、LSI はベースのテーブルとキャパシティユニットを共有している
オンデマンドモードとプロビジョニングモードがある
※モードは切り替え可能
オンデマンドモード
従量課金制(使用した分のみの課金)
新しくテーブルを作る際や、アプリケーションのトラフィックが予測できない場合に使用が勧められる
使用されるキャパシティユニットの詳細
読み込み
- 4 KB 以下の項目の強力な整合性のある読み込みリクエストには、1 つの読み込みリクエストユニット
- 4 KB 以下の項目の結果整合性のある読み込みリクエストには、2 分の 1 の読み込みリクエストユニット
- 4 KB 以下の項目のトランザクション読み込みリクエストには、2 つの読み込みリクエストユニット
書き込み
最大サイズが 1 KB の項目について 1 回の書き込みを表す。
※1 KB より大きい項目を書き込む必要がある場合、追加の書き込みリクエストユニットを消費する
トランザクション書き込みリクエストでは、1 KB までの項目を 1 回書き込むのに書き込みリクエストユニットが 2 個必要
プロビジョニングモード
事前に 1 秒あたりの読み込みと書き込みの回数を指定する
使用され方が予測出来る場合に推奨
※Auto Scaling を使用することでトラフィックの変更に応じて自動調整可能
使用されるキャパシティユニットの詳細
読み込み
1 つの読み込み容量単位は、最大サイズ 4 KB の項目について、1 秒あたり 1 回の強力な整合性のある読み込み、あるいは 1 秒あたり 2 回の結果整合性のある読み込みを表す。
トランザクション読み込みリクエストでは、4 KB までの項目を 1 秒あたりに 1 回読み込むのに読み込み容量単位が 2 個必要。4 KB より大きい項目を読み込む必要がある場合、DynamoDB は追加の読み込み容量単位を消費する必要があります。
例:
項目のサイズが 8 KB の場合、1 秒あたり 1 回の強力な整合性のある読み込みを維持するには読み込みキャパシティーユニットが 2 個、結果整合性のある読み込みを選択した場合は読み込みキャパシティーユニットが 1 個、またはトランザクション読み込みリクエストには読み込みキャパシティーユニットが 4 個必要
書き込み
最大サイズが 1 KB の項目について 1 回の書き込みを表す。
※1 KB より大きい項目を書き込む必要がある場合、追加の書き込みリクエストユニットを消費する
トランザクション書き込みリクエストでは、1 KB までの項目を 1 回書き込むのに書き込みリクエストユニットが 2 個必要
DynamoDB Auto Scaling
ベーステーブルと GSI のスループット容量を自動管理する
※コンソール上から GSI を作成するとデフォルトで有効になる
読み込みおよび書き込みのキャパシティーユニットの範囲 (上限と下限) と、その範囲内での目標使用率を定義し、アプリケーションのワークロードが増減しても、ターゲットの使用率が維持されるようにする
リザーブドキャパシティ
前払いすることで標準テーブルクラスの場合割引を受けられるもの
※書き込み、読み込み両方が対象
注意点:
- レプリケーションされた書き込みキャパシティユニットでは使用できない
- 購入したリージョン限定
- 標準-IAテーブルクラスやオンデマンドモードでは使用できない
読み込み整合性
結果整合性
最新の書き込みが反映されていなかったり、古いデータを読み取ることがある
時間がたってからリクエストすることで最新のデータが返される
デフォルトの動作
→ConsistentRead を True にすることで強い整合性のある読み込みとなる
強い整合性
成功した以前のすべての書き込みオペレーションからの更新が反映された最新データの応答を返す
注意点:
- GSI ではサポートされていない
- 多くのスループット容量が使用される
DAX (DynamoDB Accelerator)
DynamoDB で使用できるキャッシュサービス
以下が使用用途(マイクロ秒の応答時間が必要な場合)
- インメモリキャッシュとしての DAX は、1 桁台のミリ秒単位からマイクロ秒単位まで、結果整合性のある読み込みワークロードの応答時間を短縮する
- DAX は、DynamoDB と API の互換性のあるマネージドサービスを提供することにより、オペレーションとアプリケーションの複雑さを軽減します。したがって、既存のアプリケーションで使用するために必要なのは最小限の機能変更だけとなる
- 読み込みの多いワークロードや急激に増大するワークロードにおいて、DAX はスループットを強化することや、読み込み容量ユニットを必要以上にプロビジョニングしないようにすることで運用コストの節約を可能にします。個々のキーで繰り返し読み込みが必要なアプリケーションにおいては特にメリットがある
今後検討したいもの
キャパシティユニットの最適化
初期はどれくらいのキャパシティが必要になるかわかっていなかったためオンデマンドモードにしていたのですが、ある程度データが取れた後はコストの削減のためにプロビジョンドモードに変更したいと考えています
アイテムの S3 へのバックアップ
現在はバックアップや、古いデータの処理が設定できていないので特定日数が過ぎたアイテムについては S3 へバックアップされるようにしたいと考えています
クエリの高速化
現状は必要ないですが今後もしクエリスピードに問題が出てきてしまったり、今以上のスピードが必要になった場合は DAX を追加設定するのもありかなと思います(コストとの兼ね合いでむずかしいかもですが)
Discussion