DynamoDBのドキュメントを結構読み込んだので、必要だと思ったことの要点まとめ

はじめに

仕事でDynamoDBと戯れる機会があり、
そのときドキュメントを結構読んだ(多分8割くらい)ので要点・思ったことをメモりました。

実装面などについての記載は、AWS SDK for PHP視点になります。

基本事項

以下を参照すれば、基本的なことは大体判る
よくある質問 - Amazon DynamoDB | AWS

物理的な特徴

  • パーティション
    自動的にテーブルパーティション全体にデータが分散され、AWS Cloud の複数のサーバーにデータが格納される。
    つまり分散ストレージであるため、データが均一で登録されるような設計・実装が肝になる。
    これは1つのパーティションに対して負荷がかかり過ぎないように調整することと同じであるため、IOのパフォーマンス安定化に繋がる。
  • 読み込みキャパシティーユニット
    最大サイズ 4 KB の項目について、1 秒あたり 1 回の強力な整合性のある読み込み、あるいは 1 秒あたり 2 回の結果的に整合性のある読み込みを表す。
    4KBデータ未満の読出しは切り上げられるため、例えばこの値を「1」に設定した場合は、1秒間に1回の結果的に整合性のある読み取りしか行えない。
  • 書き込みキャパシティーユニット
    最大でサイズが 1 KB の項目について、1 秒あたり 1 回の書き込みを表す。
    1KB未満のデータは1KBに切り上げられるため、例えばこの値を「1」に設定した場合は、1秒間に1回の書き込みしかできない。
  • データサイズ
    各データレコードのサイズには、属性値の他に、属性名も含まれる

扱えるデータ型

  • S – 文字列 UTF-8 バイナリエンコードUnicode
  • N – 数値 有効桁数が最大 38 桁
  • B – バイナリ
  • BOOL – Boolean
  • NULL – Null
  • M – マップ
  • L – リスト
  • SS – 文字列セット
  • NN – 数値セット
  • BB – バイナリセット

各型の詳細は以下を参照

docs.aws.amazon.com

設計時に注意すべき特徴

  • Primary Keyは「HASH」 or「HASH + Sort」のどちらかのみで、キーに使用できるものは最大2つまで。
  • 書き込み先のパーティションはPKに依存するため、特定のパーティションに読書が集中しないように、キーにサフィックスを付ける。
  • テーブル名が同じでもリージョンが異なれば別テーブル扱いになる。
  • 時間単位にキャパシティユニットを大きく超えるような高い読み書きを行うとスロットリングが働いて「ProvisionedThroughputExceededException」が返ってくるので、キャパシティユニットを厳密に管理したいことがある場合は、リクエストの流量に注意を払う必要がある。
  • 大量データ書込みを行う場合、その見込みデータ数を書込みキャパシティプランに設定する必要がある。また、マルチプロセス or マルチスレッドで以てデータの書込み要求を行わないとパフォーマンスが失われる。
    処理時間は書込むデータ数を、いくつのプロセスから分散して25件 * N回の書込み要求をかけるか、である。

実装するときの注意事項

  • テーブル作成は、Primary Keyのみ生成。
    RDBだと構成を全部書くけど、DynamoDBはデータ登録時に属性が作られる
  • scanは公式に書いてあるとおりで、データが大量に保存してあるテーブルには使わない。
    scan自体使わない方針にすると良い。(手抜きで使うとコピペされる危険性の排除)
  • BatchのAPI(BatchWriteItem/BatchGetItemなど)を使用する場合、すべての処理がコケない限りは失敗はせず、個々で失敗したものはリクエストのキーと値が返される。
  • 書込みキャパシティプランをケチって、マルチプロセスで大量データを書いた場合、一部のプロセスで書込みエラーになる可能性がある。キャパシティプランをケチる場合は、シングルプロセスから書いた方がエラーの発生率は下がる。
    自分で試したところだと、
    10WCUで1プロセスから1万件データを25件ずつバルクで書き込んでもエラーにならなかった。

運用するときの注意

  • インデックスを後から付けた場合、テーブルの状態のBackfilling がfalseになるまでインデックスは使われない。
  • 大量のデータが登録されているテーブルに後からインデックスを付与すると時間がかかる。

API

  • CreateTable : テーブル作成
  • UpdateTable : テーブルのプロビジョニングしたスループット値を更新
  • DeleteTable : テーブルの削除
  • DescribeTables : テーブルの状態取得
  • ListTables
  • PutItem : データを1件登録
  • BatchWriteItem : データを最大25項目まとめて登録ただしデータ量はMAX16MB、かつ個々の項目は400KBまで
    ここでいう書込みとは、項目の作成・更新・削除を表す
  • UpdateItem : データを更新
  • DeleteItem : データを削除
  • GetItem : データを取得
  • BatchGetItems : データを最大100項目まとめて取得 ただしデータ量はMAX16MB
  • Query : 検索

良いところ

  • JSON作って投げるだけでデータの操作ができるので手軽。
    AWS SDK for PHP使うと連想配列を作って渡すだけ。
  • 基本的にオンラインでテーブルのチューニングができる。
    重たい処理をする前に、キャパシティをオンラインで拡張しておき、その処理が終わったら元に戻す、といったチートプレイが可能。
  • 登録データのパーティション(分散ストレージ)を均一化させることで、データがどんなに増えてもIOのパフォーマンスが安定する。

残念なところ

  • 一括登録、更新、削除のAPI(BatchWriteItem)の使い勝手が悪い
  • 範囲系の条件が作れないのはしんどい。(が、教授するメリットの方が大きいという認識を得た)
  • BatchWriteItemで型指定しないといけない。
  • BatchWriteItemは型指定をしないといけないのに、値は全て文字列でないといけない(AWS SDK PHP)
  • APIドキュメントの読みづらさが異常

他サービスとの連携

  • タグ
    タグをつけておくと、EC2やS3など、他のAWS上のサービスでタグがサポートされているものと連携してレポートを出すときに活用できたりする。
    DynamoDBでは、タグが付けられたテーブルに関連するローカルセカンダリインデックス (LSI) およびグローバルセカンダリインデックス (GSI) は、自動的に同じタグでラベルが付けられる。

    DynamoDB のタグ付け - Amazon DynamoDB

困ったときの回避方法

  • 属性名がDynamoDBの予約語と被ったら
    式の属性名を付ける(DBのas 別名相当)
    Commentは予約語だが、以下のようにするとイケる
     {"#c":"Comment"}
    ※#は必須

補足

色んな解説見て意味不明だったものを記載

  • グローバルセカンダリインデックス(GSI)
    テーブル作成時のPKとは別に、他の属性でPKを作れる。
    テーブルのPK同様、Partision KeyとSort Keyの組み合わせで指定可能
  • ローカルセカンダリインデックス(LGI)
    テーブル作成時のPartision Keyと任意の属性をSort Keyに指定してPKを作れる。

 所感

アプリ屋としてDynamoDBを使うときは、
以下のAPIだけ使えば基本的には良いという印象を持ちました。

  • BatchWriteItem
  • Query

理由

  1. テーブルの作成・削除はアプリ屋では行わない
  2. データの書込みはまとめて送りたい
    ※他のAPI使うと1件しか書込めないので使う理由が見当たらない
  3. データ取得の条件は柔軟性を担保したい

あとは、読書するデータ量が肝なので、このあたりの想定容量をデータの整合性を保つ必要があるときはJSONなど駆使して保ちつつ最小化できるように、テーブル設計してあげれば、地雷はあまり踏まないで使いこなせそう。