DynamoDB
DynamoDBとは
AWSが提供する「サーバレス」の「フルマネージド型NoSQL」データベースサービスです。RDSやAuroraと異なり、データを取得するためにSQLを利用せず、基本的にはアプリケーションから呼び出されるAPIを使用してデータを素早く取得します。
DynamoDBの特徴として
- Key:Value型、またはJSONドキュメントでデータを保存します。
- 可用性、耐久性、スケーラビリティが組み込まれています。
- 水平スケーリング
- イベント駆動プログラミングをサポートします。
DynamoDBの仕組み
DynamoDBのテーブル構造
DynamoDBのテーブル構成は以下の通りです。RDBMSと同様に行をユニークに特定するためにプライマリーキーを指定します。プライマリーキーは、パーティションキー(必須)のみ、またはパーティションキーとソートキーの組み合わせで作成されます。属性は、項目ごとに自由に作成することが可能になっています。DynamoDBでは、パーティションキーのハッシュ値に基づいてDynamoDB内部のパーティションストレージに保存される構成になっています。
プライマリーキーの使い方
パーティションキーのみをプライマリーキーとする場合、下の図では、東京都大阪の気温の値は常に更新されるため、最新の値が入ります。パーティションキーとソートキーの組み合わせをプライマリーキーとする場合、時間がソートキーのため、東京と大阪の気温を履歴として残すことができます。
耐久性と可用性、整合性
DynamoDBは、リージョン内の複数のアベイラビリティーゾーンにテーブルの項目を1秒以内にレプリケーションし、高い耐久性と可用性を実現しています。
整合性は、「結果整合性」と「強い整合性」の2種類あります。
もともと、テーブル1のキー1に対応する値として、値Aが保存されていたとします。キー1の値をBに更新した時に、他のアベイラビリティーゾーンにレプリケーションされるまでに読込があった場合を想定します。
結果整合性は、アベイラビリティーゾーンAとアベイラビリティーゾーンBの両方に読み込みが発生する可能性があるため、値Bと値Aのどちらかが読み出される可能性がありますが、強い整合性は、書き込みが発生しているアベイラビリティーゾーンAのみに読み込みがおこなわれるようになります。DynamoDBのベストプラクティスとしては、アプリケーション側を制御して結果整合性を使用することを勧めています。
読み込みと書き込みキャパシティモード
DynamoDBは必要なリクエストスループットを指定して、プロビジョニングするモードとオンデマンドモードの2種類あります。
プロビジョニングモード
プロビジョニングモードを使用する場合、アプリケーションに必要な1秒あたりの読み込みと書き込みの回数を指定します。
- アプリケーションに対するトラフィックが予想可能である
- トラフィックが一定している、または徐々に増加するアプリケーションである
場合に適しています。
プロビジョニングモードでは、以下の単位でスループットキャパシティを指定します。 - RCU (読み込みキャパシティユニット):1秒あたり1項目(4KB以下)の読み込み
- WCU (書き込みキャパシティユニット):1秒あたり1回(1KB以下)の書き込み
オンデマンドモード
オンデマンドモードは、プロビジョニングモードと異なり、事前に容量を定義する必要がなく読み取り及び書き込みのリクエスト単位での支払いになり、使った分だけ課金されます。
- アプリケーションに対するトラフィックが予測できない
- 作成したテーブルのワークロードが読めない
場合に適しています。
項目リクエストの種類
書き込み
- PutItem:指定されたプライマリーキーに項目を書き込む
- UpdateItem:指定されたプライマリーキーを持つ項目の属性を変更する
- BatchWriteItem:指定されたプライマリーキーに一連の項目を書き込む
- DeleteItem:指定されたプライマリーキーに関連づけられた項目を削除する
読み込み
- GetItem:指定されたプライマリーキーに関連づけられた項目を取得する
- BatchGetItem:指定された一連のプライマリーキーで項目を取得する
- Query:指定されたパーティションキーについて、条件式にあう項目を取得する
- Scan:テーブル内のすべての項目を取得する
セカンダリインデックス
プライマリキー以外の属性に基づいてデータを取得できるニーズに対応するために、別属性をプライマリキーに指定して別テーブルを作成するイメージです。
- ローカルセカンダリインデックス(LSI)
- グローバルセカンダリインデックス(GSI)
の2種類存在します。
ローカルセカンダリインデックス
ローカルセカンダリインデックスは、ベーステーブルと同じパーティションキーを使用して作成されます。ソートキーのみ他の属性と入れ替わるイメージです。
- 結果整合性のある読み取り
- 強い整合性のある読み取り
両方をサポートしています。また、ローカルセカンダリインデックスを作成するタイミングは、ベーステーブルの作成時のみで、ベーステーブルを使用している間は、ローカルセカンダリインデックスを変更することはできません。
グローバルセカンダリインデックス
グローバルセカンダリインデックスは、ベーステーブルと異なる属性でパーティションキーとソートキーを指定して作成することができます。
パーティションキーを変更することもできるため、新しいテーブル用に考えることができます。また、データの変更をベーステーブルからレプリケーションするため、非同期的に反映されます。そのため、結果整合性のある読み込みのみサポートしています。また、グローバルセカンダリインデックスはローカルセカンダリインデックスと異なり、いつでも作成、削除することができます。
DynamoDBストリーム
DynamoDBストリームは、テーブルに対する変更履歴情報を記録するフローです。DynamoDBストリームのレコードは厳密に変更が発生した順番に記録され、24時間利用可能です。DynamoDBストリームを利用することで、イベントドリブンにアプリケーションを拡張することが可能になります。
アトミックカウンタ
DynamoDBのアトミックカウンタを利用して他の書き込みリクエストを妨害することなく、WEBサイトのアクセス数などを追跡させることができます(インクリメントだけでなく、デクリメントも可能)。
実現方法は「UpdateItem」オペレーションを利用して実現します。UpdateItemオペレーションは失敗すると再試行するため、二重計上する可能性があります。そのため、厳密にカウントさせたい場合は利用できません。
ホットパーティション
一部のパーティションに対して、読み書きが集中することを「ホットパーティション」と言います。ホットパーティションな状態になってしまうと、必要な容量がプロビジョニングされたスループットよりも小さく、スロットリングエラーにつながります。対策としては
- ワークロードを分散させる
ことがとても有効だが、これを満たすパーティション設計は難しいため、「ランダムなサフィックスを追加する」方法がある。
例えば、日付をパーティションに設定していた場合、「2021-08-21」このパーティションに対して、乱数を追加することで「2021-08-21.000~2021-08-21.999」のように分散させる。
並列スキャン
デフォルトのスキャンオペレーションでは、データを順次処理していきますが、スキャンするテーブルやインデックスが大きいほどScanを完了するのに時間がかかります。また、一度に1つのパーティションしか読み込むことができないため、単一のパーティションの最大スループットによって制約がかかってしまいます。
並列スキャンでは、テーブルまたはセカンダリインデックスを論理的に複数のセグメントに分割し、複数のワーカーがスレッドを並列してスキャンすることでパフォーマンスが向上します。
queryテクニック
ExpressionAttributeNames
DynamoDB上で予約語に含まれている属性名が存在する場合は、ExpressionAttributeNamesを使用して属性名をプレースホルダー(置換変数)に置き換えて指定する必要があリます。
ExpressionAttributeNames:{
'#n': 'name'
}
ExpressionAttributeValues
filterexpressionやkey-condition-expressionなどのパラメータで属性値の比較を行いたい場合に使用する。
ConditionExpression
DynamoDB上での条件付き書き込みを実現することができます(オプミスティクロック)。
ProjectionExpression
指定した属性のみの値を取得でき、指定されていない属性の値は取得できないように制御することができます。
ConsistentRead
結果整合性のある読み取りではなく、強い整合性のある読み取りを実行したい時に使用します。
ReturnValues
属性の更新、削除する直前の属性値を取得することができます。
FilterExpression
パーティションキー、ソートキー以外の属性を使用してデータを絞り込みたい場合に使用します。
LastEvaluatedkeyとExclusiveStartKey
DynamoDB上で1MBを超えるデータをscanする場合はLastEvaluatedkeyとExclusivestartKeyを使用する。
Discussion