RailsアプリでDynamoDBを活用する方法 ― Dynamoid gem入門
DynamoDBは、キーバリュー型とドキュメント型のデータ構造を提供するNoSQLデータベースです。まずはここを整理してみましょう。この記事を読んでいる開発者の多くは、明確に定義されたスキーマと、テーブル・行・列へ正規化されたデータを持つ従来のリレーショナルデータベース(RDBMS)に慣れていることと思います。テーブル同士は外部キーによる「リレーションシップ」で結び付けられていますよね。
それに対してDynamoDBはスキーマレスです。すべてのテーブルにはプライマリキーが必要ですが、それ以外の非キー属性には制約が一切ありません。「では、どんな場面でこれが有利になるのか?」という疑問が湧くかもしれません。その答えを知るために、AmazonがなぜDynamoDBを生み出したのかを見ていきましょう。
Amazonは2012年にDynamoDBを一般公開する計画を発表しました。もともとAmazonは、2004年のホリデーシーズンに大量のトラフィックで複数の自社アプリケーションがダウンしたことをきっかけに、社内向けにDynamoを開発していたのです。
どんなときにDynamoDBを検討すべきか?
DynamoDBは、数千人以上という非常に多くの同時接続ユーザーをサポートし、毎秒数万件の読み書きが必要なアプリケーションにとって有力な選択肢です。たとえば、ソーシャルネットワーク、ゲーム、IoTデバイスなどはDynamoDBに適した候補と言えるでしょう。実際、Lyft、Airbnb、RedfinなどがDynamoを採用しています。
初期の利用者は少なくても、最終的に大規模なスケールを目指して構築するのであれば、Postgresのような従来のSQLデータベースではなく、最初からDynamoDBを選ぶことが有利になるケースもあります。一方で、ユーザーが頻繁にクエリを実行するデータウェアハウスやOLAPアプリケーションの構築には、スキーマレスデータベースはおそらく不向きです。
さらに、RDBMSがストレージ向けに最適化されているのに対し、DynamoDBはコンピュート向けに最適化されている点も特徴です。Amazonによれば、DynamoDBはどのような規模でも一桁ミリ秒のパフォーマンスを実現し、1日10兆件以上のリクエスト、ピーク時には毎秒2,000万件以上のリクエストを処理できるとのこと。驚異的な数字ですね!
加えて、AWSはデータ保持やセキュリティが求められるアプリケーションにとってDynamoDBを魅力的にする多彩な機能を提供しています。
保存時の暗号化: DynamoDBはプライマリキーを含むすべてのデータを暗号化されたテーブルで保護します。ユーザーは「AWS所有のカスタマーマスターキー(CMK)」「AWS管理のCMK(キーはアカウント内に保存され、AWS Key Management Serviceが管理)」「カスタマー管理のCMK(キーは自分で作成・所有・管理)」の3つのオプションから選択でき、しかもテーブルごとに異なるオプションを組み合わせられます。
オンデマンドバックアップ/ポイントインタイムリカバリ: 過去約30日間の任意の時点へテーブルを復元できます。誤った書き込みや削除を恐れる必要はもうありません!
DynamoDBの基本
DynamoDBには3つのコアコンポーネントがあります。それぞれ見ていきましょう。
- テーブル: アイテムのコレクション
- アイテム: 属性のコレクション
- 属性: それ以上分解する必要のない、最小単位のデータ要素
たとえば、賃貸物件を管理するアプリケーションを作る場合、「Houses」というテーブルに次のようなアイテムを持たせるイメージです。
{
"HouseID": 1,
"AddressLine1": "123 Main St",
"City": "Atlanta",
"State": "GA",
"Zip": 30322,
"Rented": true,
"Tenant": "John Smith"
}
{
"HouseID": 2,
"AddressLine1": "456 Square St",
"City": "Nashville",
"State": "TN",
"Zip": 37211,
"Rented": true,
"Tenant": "Mary Jane"
}
HouseID、AddressLine1、City、State、Zip、Rented、Tenantはすべてアイテムの属性です。アイテムを従来のSQLデータベースの「行」に、属性を「列」に見立てることもできますが、DynamoDBのようなNoSQLデータベースとSQLデータベースはまったく異なる存在なので、安易に比較しないことをおすすめします。
各アイテムには一意のプライマリキーが必ず付与される点に注目してください(DynamoDBは単一のパーティションキーと複合プライマリキーの両方をサポートしています)。しかし、HouseID以外の部分においてHousesテーブルはスキーマレスです。つまり、属性やデータ型を事前に定義する必要はありません。従来のSQLデータベースであれば、Zipをinteger型としてスキーマに定義しておく必要があるのとは対照的ですね。
「DynamoDBでインデックスはどう扱うのか?」と気になった方、鋭い質問です!Housesテーブルのrented属性とzip属性にインデックスを作成したいとしましょう(郵便番号を指定して、その地域の賃貸中物件をすべて取得するようなケースです)。SQLデータベースなら、次のようなマイグレーションを書くところです。
CREATE INDEX RentedAndZipIndex
ON Houses (rented, zip);
一方、DynamoDBの場合はセカンダリインデックスを設定します。その際にはパーティションキーとソートキーを指定する必要があり、この例ではzipがパーティションキー、rentedがソートキーとなります。DynamoDBのインデックスには他にも学ぶべき要素がたくさんありますが、本記事ではここまでにしておきましょう。
Ruby / Ruby on RailsでDynamoDBを使う
AWSはDynamoDB用のSDKを多数の言語で提供しています(現在はJava、JavaScript、Node.js、.NET、PHP、Python、Rubyに対応)。RubyでDynamoDBを使う方法は2つあります。
1) DynamoDBをローカルにダウンロードする。アプリケーションの動作確認だけが目的なら、これが手軽でおすすめです! 本番環境への移行時には、ローカルエンドポイントを削除してWebサービスに向けるだけでOKです。
2) DynamoDB Webサービスを利用する。こちらはAWSアクセスキーと認証情報が必要になります。
DynamoDBとやり取りするには、CLIをダウンロードしておくと便利です。もちろん、コンソールやAPIだけを使うことも可能です。
また、このシリーズを進めるには、Ruby本体とAWS SDK for Rubyがインストール済みである必要があります。
Railsユーザーには、プロジェクトに追加できる便利なgemがあります。Dynamoidです。ただし、AWS認証情報は別途必要になる点に注意してください。
Railsでの実装例
ステップ1: セットアップ
Gemfileに以下のgemを追加し、bundle installを実行します。
gem 'dynamoid'
gem 'aws-sdk'
次に、config/initializersディレクトリに新しいファイルaws.rbを作成し、以下を追加します。

