AWS DynamoDB(2)AWS SDK for Javaとアトミックカウンター

JavaによるDynamoDBへのアクセス

AWS SDK for Javaを用いることで、JavaプログラムからDynamoDBにアクセスすることができる。DynamoDBはHashKeyでインデックス化されており、Itemの追加や更新には当該テーブルのHashKeyの情報が必要となる。

DynamoDBインスタンスを取得

Credentialsやテーブル名を指定してDynamoDBインスタンスを指定する。リージョンを明示的に指定しないとデフォルトではバージニア州が指定されてしまう。通常credentialsは、ホームディレクトリ直下の「.aws」ディレクトリ(~/.aws/credentials)に置かれている。

import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import com.amazonaws.services.dynamodbv2.document.DynamoDB;
import com.amazonaws.services.dynamodbv2.document.Table;

// ProfileCredentialsProvider
credentialsProvider = new ProfileCredentialsProvider();
try {
    credentialsProvider.getCredentials();
} catch (Exception e) {
    throw new AmazonClientException("Cannot load the credentials from the credential profiles file. "
                    + "Please make sure that your credentials file is at the correct "
                    + "location (/Users/hoge/.aws/credentials), and is in valid format.", e);
}

// AmazonDynamoDBClient
AmazonDynamoDBClient dynamoDBClient = new AmazonDynamoDBClient(credentialsProvider);
// リージョンの設定
dynamoDBClient.setRegion(Region.getRegion(Regions.fromName("ap-northeast-1")));
// DynamoDB
DynamoDB dynamoDB = new DynamoDB(dynamoDBClient);
// DynamoDB Table
Table dynamodbTable = dynamoDB.getTable(TABLE_NAME);

データの取得

getItemメソッドで、HashKeyを指定することでItemの取得が可能となる。HashKeyの「名称」と「値」を指定することで、Itemを取得できる。

dynamodbTable.getItem(HASH_KEY_NAME, HASH_KEY_VAL);

データの書き込み

DynamoDBは空文字を格納することができない。データを格納する前に空文字チェックを行っておく

データの挿入

putItemメソッドで、Itemの書き込みが可能となる。書き込みを行う際、HashKeyの「名称」と「値」の指定が必須である。なお、同じキーを持つ項目が存在している場合は、全ての値が更新(上書き)される。

Item item = new Item()
		.withPrimaryKey(HASH_KEY_NAME, HASH_KEY_VAL)
		.withString(key, val);
dynamodbTable.putItem(item);

データの更新

updateItemメソッドで、Itemを更新する。HashKeyの「名称」と「値」を指定することで、どのItemを更新するかが決定される。また更新内容は、SETやADD, REMOVEで始まる更新式によって指定する。なお、同じキーを持つ項目が存在している場合は、指定したAttributeのみ置換される。指定したキーが存在しない場合は、新規の項目が作成される。

// 更新するAttributeの名称(Key)
Map<String,String> resultExpressionAttributeNames = new HashMap<String,String>();
resultExpressionAttributeNames.put("#key", KEY_NAME);
// 更新するAttributeの値(Value)
Map<String,Object> resultExpressionAttributeValues = new HashMap<String,Object>();
resultExpressionAttributeValues.put(":val", VALUE);
// Attributeの更新
dynamodbTable.updateItem(
	HASH_KEY_NAME, HASH_KEY_VALUE, // 更新対象のItem(HASH_KEY, VALUE)
	"set #key = :val",
resultExpressionAttributeNames,
resultExpressionAttributeValues);

the provided key element does not match the schema javaというエラーが発生した場合は、誤ったHashKeyを指定している可能性があるので確認する。

アトミックカウンター

DynamoDBは、高い可用性やスケーラビリティ(BASE属性)を確保している一方で、厳密な一貫性や即時反映性(ACID属性)を諦めている。しかし、アトミックカウンター(一貫性のあるカウンタ)をサポートしているため、他の処理を妨げることなく並列に、一貫性のあるカウンタ処理を実施することは可能である。

アトミックカウンターをサポートとあるが、アトミックカウンターという特別に用意された機能が存在するわけでもない。updateItemメソッドを利用して以下のような記述をすると、アトミック性のあるカウンタを実装することができる。

    	Map<String,String> expressionAttributeNames = new HashMap<String,String>();
		expressionAttributeNames.put("#key", kEY_NAME);
		Map<String,Object> expressionAttributeValues = new HashMap<String,Object>();
		expressionAttributeValues.put(":val", 1);
		
		try {
			dynamodbTable.updateItem(
				    HASH_KEY_NAME, HASH_KEY_VAL,  
				    "ADD #key :val",
				    expressionAttributeNames, 
				    expressionAttributeValues);
		} catch (Exception e) {
			
		}

