AWS DynamoDB

(株)HIRO ICT 研究所の「空間知能化システム」で使用するAWS DynamoDBをご紹介します。

AWS Console

AWS CLIをインストールした後の初期設定

AWS CLIをインストールした後の設定についてです。AWS CLIを使用してAPIを利用するためには、AWSから発行されたアクセスキー(アクセスキーID、シークレットアクセスキー)の設定が必要になります。でないとAWSにアクセスできませんからね。この認証情報の設定に関しては複数のパターンがありますので以下にまとめていきたいと思います。

また、シークレットアクセスキーはアクセスキーの作成時にしか確認・ダウンロードができませんので必ずCSVファイルをダウンロードしておきましょう。もし忘れてしまった場合はアクセスキーを再度作り直す必要があります。

設定コマンド(configure)を使う

次のコマンドを使用することで自動で認証情報と設定ファイルが作成されます。

$ aws configure

コマンドを実行すると以下4項目が順番に表示されるので入力してください。

AWS Access Key ID [None]: xxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxx
Default region name [None]: ap-northeast-1
Default output format [None]: json

AWS Access Key ID [None] と AWS Secret Access Key [None] にはユーザー作成時にダウンロードしたファイル内の値を入力します。

Default region name [None] にはデフォルトリージョンを指定します。ap-northeast-1 は東京です。 リージョンの種類に関してはこちら(AWS リージョンを選択する | Amazon Elastic MapReduce

Default output format [None] にはコマンド出力結果の表示形式を指定します。json、table、textの3種類から選択してください。

設定が終わると~/.awsディレクトリに認証情報(credentials)と設定ファイル(config)が作成されています。

$ ll ~/.aws
total 16
-rw-------  1 xxxxxx  staff   48 10 25 18:47 config
-rw-------  1 xxxxxx  staff  116 10 25 18:47 credentials

入力した値が設定されているか確認しましょう。

$ cat ~/.aws/config
[default]
output = json
region = ap-northeast-1

$ cat ~/.aws/credentials 
[default]
aws_access_key_id = xxxxxxxxxx
aws_secret_access_key = xxxxxxxxxx

環境変数にセットする

環境変数にセットすることでAWSにアクセスする事も可能です。以下が環境変数の対応表です。(トークンについては表に含めてますが今回の内容からは除外します)

対象 設定ファイル変数 環境変数 オプション

アクセスキーID aws_access_key_id AWS_ACCESS_KEY_ID -

シークレットアクセスキー aws_secret_access_key AWS_SECRET_ACCESS_KEY -

リージョン region AWS_DEFAULT_REGION --region

出力 output AWS_DEFAULT_OUTPUT --output

プロファイル profile AWS_DEFAULT_PROFILE --profile

設定ファイル - AWS_CONFIG_FILE -

トークン aws_security_token AWS_SECURITY_TOKEN -

コマンドを実行する前に環境変数にセットしてやれば、aws configureコマンドを使用して認証情報と設定ファイルを作成しなくてもコマンドを実行する事ができます。

$ export AWS_ACCESS_KEY_ID=xxxxxxxxxx
$ export AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
$ export AWS_DEFAULT_REGION=ap-northeast-1
$ export AWS_DEFAULT_OUTPUT=json

$ aws ec2 describe-instances

また、AWS CLIでの優先順位は次の通りなので、既に認証情報と設定ファイルが作成されていたとしても、環境変数が優先されます。

環境変数

AWS認証情報 ~/.aws/credentials

CLI構成ファイル ~/.aws/config

インスタンスプロファイルの認証情報

複数のProfile情報を使い分ける

認証情報と設定ファイルには複数のProfileを指定しておく事ができます。aws configureコマンドに--profile [name]のオプションを付けて実行してください。

$ aws configure --profile tasknotes
AWS Access Key ID [None]: xxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxx
Default region name [None]: ap-northeast-2
Default output format [None]: json

そうすると認証情報と設定ファイルがオプションに指定した名前で以下のように更新されます。

$ cat ~/.aws/config 
[default]
output = json
region = ap-northeast-1
[profile tasknotes]
output = json
region = ap-southeast-2

$ cat ~/.aws/credentials
[default]
aws_access_key_id = xxxxxxxxxx
aws_secret_access_key = xxxxxxxxxx
[tasknotes]
aws_access_key_id = xxxxxxxxxx
aws_secret_access_key = xxxxxxxxxx

このProfileをコマンド実行時に指定したい場合は、環境変数AWS_DEFAULT_PROFILEにセットするか

$ export AWS_DEFAULT_PROFILE=tasknotes
$ ec2 run-instances --image-id ami-4985b048 --instance-type t2.micro

コマンドのオプションで--profileを指定するかです。

$ aws --profile tasknotes ec2 run-instances --image-id ami-4985b048 --instance-type t2.micro

実行してみると指定したProfile情報が適用されていますね。

f:id:tasukujp:20141026191544p:plain

別の設定ファイルを使用する

環境変数AWS_CONFIG_FILEに別の設定ファイルを指定しておくことでコマンド実行時に~/.aws/ディレクトリ以外を参照させることができます。

$ export AWS_CONFIG_FILE=~/dev/AWS/myconfig

この状態で configure コマンドを実行。

$ aws configure
AWS Access Key ID [****************TRQQ]: test
AWS Secret Access Key [****************kOJS]: test
Default region name [None]: us-west-2
Default output format [None]: text
myconfig ファイルが作成されています。
$ ll ~/dev/AWS

total 24
-rw-------  1 xxxxxx  staff   43 10 25 19:40 myconfig

$ cat ~/dev/AWS/myconfig 
[default]
output = text
region = us-west-2

ただし、認証情報のアクセスキーIDとシークレットキーはデフォルトのファイルが更新されてしまいますので気を付けましょう。あくまで設定ファイルだけです。

$ cat ~/.aws/credentials 
[default]
aws_access_key_id = test
aws_secret_access_key = test

コマンド補完機能

AWS CLIでコマンド補完が使えます。シェルによって方法が違いますので、まず現在使用してるシェルを確認してください。基本bashになってると思います。

$ echo $SHELL
/bin/bash

ちなみに現在使えるシェルを知りたい時は /etc/shells を確認します。

$ cat /etc/shells
/bin/bash
/bin/csh
/bin/ksh
/bin/sh
/bin/tcsh
/bin/zsh

使ってるシェルにあわせて以下のコマンドを実行することで aws cli のコマンド補完が使えます。

bashの場合(Cは大文字)

$ complete -C aws_completer aws

tcshの場合

$ complete aws 'p/*/`aws_completer`/'

zshの場合

$ source bin/aws_zsh_completer.sh

設定されたか確認してみます。

$ complete -p
complete -C aws_completer aws

これで補完機能が使えるようになりました。コマンド入力途中で tab キーを押して下さい。候補が複数ある場合は tab を2回押すと一覧で表示され、候補が一つしかない場合はコマンドが全て表示されて後ろにスペースがつきます。

$ aws ec2 describe-in
describe-instance-attribute   describe-instance-status      describe-instances            describe-internet-gateways

しかし、このままだとターミナルを再起動したら設定が消えてしまいますので.bash_profile にコマンドを加えておきます。これで再起動時に自動でコマンドを実行してくれます。

$ echo 'complete -C aws_completer aws' >> ~/.bash_profile

参考:

aws/aws-cli ・ GitHub

Configuring the AWS Command Line Interface - AWS Command Line Interface

DynamoDBの使い方

セカンダリインデックス

ローカルセカンダリインデックス(LSI)

こっちはプライマリキーのタイプが"Hash key + Range key"の場合のみ設定可能。

簡単にいうと、別のRange keyを増やすようなイメージ。

例えば以下のような注文履歴テーブルがあるとする。

このテーブルは顧客ID(Hash key)と注文日(Range key)がプライマリキー。

グローバルセカンダリインデックス(GSI)

こっちはプライマリキーのタイプによらずに設定可能。

ローカルセカンダリインデックスのHash keyがプライマリのHash key固定なのに対し、 こちらは別のHash key (+ Range key)を設定することができる。

属性の射影

セカンダリインデックスを張るというのは、セカンダリインデックス用のテーブルを作るイメージに近い。

つまりそれだけストレージ容量を食うので、データサイズが大きい場合は注意する必要がある。

どのくらい追加でストレージが必要なのかは、セカンダリインデックスを作成する際に設定する

属性の射影設定に依存し、最大で2倍となる。

テーブルに定義された属性をインデックス側にも含めることを「射影」といって、 DynamoDBではテーブル作成時に射影設定を以下の3タイプから選択できる。

  • ・All Attributes (全ての属性を射影)
    →テーブルにある全ての属性を射影する
    →これが一番容量を食うタイプで、追加で必要なストレージサイズは2倍となる。
  • ・Table and Index Keys (キー属性のみを射影)

    →Hash keyやRange keyといったキー属性のみを射影する

  • ・Specify Attributes (射影する属性を指定)
    →射影する属性を指定できるが、最大20個まで

  • →つまり射影したい属性が21以上ある場合は"All Attributes"を選択する必要がある

射影しなかった属性データはインデックスでのクエリ結果に含まれないので、 クエリした際に欲しい属性は射影しておく必要がある。

もし射影してない属性データが欲しい場合は改めてテーブル側から取得する必要があり、 その分余計なユニットを消費してしまうので逆にコストが高くなることも。

Amazon RDSとの比較篇

RDBとNoSQL

ACIDなRDB

一昔前、一般的に「データベース」と言えば、多くはリレーショナルデータベース(RDB)のことを指していました。テーブルと呼ばれる「行とカラムで構成される二次元のデータ構造」に対して、SQLと呼ばれる強力なクエリ言語で操作を行い、データの一貫性(Consistency: どこから観測しても同じ値が得られること)や操作の原子性(Atomicity: 一連の操作を全て適用commitするか、全てキャンセルrollbackするかの二択として実現できること)を実現するモデルは、開発者を含むシステムの利用者にとって非常に理解しやすく、広く受け入れられて来ました。多くの方がご存知の通りです。

このようなデータベースが持つ強い整合性を伴う特徴を、ACID(Atomicity・Consistency・Isolation・Durability)特性と呼ぶことがあります。

また、RDBはSQLによって、あらゆるカラムをWHERE句の条件に指定でき、自由自在にデータを絞り込んで検索することが可能です。インデックスの有無によるパフォーマンスの違いはありますが、検索条件の自由度が非常に高いのも大きな特徴です。

さてその一方で、システムに対する要求(本稿の話題においては特に非機能要求)は日に日に高まり、高い可用性(Availability: データが常に読み書きできること)と拡張性(Scalability: 大量のデータ書き込み/読み出し要求に応えるための規模拡張が容易にできること)が求められるシステムが多くなって来ています。

要するに、基本的にシステムのダウンは許さん。そして大量のデータアクセスに耐えられるようにせよ。という要求です。

一般的に、高い可用性を得るには「冗長化」作戦が有効です。データのコピーを複数のノードに持ち、仮にノードの1つが障害を起こしても他のノードが応答できる状態を作るのです。RAID1と言えば分かる人には分かりやすいでしょうか。

また高い拡張性は「シャーディング」作戦が有効です。これもまた複数のノードを用意し、データごとに受け持つノードを分けることで、性能を担保します。こちらはRAID0と言えば分かりやすいかもしれません。

ただ、このようにデータを分散して保持すると、一貫性の維持が困難になります。データの書き換え時に、全ノードに変更が行き渡ることを保証するのが大変なのです。結果として、一貫性と可用性の両立には大きな困難が伴います。

一貫性のあるデータベースは、前述の通り理解しやすく説明もしやすい(例えばお客様に対して)ため、高可用性・高拡張性を要件としないシステムにおいては第一選択となります。

BASEなNoSQL

一方、冷静に考えると、実は「一貫性」というのは(そりゃ、あるに越したことは無いんでしょうが)実は必須でない場合があります。確かに説明がしやすいですが、例えばデータの編集操作をしたらその瞬間以降は、確実に新しい値が見えるべきで、一瞬たりとも古い値が見えてはならない、という要件は必ずしも必須でない場合があります。もちろん無いとは言いませんが。

例えば「書き換えたはずなのに古い値が見えるなんて、なんか気持ち悪い。お客様にどう説明しよう?」と悩むのは嫌なので一貫性が欲しい。また、ダウン時の機会損失が大きなシステムであるため、可用性の低下は許容できない。この場合、簡単に(低コストで)これらを両立させることは難しいので、一貫性に関する考えを精査していくことが求められます。精査の結果「システム要件として絶対に一貫性が必要である」という結論となると詰むかもしれませんが、前述の通り「なんか気持ち悪い」というだけであれば、その気持ち悪さと機会損失どっちを取るんだ、という選択を迫ることになります。

つまり、高可用性・高拡張性を要件とするシステムにおいては、一貫性を一部犠牲にすることで大きな価値を得られるがあるケースがあります。このようなケースにハマるデータベースが、いわゆるNoSQLです。

NoSQLはACIDではなくBASE(Basically Available・Soft state・Eventually consistent)という特性をで語られます。細かい説明は他の資料に譲りますが、BASE *1は高い可用性を持ちます。そして、一貫性が無いとは言え、それは即座に一貫性が保証されないだけで、結果的(Eventually)には一貫性を持つ状態に収束する、所謂「結果整合性」という特徴を持っています。

ところで、前述の通り、RDBの検索条件の自由度は高い一方、NoSQLでは(一般的に)事前にキーとして指定した要素を使うことでしか目的のデータを探せません。キーとして指定した要素以外を使って値を探し出したい場合は、全体をスキャン(走査)して条件に一致するものを1つ1つ選別していく必要があり、パフォーマンス面で非常に不利(大抵の場合、非現実的)となります。

というわけで、高い可用性または拡張性を要求するシステムにおいては、一定の条件を飲むことができれば、NoSQLが第一選択となり得ます。

RDSとDynamoDB

さて、AWSにおいてRDBの代表プロダクトは「RDS」、NoSQLの代表プロダクトは「DynamoDB」であります。

ACIDなRDS

前述のとおり、RDSは高い一貫性を持ちます。では、可用性や拡張性は無いのでしょうか?

いや、無いと言ってしまうとあんまりなんですが、まぁ弱いんです。

RDSは、Multi-AZの構成にしたとしても、稀に何らかの障害等により、MasterからSlaveへのフェイルオーバーが発生することがあります。そしてこのフェイルオーバーの処理を行っている数分間は、可用性が損なわれます。また、障害ではなかったとしても、例えばセキュリティパッチの適用等の目的で、メンテナンスウィンドウにおける再起動が起こることがあります。つまり、RDSにおいてはサービスレベルの設計時点でメンテナンスウィンドウにおいて可用性が損なわれることは織り込み済みの事象と言えます。

また、拡張性については、RDSはスケールアップのみをサポートします。つまり、インスタンスタイプの変更です。規模の拡大に伴ってスケールアップを繰り返すと、すぐに限界が訪れてしまう可能性があります。読み込みだけに絞れば、Read replicaによるスケールアウトに対応しますが、レプリカをぶら下げられる数にも一定の制限があり、比較的天井が低いのが実情です。

逆に言えば、この「織り込み済みの可用性低下」や「拡張性の天井」を許容できないシステムにおいては、RDSという選択をしてはいけません。


Amazon RDS

BASEなDynamoDB

という状況から生まれたのがDynamoDBです。DynamoDBは高い可用性を持ちます。言い換えると、織り込み済みの可用性低下は無く、基本的にいつでも利用可能(Basically Available)であることを想定してサービス設計がされています。

また、テーブル設計(キー設計)に一定の考慮が必要ではあるのですが、水平スケーリング(シャーディングによるキャパシティの確保)の機能を持ち、想定した負荷に対応できるような体制を構えることが可能です。

一方、一貫性はEventualであるため、データを更新した直後には一定の確率で古いデータが取得できてしまうことがあります。しかしその状態は長くは続かず(通常1秒以内と言われています)、結果的には常に新しいデータが取得できるようになります。ただし、DynamoDBには「強い整合性の読み込み」というモードがあり、この操作を行うと、費用と引き換えに、必ず新しい値を返すことを要求できます。便利!

そして、DynamoDBにはトランザクションがありませんので、2つの操作をall or nothingで行う原子性を持たせる機能はありません。が、この辺りはどうしても欲しければクライアント側で頑張って実装したりすると実現可能なようです。難しそうですが。

また、先ほども触れた通り、DynamoDBでは自由な絞り込み条件で値を探すことができません。事前に設定したキーに対応する値を取ってくるのが基本的な操作です。DynamoDBでは、1つのテーブルにつき1つの主キーを設定できますが、それに加え、5つのセカンダリインデックスと呼ばれるキーを設定できます。つまり、事前に決定した1+5通りの要素で検索ができます。しかし、それ以外の要素による検索は、全走査による選別作業になってしまいます。

この点は、後からいかようにでもWHERE句で検索条件を指定できるRDBと違い、テーブル設計の重要性がRDB以上に大きいと言えます。


Amazon DynamoDB

まとめ

RDSDynamoDB
一貫性強力結果整合なので基本的に弱い(強整合性指定も可能)
原子性あるない(同じアイテム内の更新であれば可能)
検索条件SQLのWHERE句で自由自在事前指定のキーまたはインデックスのみ
可用性メンテナンスウィンドウあり基本的に常に利用可
拡張性スケールアップのみで天井が低いシャーディングによるスケールアウトが可能

いかがでしたでしょうか。AWS上で稼働するシステムのデータストアとして、RDSを選ぶ場面とDynamoDBを選ぶ場面、それぞれぼんやりとでも想像できましたでしょうか。

例えばマイクロサービス的なコンポーネントを作っていて、複数のノード間でシンプルなデータ共有をする必要がある場合を考えてみます。楽なのはRDSを立ててしまうことですが、メンテナンスウィンドウ等による可用性低下を受け入れる必要があります。

仮に大した性能要件も必要なかったとしても、シンプルなデータ共有なのであれば、可用性を求めてDynamoDBを使う、という選択肢が出てきます。性能要件が小さければ、RDSインスタンスを維持する場合と比較して、費用面でも有利になる可能性があります。

システム設計時の選択肢として、是非DynamoDBもあなたの道具箱に入れておいてください。

最後に余談ですが、このRDSとDynamoDBのサービスアイコン。RDSはモノリシックなコンポーネントとしてドンと鎮座しており、DynamoDBはシャーディングによる水平スケーリングを実現している。そんな想いが込められているのでしょう。

脚注

余談ですが、ACID(酸)に対してBASE(塩基=アルカリ)とは、なかなか上手にシャレを当ててきたなぁ、と思います、ハイ。 ゥ!

ハッシュキーテーブル篇

要するに、即時一貫性・操作の原子性・検索条件の自由度を犠牲にして、可用性と拡張性を手に入れたデータベースがDynamoDBであります。 では具体的に、データの読み書きはどのように行うのでしょうか。

DynamoDBにおけるコンセプト

DynamoDBには主に「table」「item(項目)」「attribute(属性)」という3つの概念が現れます。それに従属する概念として「キー」「インデックス」が出てきます。まずはこの辺りを整理していきましょう。

tableというのはみなさん分かりやすいでしょう。概ねRDBで言うところのテーブルに相当し、itemの集合体です。itemについても、概ねRDBで言うところのrow(行)に相当し、attributeの集合体です。そしてattributeといのも、概ねRDBで言うところのcolumn(列)に相当します。

ただ、DynamoDBにおけるitemは、正規化を行う必要はなく、要するに1つのJSONオブジェクトの形で表現できるデータがitemに相当します。つまり、データとしては文字列でも配列でも、ネストされたオブジェクトでも構わない、ということです。下記にitemの一例を示します。これは製品情報(ProductCatalog)というtableに入っている2つのitemのイメージです。

{ 
  "Id": 101,
  "ProductName": "Book 101 Title",
  "ISBN": "111-1111111111",
  "Authors": [ "Author 1", "Author 2" ],
  "Price": -2,
  "Dimensions": "8.5 x 11.0 x 0.5",
  "PageCount": 500,
  "InPublication": true,
  "ProductCategory": "Book"
}
{
  "Id": 205,
  "Title": "20-Bicycle 205",
  "Description": "205 description",
  "BicycleType": "Hybrid",
  "Brand": "Brand-Company C" ,
  "Price": 500,
  "Gender": "B", 
  "Color": [ "Red", "Black" ],
  "ProductCategory": "Bike"
}

この、IdとPriceとProductCategoryくらいしか共通点のない感じ。RDBのテーブル設計の考え方からはちょっとかけ離れた印象を受けると思いますが、NoSQLデータベースとは得てしてそういうものです。

key-valueによるデータ保存

さて、こんな感じでtableにitemが一杯入ってますよ、というところまではよろしいかと。ただし、データベースはデータの読み出しが出来なければ意味がありません。SQLの考え方では SELECT * FROM ProductCatalog WHERE BicycleType = 'Hybrid'; なんてことをすると思いますが、その手は使えません。前述の通り、DynamoDBでは一定の「検索条件の自由度」を諦めています。

結論から言えば、Idでしか探せません。「Idが205のアイテムをください(GetItem)」です。もしくは「探すんじゃなくて全部ください(Scan)」です。両極端。

多くのプログラミング言語には、Mapや連想配列等と呼ばれるデータ構造があると思います。これは、あるデータを「key」と「value」の組として記録し、「key」を与えることで「value」を取り出せる、というものですね。これと同じです。

var productCatalog = {
  "101": { 
    "Id": 101,
    "ProductName": "Book 101 Title",
    // ...
  },
  "205": {
    "Id": 205,
    "Title": "20-Bicycle 205",
    // ...
  }
}

このようなJavaScriptのオブジェクトから、自転車のitemを取り出したかったらproductCatalog["205"] ですよね。一方、BicycleTypeがHybridのものを探したかったら、

Object.keys(productCatalog).forEach(function(key){
  if (productCatalog[key]["BicycleType"] == "Hybrid") {
    // ...
  }
});

とか何とかするんでしょうねぇ。こんなイメージです。DynamoDBでは、テーブル作成時にあらかじめ「Idをキーとして利用しますよ」という宣言をし、その上でデータを保存します。その結果、そのキーを使ってデータを取り出せます。万が一、キー以外のもので検索したくなったら、全件ループScanで頑張るしか道がありません。

DynamoDBにおいて、キーはitem上に必須となります。つまり{"foo": "bar"}というデータはProductCatalogに保存できません。また、キーの値は重複できません。つまり{"Id": 1, "foo": "bar"}と{"Id": 1, "baz": "qux"}を同じテーブルに同時に格納できません。

つまり、全てのデータはキーによって一意に特定でき、キーによる検索は0個または1個のitemを返します。この辺りはRDBにおける主キーと非常に似ていますね。この操作を、DynamoDBではGetItemと呼びます。

ここに示したようなキーのことを「ハッシュキー」と呼びます。また、ハッシュキーを宣言したDynamoDBのtableを、本稿では便宜的に「ハッシュキーテーブル」と呼びます。

参考までに、DynamoDBのtableには「(ハッシュキーを宣言した)ハッシュキーテーブル」と「(ハッシュ+レンジの複合キーを宣言した)複合キーテーブル」の2種類があります。しかし、複合キーテーブルについては次回以降に触れる予定で、今回はハッシュキーテーブルに話題を絞ります。ちなみに「ハッシュキーテーブル」「複合キーテーブル」の両者とも正式な用語ではなく、本稿独自で便宜的に名づけたものなので、利用にあたってはご注意ください。

ハッシュキーテーブルにおける拡張性担保

さて、ここからは一段レベルを上げた話をします。

DynamoDBでは高い拡張性(大量の読み書きリクエストに耐えうる)を持っています。具体的にはどのように性能を担保しているのでしょうか。

性能の担保は、Amazon RDSとの比較で学ぶDynamoDBで触れた通り、「シャーディング」作戦が有効であり、DynamoDBにおいても同様です。つまり、高い性能を必要とする場合は、複数のノードを用意し、データごとに受け持つノードを分けて対応します。このノードのことを、DynamoDBにおいては「パーティション」と呼びます。

もっと具体的な話に落としこんでみましょう。(ただし、DynamoDBは具体的な実装を公表していませんので、下記はイメージを助けるための想像でしかありませんのでご注意ください。)

例えば、ProductCatalogテーブルに必要な性能の確保のためには16個のパーティションが必要だと判断し、それを用意した場合を考えます。それぞれのパーティションに 0, 1, 2...9, a, b...f という番号を付けます。

この状態でDynamoDBが上記のBookのデータを書き込むリクエストを受けた場合、どのパーティションに書き込めばいいでしょうか。キーである"101"というデータにハッシュ関数SHA-1を適用すると、その結果はdbc0f004854457f59fb16ab863a3a1722cef553fです。この結果の1桁目はdなので、このデータはパーティションdに書こう。とまぁこんな感じです。(これはあくまでも理解のための描写で、実際はconsistent hashing法とか使ってるはずです。)

その後、DynamoDBが"101"のデータをくれという読み込みリクエストを受けた場合、どのパーティションを探しに行けばいいでしょうか。同じ計算をすることによって、このデータはパーティションdに格納されていることが分かるため、値を探しやすくなります。

上記の読み書き操作においては、パーティションd以外は負荷が全く掛かりません。また、"102"のパーティションはc、"103"は9、という感じで、すべてのデータが確率的には均一に全てのパーティションに分散するため、パーティション1つだけで受け持つ状況とくらべて16倍の性能が確保できることになります。

partitionkeyvalue
7104{ ... }
7106{ ... }
9103{ ... }
c102{ ... }
d101{ ... }
e105{ ... }

上記のように、もちろん同じパーティションに属するキー(104と106)もあります。ハッシュ関数によってパーティションを決定する要素となるキーだから「ハッシュキー」と呼ばれるんですね。この技術は、DynamoDBのパフォーマンス担保に大きな役割を果たしています。

DynamoDBにおける可用性担保と結果整合性

可用性の担保は、Amazon RDSとの比較で学ぶDynamoDBで触れた通り、「冗長化」作戦が有効であり、DynamoDBにおいても同様です。具体的には、DynamoDBはデータをコピーして3箇所に分散配置保持しています。仮に1つのノードが障害のため応答を返せなくなったとしても、残り2つのノードが応答できれば可用性の低下はありません。

ところで、DynamoDBには結果整合性という特性があります。つまり、データを更新した直後には一定の確率で古いデータが取得できてしまうことがあります。

この2つの特徴には高い関連性があります。こちらもイメージをつかむために、もっと具体的な話に落としこんでみましょう。(こちらも、DynamoDBは具体的な実装を公表していませんので、下記はイメージを助けるための想像でしかありませんのでご注意ください。)

まず、あるデータが3つのノードにおいて「foo」と記録されている状態をイメージします。

node-Anode-Bnode-C
foofoofoo

ここでDynamoDBが「このデータをbarに書き換えて」というリクエストを受け付けたとします。最終的に、DynamoDBの目標は、3つとも全てをbarに書き換えることです。が、DynamoDBは3つ中2つのデータが更新されたことを確認し次第、クライアントに「OK、できたよ」という成功のレスポンスを返してしまいます。

node-Anode-Bnode-C
foobarbar

この時、クライアントがこのデータを読み出そうと試みると、ランダムに1つのノードを選択し、その値を返します。つまり1/3の確率で"foo"(古いデータ)を返すことがわかります。ただし、この状態は長く続かず、DynamoDBはすみやかに3つ目のノードにも新しいデータを伝播させようとします。

さて一方で、DynamoDBのデータ読み込みリクエストには「強い整合性の読み込み」というオプションがあります。DynamoDBは強い整合性の読み込みリクエストを受けると、ランダムに2つのノードを選択し、その値を比較します。値が一致した場合(ランダムに選んだ2つがnode-Bとnode-Cだった場合)はその値"bar"を返し、もし値が不一致だった場合は残りの1つも読み出して、多数決で多い方の値"bar"を返します。つまり、必ず"bar"(新しいデータ)を返すことがわかります。

これを考えると、強い整合性の読み込みは、結果整合性読み込みと比較して2倍0それ以上のreadコストを掛けているわけで、スループットを2倍消費することにも合点が行きますね。

参考

Amazon - DynamoDB Strong consistent reads, Are they latest and how? - Stack Overflow

複合キーテーブル篇

今回のサンプルデータ

フォーラム・スレッド・返信投稿という3要素で構成した掲示板のデータベースとして、それぞれForum, Thread, Reply というDynamoDBのtableがあり、 下記のようなitemがそれぞれのtableに入っているようなイメージをしてみてください。

// Forum
{
  "Name": "DynamoDB",
  "Category": "Amazon Web Services",
  "Threads": 3,
  "Messages": 4,
  "Views": 1000,
  "LastPostBy": "User A",
  "LastPostDateTime": "2012-01-03T00:40:57.165Z"
}
{     
  "Name": "Amazon S3",
  "Category": "AWS",
  "Threads": 1
}
// Thread
{
  "ForumName": "DynamoDB",
  "Subject": "DynamoDB Thread 1",
  "Message": "DynamoDB thread 1 message text",
  "LastPostedBy": "User A",
  "Views": 0,
  "Replies": 0,
  "Answered": 0,
  "Tags": [ "index", "primarykey", "table" ],
  "LastPostDateTime": "2012-01-03T00:40:57.165Z"
}
{
  "ForumName": "DynamoDB",
  "Subject": "DynamoDB Thread 2",
  "Message": "DynamoDB thread 2 message text",
  "LastPostedBy": "User A",
  "Views": 0,
  "Replies": 0,
  "Answered": 0,
  "Tags": [ "index", "primarykey", "rangekey" ],
  "LastPostDateTime": "2012-01-03T00:40:57.165Z"
}
{
  "ForumName": "Amazon S3",
  "Subject": "Amazon S3 Thread 1",
  "Message": "Amazon S3 Thread 1 message text",
  "LastPostedBy": "User A",
  "Views": 0,
  "Replies": 0,
  "Answered": 0,
  "Tags": [ "largeobject", "multipart upload" ],
  "LastPostDateTime": "2012-01-03T00:40:57.165Z"
}
// Reply
{
  "Id": "DynamoDB#DynamoDB Thread 1",
  "ReplyDateTime": "2011-12-11T00:40:57.165Z",
  "Message": "DynamoDB Thread 1 Reply 1 text",
  "PostedBy": "User A"
}
{
  "Id": "DynamoDB#DynamoDB Thread 1",
  "ReplyDateTime": "2011-12-18T00:40:57.165Z",
  "Message": "DynamoDB Thread 1 Reply 1 text",
  "PostedBy": "User A"
}
{
  "Id": "DynamoDB#DynamoDB Thread 1",
  "ReplyDateTime": "2011-12-25T00:40:57.165Z",
  "Message": "DynamoDB Thread 1 Reply 3 text",
  "PostedBy": "User B"
}
{
  "Id": "DynamoDB#DynamoDB Thread 2",
  "ReplyDateTime": "2011-12-25T00:40:57.165Z",
  "Message": "DynamoDB Thread 2 Reply 1 text",
  "PostedBy": "User A"
}
{
  "Id": "DynamoDB#DynamoDB Thread 2",
  "ReplyDateTime": "2012-01-03T00:40:57.165Z",
  "Message": "DynamoDB Thread 2 Reply 2",
  "PostedBy": "User A"
}

うんうん、まぁよくありそうな感じですね。タグ辺りが正規化されていないのも、item毎にattributeの数や種類が違うのも、NoSQLならではです。

さて、このデータにもとづいて「フォーラム一覧画面」「DynamoDBフォーラムのスレッド一覧画面」「DynamoDB Thread 2の投稿一覧画面」を表示することを考えてみましょう。この場合、どのattributeをキーにすると良いでしょうか。

まず、ForumtableについてはNameがハッシュキーということで問題ないでしょう。全item取得の操作(これをDynamoDBではScanと呼びます)をすればフォーラム一覧画面が作れますね。

しかし、その他の画面用のデータアクセスについては、ハッシュキーテーブルとしては設計が難しそうです。というのも、ハッシュキーテーブルに対しては「キーを指定した1件取得(GetItem)」か「全件取得(Scan)」という選択肢しかありません。

この問題に対応するために、DynamoDBでは「一定の規則で並んだitemのリストから、特定の範囲を切り出して複数個のitemを取り出す(Query)」という取得操作を提供しています。ただし、Queryはハッシュキーテーブルに対しては実行できません。(正確には、実行できるが無意味)

複合キーテーブル

ハッシュキーテーブルでは、table作成時に1つのattributeを選び、それをハッシュキーとして宣言しました。

そうではなく、table作成時に2つのattributeを選び、1つをハッシュキーとして、もう一つをレンジキーと呼ばれるキーとして宣言する、という方法があります。この方法で定義したtableを「複合キーテーブル」と呼ぶことにします。(ハッシュキーテーブル及び複合キーテーブルは、本稿で便宜上名づけたもので、公式用語ではありませんのでご注意ください。)

さて具体的に。先ほどのThreadtableは、ForumNameをハッシュキーとして、そしてSubjectをレンジキーとして宣言した複合キーテーブルとします。また、Replytableは、Idをハッシュキー、ReplyDateTimeをレンジキーとして宣言します。

この2つのattributeは複合キーとして働きます。つまり、2つの値の組み合わせによって、1つのitemを特定します。ThreadtableにおいてForumName = 'DynamoDB' AND Subject = 'DynamoDB Thread 1'であるitemは一つだけしか保存できません。(2つ目を保存しようとすると古いitemを上書きします。)

言い換えると、ハッシュキーだけではitemを1つに特定できません。具体例を見てもそうなっていると思います。ThreadtableにおいてForumName = 'DynamoDB'であるitemは複数ありますね。

これがハッシュキーテーブルと異なるポイントです。ハッシュキーテーブルのハッシュキーは単独で重複を許しませんでしたが、複合キーテーブルのハッシュキーは、単独であれば重複が許されます。ここは理解のポイントだと(勝手に)思ってます。私がそうだったものでw

さて、このようなtableに対する読み出し操作 Scan, GetItem, Query をそれぞれ見ていきましょう。

まずScanはハッシュキーテーブルと全く同じです。パラメータ無くとにかく問い合わせれば全件返ってキます。

次にGetItemの場合は、ハッシュキーの値をレンジキーの値2つを与えます。その結果、0個または1個のitemを返します。複合主キーを使ったRDBの挙動と一緒ですね。

そしてQueryです。多分一般的な説明をしてもわかりづらいので、まずはThreadtableで考えてみましょう。Threadtableでは、ForumNameがハッシュキー、Subjectがレンジキーでした。このtableに対してForumName = 'DynamoDB'という条件でQueryができます。つまり「DynamoDBフォーラムのスレッド一覧画面」で必要なリストが取れます。

続いてReplytableです。こちらはIdがハッシュキー、ReplyDateTimeがレンジキーでした。このtableに対してId = 'DynamoDB#DynamoDB Thread 1' AND ReplyDateTime BETWEEN '2011-12-15T00:00:00.000Z' AND '2011-12-31T23:59:59.999Z' というような条件でQueryができます。そう、レンジキーで指定したカラムは、範囲(range)を検索条件として指定できるのです。もちろん、上記Threadの例の通り、レンジキーに対する条件は省略(つまりハッシュキーだけによる絞り込み)も可能です。

ちょっと複雑に感じるでしょうか。このような検索操作ができる(そして、そうでない検索操作が難しい=提供されていない)理由は、次にお話するパーティションの話によって理解しやすくなると思いますので、引き続きお付き合い下さい。

とりあえずここまでの話をまとめるとこんな感じです。

ハッシュキーテーブル複合キーテーブル
Scan全件取得全件取得
GetItemhash-keyに対するequal-to条件値を1つ指定して、001件取得hash-keyとrange-key両者に対するequal-to条件値を指定して、001件取得
Query(無意味)hash-keyに対するequal-to条件値を1つ、range-keyに対する範囲条件(optional)を指定して、00複数件取得

複合キーテーブルにおけるパーティショニング

さて、複合キーテーブルもDynamoDBとして性能の担保のためのパーティショニングを行っています。あるitemをどのパーティションに保存すべきかは、ハッシュキーテーブルの時と同じ、ハッシュキーに基づいて決定しています。

ただし、複合キーテーブルでは、1つのハッシュキーにつき複数の(レンジキー値の異なる)itemがあるため、それらが全て同じパーティション内に保存されることになります。そしてもう一つ。同じハッシュキーを持つitem群は、レンジキーによってソートされた状態で保存されています、多分。(実装は非公開のため、予想です)

具体的には下記の表を見てください。これはReplytableの例です。ハッシュキーによって、パーティションが1番と3番に分かれています。そして、レンジキーによってソートされています。

partitionhash-keyrange-keyvalue
1DynamoDB#DynamoDB Thread 12011-12-11T00:40:57.165Z{ ... }
1DynamoDB#DynamoDB Thread 12011-12-18T00:40:57.165Z{ ... }
1DynamoDB#DynamoDB Thread 12011-12-25T00:40:57.165Z{ ... }
3DynamoDB#DynamoDB Thread 22011-12-25T00:40:57.165Z{ ... }
3DynamoDB#DynamoDB Thread 22012-01-03T00:40:57.165Z{ ... }

このような状態でデータを保持していると、ハッシュキーを1つに特定(=操作対象のパーティションを特定)した上で、レンジキーを範囲条件で切り出して返す、という操作が非常に自然で高速に行えることが感覚的に理解してもらえると思います。一方、操作対象となるパーティションが絞れない操作はサポートされない、と考えれば問題ないです。

例えば、ハッシュキーは特に指定せず、レンジキーの範囲だけで検索(つまりrange BETWEEN x AND yによる検索)を考えてみましょう。これは、全てのパーティションで検索を行い、その結果をマージしなければならないため、コストが大きいですね。なのでこのような操作はサポートされていません。

そして「ハッシュキーの値が'A'から始まるもの」という検索も、RDBではhash LIKE 'A%'といった気軽な検索が出来たと思いますが、DynamoDBではサポートしません。

一方、hash = x AND range LIKE 'A%'であれば、自然に集合を切り出して来れそうですね。ご想像の通り、サポートしています。

ここまで想像ができると、ReplytableのIdattributeが何故こんな形(フォーラム名とスレッド名を#でjoinしたもの)になっているのか、にも一定の納得が行くと思います。RDBの設計では考えられないことですけどね。

あともう一つ。Queryには大きな特徴があります。Queryの結果は、常にレンジキーの値でソート済みで返って来ます。上記のイメージを持っていれば、当たり前なんですけどね。

ハッシュキーの設計

さて。前回のコンセプトから学ぶAmazon DynamoDB【ハッシュキーテーブル篇】では「すべてのデータが確率的には均一に全てのパーティションに分散するため、パーティション1つだけで受け持つ状況とくらべて16倍の性能が確保できる」と説明しました。

ただし、この原理には弱点があります。1つのitemだけを集中的に読み書きするようなシステムです。そりゃそうですよね、性能を確保するために複数のパーティションを並べているのに、1つのアイテムへの読み書きが集中したら、1つのパーティションだけが高負荷になるだけです。このようなパーティションのことを「ホットパーティション」と呼び、DynamoDBを利用する際はホットパーティションの発生を回避するように設計しなければなりません。その具体例については、また改めて説明する機会を設けられればと思っています。

で、ホットパーティションは、ハッシュキーテーブルよりも複合キーテーブルにおいて発生する可能性が高くなります。1つのitemに集中していなくても、1つのhash-keyに集中するだけでホットになってしまうからです。

例えば。前述の「レンジキーの範囲だけで検索(つまりrange BETWEEN x AND yによる検索)」の例を考えてみましょう。裏側のイメージが出来ていない人は、表面的なことだけを考えてこんなことを考えるかもしれません。

「あ! ハッシュキー内でしか範囲検索できないのならば、ハッシュキーは固定で1とかにしておいて、そして使わなければいいんだ。そうすれば全件に対する範囲検索ができるぞー!」

確かに、機能的には。そして開発中も上手く動く気がします。そして多分負荷テストでコケます。負荷テストをサボると本番でトビます。怖いですね。

DynamoDBにおいては、裏側のイメージをきちんと持ってキー設計をすることが大事です。

Amazon DynamoDBのアップデート: JSON、 拡張された無料試用枠, フレキシブルスケーリング、 より大きなアイテム

mazon DynamoDBのアップデート  JSON、 拡張された無料試用枠, フレキシブルスケーリング、 より大きなアイテム」 の紹介です。

DynamoDBをさらに便利にする4つの重要なアップデート

Amazon DynamoDB は、あらゆるスケールにおいて一貫して1桁ミリ秒での応答が 要求される全てのアプリケーションに適した、高速かつ柔軟な NoSQL データベースのサービスです。お客様からも、すぐ簡単に使い始められ(しかも多くの場合コストをかけずにAWSの無料試用枠内で)、どんなに大きなデータ量にも対応できるリクエストレートにも後からシームレスにスケールでき、SSDによる一貫した性能を発揮できることに喜びの声を頂いています。

今回、DynamoDBをさらに便利にする4つの重要なアップデートを行いました: JSON データのサポート、無料試用枠の拡張、追加のスケーリングオプション、より大きなアイテムへの対応です。また、新しいデモ動画と、顧客事例も追加しました。

JSONドキュメントのサポート

JSONフォーマットのドキュメントをそのままDynamoDBの1アイテムとして保存できるようになりました(後述の新たなサイズ上限である400KB以内が条件)

このドキュメント志向のサポートは、各AWS SDKと、DynamoDBが新たにサポートしたデータタイプによって実現されます。ドキュメントのサポート(AWS SDK for Java、 SDK for .NET、SDK for Ruby、SDK for JavaScript in the Browserで利用可)は、JSONデータや各言語のネイティブオブジェクトのDynamoDBのデータタイプへのマッピングの簡略化、ドキュメントの構造に合わせたクエリのサポートを行います。また、JSONドキュメントをAWS Management Consoleで編集することも可能です。

この機能追加により、DynamoDBは本格的なドキュメントストアとなりました。AWS SDKを使えば、JSONドキュメントを、その入れ子を含む複雑な”構造”を保ったままDynamoDBのテーブルに簡単に保存することが出来ます。また、新しいデータタイプのサポートにより、HTMLやXMLなど他のフォーマットのデータもシンプルな変換レイヤを作ることで保存が可能です。

いくつか例を見てみます。下記のJSONドキュメントから始めましょう:

{
  "person_id" : 123,
  "last_name" : "Barr",
  "first_name" : "Jeff",
  "current_city" : "Tokyo",
  "next_haircut" :
  {
    "year" : 2014,
    "month" : 10,
    "day" : 30
  },
  "children"  :
    [ "SJB", "ASB", "CGB", "BGB", "GTB" ]
}

これをJSON文字列として扱うにはエスケープ文字が必要です:

String json = "{"
        +   "\"person_id\" : 123 ,"
        +   "\"last_name\" : \"Barr\" ,"
        +   "\"first_name\" : \"Jeff\" ,"
        +   "\"current_city\" : \"Tokyo\" ,"
        +   "\"next_haircut\" : {"
        +       "\"year\" : 2014 ,"
        +       "\"month\" : 10 ,"
        +       "\"day\" : 30"
        +   "} ,"
        +   "\"children\" :"
        +   "[ \"SJB\" , \"ASB\" , \"CGB\" , \"BGB\" , \"GTB\" ]"
        + "}"
        ;

こちらがJSONドキュメントをpeopleという名前のテーブルに保存するコードです:

DynamoDB dynamo = new DynamoDB(new AmazonDynamoDBClient(...)); 
Table table = dynamo.getTable("people");

Item item =
  new Item()
      .withPrimaryKey("person_id", 123)
      .withJSON("document", json);

table.putItem(item);

そしてこちらがそれを取り出すコードです:

DynamoDB dynamo = new DynamoDB(new AmazonDynamoDBClient(...)); 
Table table = dynamo.getTable("people"); 

Item documentItem =
  table.getItem(new GetItemSpec()
                .withPrimaryKey("person_id", 123)
                .withAttributesToGet("document"));

System.out.println(documentItem.getJSONPretty("document"));

AWS SDK for Java がドキュメントをDynamoDBのデータタイプにマップして保存してくれます:

ドキュメントをプログラムから、構造を持った形で表現したり、操作したりすることも出来ます。次のコードはこの後で紹介するDynamoDBの新しいデータタイプであるMapやListを使用しています:

DynamoDB dynamo = new DynamoDB(new AmazonDynamoDBClient(...)); 
Table table = dynamo.getTable("people"); 

Item item =
  new Item() 
      .withPrimaryKey("person_id", 123)
      .withMap("document", 
               new ValueMap()
                   .withString("last_name", "Barr") 
                   .withString("first_name", "Jeff") 
                   .withString("current_city", "Tokyo") 
                   .withMap("next_haircut", 
               new ValueMap() 
                   .withInt("year", 2014) 
                   .withInt("month", 10) 
                   .withInt("day", 30)) 
                   .withList("children", 
                             "SJB", "ASB", "CGB", "BGB", "GTB")); 

table.putItem(item);

こちらがアイテム全体を取得する方法です:

DynamoDB dynamo = new DynamoDB(new AmazonDynamoDBClient(...)); 
Table table = dynamo.getTable("people"); 

Item documentItem =
  table.getItem(new GetItemSpec()
                    .withPrimaryKey("person_id", 123)
                    .withAttributesToGet("document"));

System.out.println(documentItem.get("document"));
Document Pathを使ってドキュメントの一部を取り出すことも出来ます。例えばnext_haircutアイテムだけを取り出したいとしましょう。こちらがその方法です:

DynamoDB dynamo = new DynamoDB(new AmazonDynamoDBClient(...)); 
Table table = dynamo.getTable("people"); 

Item partialDocItem =
  table.getItem(new GetItemSpec()
                    .withPrimaryKey("person_id", 123)
                    .withProjectionExpression("document.next_haircut"));

System.out.println(partialDocItem);

同じように、ドキュメントの一部分を更新することも出来ます。こちらがcurrent_cityを Seattleに戻すコードです:

DynamoDB dynamo = new DynamoDB(new AmazonDynamoDBClient(...)); 
Table table = dynamo.getTable("people"); 

table.updateItem(
  new UpdateItemSpec()
      .withPrimaryKey("person_id", 123)
      .withUpdateExpression("SET document.current_city = :city")
      .withValueMap(new ValueMap().withString(":city", "Seattle")));

今回のローンチの一部として、下記の4つのデータタイプを追加しました:

List - JSON Arrayのように、順番が保たれた値のコレクションを保持します。上記のサンプルドキュメントのchildrenの部分はListとして保存されます。

Map - JSON Objectのように、順序付けのないName-Valueペアを保持します。サンプルドキュメントのnext_haircutの部分はMapとして保存されます。

Boolean - Boolean値 (true もしくは false)を保持します。

Null - UnknownあるいはUndefinedな値の状態を表すデータタイプです。

JSONからDynamoDBのデータタイプへのマッピングは直感的です。お好みであれば、JSONドキュメントをDynamoDBに保存して、低レベルのネイティブファンクションを使って取り出すことも出来ます。既存のアイテムをJSONドキュメントとして取り出すことも可能です。

1つ重要な注意点は、DynamoDBのタイプシステムはJSONのスーパーセットであるもの、すなわち、BinaryやSetなどのタイプを含むドキュメントは正しくJSONとして表現出来ない場合があります。Item.getJSON(String)とItem.toJSON()メソッドはBinaryをBase64エンコードしますし、SetはJSON Arrayとして表現されます。

拡張された無料試用枠

AWSの無料試用枠の一部として用意されているDynamoDBのキャパシティを拡張しました。これからは1月当たりに25 GBのデータ保存と2億回のリクエスト、読み込み書き込みそれぞれ25 キャパシティユニットまでを無料でご利用頂けます。言い換えればこれは有用なアプリをプロダクション環境で運用するのに十分なキャパシティが無料だと言えます。例えば、我々の経験からすると、15,000人のユーザがいるモバイルゲームや、1日に50万インプレッションを提供するアドテクプラットフォームを運用可能な規模です。

追加のスケーリングオプション

ご存知の通り、DynamoDBはプロビジョンド・キャパシティモデルで動作します。テーブル及び関連するGlobal Secondary Indexを作成する時点で、必要な読み込みと書き込みのキャパシティを、キャパシティユニットの形で指定する必要があります。1読み込みキャパシティユニットは秒間1回(4 KBまで)の強一貫性読み込み、あるいは秒間2回(こちらも4 KBまで)の結果一貫性読み込みを許可します。1書き込みキャパシティユニットは秒間1回(1 KBまで)の書き込みを許可します。

これまで、DynamoDBは1回の変更操作において、プロビジョンド・スループットを2倍か半分にする操作だけを許可しています。今回のリリースで、AWSアカウントの制限の範囲内なら(引き上げも可能です)どんな値にでも調節出来るようになりました。この制限については ドキュメントのDynamoDB の制限値 をご参照下さい。

より大きなアイテム

各DynamoDBのアイテムの最大サイズが400 KBとなりました。1アイテム当たりのサイズ にはアトリビュートの名前(UTF-8にて)と、アトリビュートの値を含みます。これまでの最大値は 64 KBでした。

新しいデモ動画

私の同僚の Khawaja Shams (DynamoDBの技術責任者)が動画に登場しています。彼は今回の新機能を紹介しつつ、JSONサポートを活用したデモアプリをお披露目します:

DynamoDB in Action  お客様の声

世界中のAWSのお客様がミッションクリティカルなアプリケーションのコア技術としてDynamoDBを導入しています。以下は、最近の成功事例です:

ワークグループや家族向けのコミュニケーションツールであるTalko のサービスアーキテクト、 Ransom Richardson氏はなぜ彼らがDynamoDBを使っているのか語ってくれました:

DynamoDBはTalkoのストレージアーキテクチャのコアとなっています。 信じられない程の信頼性で、我々が使ってきたこの2年間の間、100%のuptimeを記録しています。その一貫した低遅延の性能のおかげで、データベースの性能のチューニングに時間を使わずに、アプリケーションの開発に集中することが出来ます。DynamoDBのおかげで、プロダクトのローンチ時も簡単にキャパシティをスケールすることが出来ました。


Electronic Arts は The Simpsons:Tapped Out (アメリカの iOS アプリのランキングで上位20位にランクインし、数百万のアクティブユーザを抱えるゲーム)のゲームデータを DynamoDB と Amazon Simple Storage Service (S3)に保存しています。MySQLからDynamoDB へと移行したことで、データ保存にかかるコストは90%削減という驚くべき値となりました。

この信じられないほど成功したゲームの開発チームは、AWS re:Inventでセッションを予定しています。どのようにMySQLからDynamoDBへとオンザフライで移行し、AWS Elastic Beanstalk と Auto Scaling を活用してコストを下げながらデプロイメントをシンプルにしたのか興味がある方は、是非 GAM302 へとご参加下さい。

オンラインインデキシング(近日提供予定)

オンラインインデキシングという、既存のDynamoDBのテーブルのインデックスを追加削除出来るようにする機能の提供を予定しています。これにより、クエリパターンの変化に合わせてインデックスを調整することが出来るようになります。この機能は近日中に提供予定ですのでお楽しみに!

今からすぐに使い始められます

これらの新機能は既に US East (北バージニア)、US West (オレゴン)、Europe (アイルランド)、 Asia Pacific (東京)リージョンでご利用頂けます。その他のリージョンについても近い将来に提供できる予定です。また、どのリージョンを対象にしている開発者様も、最新の DynamoDB Local をダウンロードしてローカルで開発とテストを行うことが出来ます(詳細はDynamoDB Local for Desktop Development を御覧ください)

安川

DynamoDBの利用例

DynamoDBの利用例の紹介です。

スケジュールの例

テーブルの詳細

テーブル名	schedule
プライマリパーティションキー	extension (文字列)
プライマリソートキー	start_date (文字列)
有効期限 (TTL) 属性	無効TTL の管理
テーブルの状態	有効
作成日	yyyy年mm月dd日 14:44:19 UTC+9
UTC: yyyy年mm月dd日 5:44:19 UTC
ローカル: yyyy年mm月dd日 14:44:19 UTC+9
リージョン (Tokyo): yyyy年mm月dd日 14:44:19 UTC+9
プロビジョニングされた読み込みキャパシティーユニット	5 (Auto Scaling 無効)
プロビジョニングされた書き込みキャパシティーユニット	5 (Auto Scaling 無効)
最後の減少時刻	-
最後の増加時刻	-
ストレージ容量(バイト単位)	12.92 KB
項目数	43
リージョン	Asia Pacific (Tokyo)
Amazon リソースネーム(ARN)	arn:aws:dynamodb:ap-northeast-1:xxxxxxxx:table/schedule

項目例(通常スケジュール)

description String:	大中さん\nこんにちは\n今日は、デーサービスの日です。\n12時にお迎えの車が来ます。\nよろしくお願いします。
	
extension String:	2001
	
repeat Boolean:	false
	
start_date String:	2017-08-17T00:49:00.000Z
	
title String:	情報支援
	
update String:	2017-08-17T00:50:31.609Z
	
week Number:	0

項目例(週スケジュール)

description String:	大中さん\nこんにちは\n今日は、デーサービスの日です。\n12時にお迎えの車が来ます。\nよろしくお願いします。
	
extension String:	2001
	
repeat Boolean:	true
	
start_date String:	2017-01-01T00:49:00.000Z
	
title String:	情報支援
	
update String:	2017-08-17T00:50:31.609Z
	
week Number:	0


お花畑6