注意: 認証情報は必ず環境変数で管理してください。プロジェクトに直接ハードコードするのは絶対に避けましょう!
ステップ2: ドキュメントの定義
この例では、app/modelsディレクトリにhouse.rbファイルを次のように作成しました。

コードの内容を順番に見ていきましょう。
- テーブルを定義する際は、必ず
include Dynamoid::Documentを記述する必要があります。 - 4行目では、テーブル名・キー・キャパシティモードを定義しています。Dynamoid gemには妥当なデフォルト値が用意されているため、厳密にはこれらの記述は必須ではありません。ただし、明示的に定義すればデフォルトが上書きされます。
read_capacityとwrite_capacityも指定できますが、capacity_modeをon_demandに設定している場合、これらのオプションは無視されます。on_demandモードは、AWS側に自動的なスケールアップ/ダウンを指示する設定だからです。 - 続いて、テーブルのフィールドを定義しています。モデル上のすべてのフィールドとデータ型を宣言する必要があります(省略した場合は
stringとみなされます)。
dynamoid gemには、テーブルを作成する便利なrakeタスクが付属しています。
rake dynamoid:create_tables
ステップ3: オブジェクトとのやり取り
一部は見慣れないコードに感じるかもしれませんが、朗報があります!dynamoid gemの優れた点は、Active Recordで使い慣れた多くの機能がほぼ同じ感覚で使えることです。
アソシエーション
Dynamoidはhas_many、has_one、has_and_belongs_to_many、belongs_toといったアソシエーションをサポートしており、ActiveRecordと同じように定義できます。たとえば、賃貸物件アプリにLeaseという別のドキュメントテーブルがあるとしましょう。House側には次のように書けます。
has_one :lease
Lease側にはこうです。
belongs_to :house
バリデーション
DynamoidにはActiveModelのバリデーションも組み込まれているので、この点も安心です。
コールバック
save、update、destroyアクションに対してbefore_系・after_系のコールバックが利用できるため、lease.rbに次のように書くこともできます。
before_save :validate_signature
レコードの作成
オブジェクト生成の構文も、ActiveRecordで普段書いているものとほぼ同一です。次のように書けます。
h = House.new(address_line_1: "123 Main St", city: "Cool City", state: "Iowa", zip: 52302)
h.rented = true
h.save
あるいは、シンプルに.createメソッドを使ってもよいでしょう。
House.create(address_line_1: "123 Main St", city: "Cool City", state: "Iowa", zip: 52302)
クエリ
クエリの書き方はもうお分かりですよね? その通り、ActiveRecordと同じ要領です。
.find: IDを指定して取得.where: 任意の数の一致条件を指定.find_by_x:xに属性名を指定
さらに学びたい方へ
Dynamoid gemにはまだまだ学ぶべき機能がたくさんありますが、今回の内容で十分に遊び始められるはずです。公式GitHubページで、利用可能な機能の詳細をぜひチェックしてみてください!
次回予告
いかがでしたか? 今回は「NoSQL」という言葉の意味や、スキーマレスデータベースが必要なプロジェクトになぜDynamoDBが有力な選択肢となるのかを解説し、Railsプロジェクトでdynamoid gemを使うための基本セットアップも一緒に確認しました。
シリーズ次回の記事では、DynamoDBをローカル環境にセットアップし、Ruby SDKのいくつかの機能を実際に試していきます。お楽しみに!
-
React on Rails:シンプルなアプリの構築
アプリケーションのフロントエンド側全体を構築する企業は、多くの場合、バックエンドを構築するためにRailsなどの同じフレームワークを選択します。長年にわたり、これは最良かつ最も信頼できるオプションでした。 今日、絶えず進化するフロントエンドユニバースにある多数のライブラリとフレームワークにより、開発者はバックエンドとフロントエンドの両方に異なるプラットフォームを選択し、それらを簡単に統合できます。 Reactはフロントエンドのパンゲアの巨人になりました。 Ruby on Railsを使用している場合は、デフォルトのRailsページをReactコード(またはその他のフロントフレームワーク)に
-
Rails5でのAngularの使用
あなたは前にその話を聞いたことがあります。分散型で完全に機能するバックエンドAPIと、通常のツールセットで作成されたフロントエンドで実行されているアプリケーションがすでにあります。 次に、Angularに移動します。または、AngularをRailsプロジェクトと統合する方法を探しているだけかもしれません。これは、この方法を好むためです。私たちはあなたを責めません。 このようなアプローチを使用すると、両方の世界を活用して、たとえばRailsとAngularのどちらの機能を使用してフォーマットするかを決定できます。 構築するもの 心配する必要はありません。このチュートリアルは、この目的のた