更新式にて単純に1を加算する処理を行っているだけであるので、プログラムを書き換えることで加算もできれば減算もできる。2を足す、3を引くといったことも可能である。

    	dynamodbTable.updateItem(
				    HASH_KEY_NAME, HASH_KEY_VAL,  
				    "SET #key = #key + :val",
				    expressionAttributeNames, 
				    expressionAttributeValues);

としてもよいが、SETアクションの場合、アイテムが事前に存在しない場合にエラーとなるので、ADDアクションで実装したほうがよい。

DynamoDB操作の違い

なお、DynamoDBのそれぞれの操作の差異は以下の通り。

操作 アクション 既にアイテムが存在している場合の挙動
putItem 全ての属性を消去した上で新たに属性を追加する
updateItem SET 対象の属性のみ更新される
updateItem REMOVE 対象の属性のみ削除される
updateItem ADD 対象の属性が数値の場合は値に追加される、セットデータの場合は要素が追加される
updateItem DELETE 対象の属性のセットデータから要素が削除される

AWS DynamoDB(1)DynamoDBとは何なのか

DynamoDBとは

DynamoDBは高速かつフレキシブルな、完全マネージド型のNoSQLデータベース。データはKey, Value型で保存される。高速なレスポンス、スケーラビリティ、ドキュメントデータモデル(JSON)をサポートしていることなどが特徴的。同一リージョン内の3つの設備で同期レプリケーションされるため障害にも強い。

管理不要で信頼性が高い

  • 単一障害点が存在しない構造
  • 同一リージョン内の3つの設備にデータが保存される
  • ストレージの自動パーティショニング

プロビジョンドスループット

  • Read/Writeの速度を指定できる
  • ただし、スケールダウンに関しては1日4回までの制限あり

その他の特徴

  • 容量制限が存在しない
  • 結果整合性
    — 書き込みに関しては、2箇所への書き込みが完了した時点でACK
    — 読み込みに関しては、最新の結果が反映されていない可能性がある

料金

  • 指定したスループットによる時間課金
  • 保存データ量による課金

DynamoDBへのアクセスにはHTTPおよびHTTPSが用いられる。HTTP/HTTPSによる通信はオーバヘッドが大きいため、ゲームアプリ等の早い応答速度が求められるサービスでは、DyamoDBではなくRDSなど他のデータベースを選択することが多い。シリアライズフォーマットとしては、JSON形式が使用される。

データモデル

DynamoDBのテーブルは複数のItemから構成され、Item内には、KeyValue型のデータ(Attributes)が格納されている。各Itemに格納されているAttributesの数は不ぞろいでも良く、あるアイテムにはuser-id, name, e-mail, ageの4つのAttributesが、別のItemにはuser-idのみが格納されているとことも可能である。格納するAttributesのうち1つにHashKeyを指定する。HashKeyはプライマリーキーとして利用でき、ハッシュインデックスを構築されるときのキーとなる。また、RangeKeyを指定することもでき、この場合はHashKey + RangeKeyでプライマリーキーとなる。

DynamoDBは、スカラー型、文字セット、バイナリなどの多値型、マップなどのドキュメント型の3つの形式をサポートしている。格納することのできる値の範囲や制限事項などは、DynamoDB での制限 – Amazon DynamoDBを参照のこと。文字列や多値データセット型は空白や空白セットはサポートされていない。スカラー型の場合、NULL値を格納することは可能である。

パーティショニング

DynamoDBは、スループット性能を維持するためテーブルをパーティショニングすることがある。パーティション間のデータ分散にはHashKeyを用いられ、またスループットは各パーティションに均等に配分されるために、特定のHashKeyにアクセスが偏ると性能が出ない場合がある

セカンダリインデックス(Secondary Index)

セカンダリインデックスは、RangeKey以外に使用することのできる絞込み検索用のAttributesである。ローカルセカンダリインデックス(local Secondary Index)はRangeKeyの代替となる検索用インデックスで、同一HashKeyのItem検索に利用できる。グローバルセカンダリインデックス(Glocal Secondary Index)は、HashKeyの代替となる検索用インデックスで、異なるHasyKeyのItem検索にも利用できる。セカンダリインデックスは便利ではあるが、追加のスループットやストレージを必要とするためRDSで代替できないか検討すべきである。