前回は、CAP定理に基づいてリレーショナルデータベース(RDB)やNoSQLデータベースを分類し、その特性に応じて適したユースケースやデータ特性を整理しました。今回は、それらの分類のうち、可用性(Availability)とネットワーク分断耐性(Partition Tolerance)を重視したAP型データベースの代表例である「Amazon DynamoDB」と「Apache Cassandra」を比較しながら、その特徴を深掘りします。

なお、Cassandraは、DynamoDBの分散モデルを参考にFacebook社が開発したオープンソースのNoSQLデータベースです。Amazon DynamoDBはその実装が厳密に公開されていないため、同様のアーキテクチャを持つApache Cassandraを合わせて比較することで理解を深めていきたいと思います。

AP型データベースAmazon DynamoDBとApache Cassandraの特徴

前回の復習になりますが、AP型のNoSQLデータベースは一貫性(Consistency)が下がることのトレードオフとして、可用性(Availability)とネットワーク分断耐性(Partition Tolerance)を高めています。具体的には、以下のイメージのように複数のアベイラビリティゾーンにデータベースを配置し、各ノードにデータを分散して配置することで実現しています。

AP型データベースでは、各ノードにデータを分散して配置する

単一障害点がないのが大きな特徴で、どこのノードからでもデータ更新が可能であり、ノードも任意に追加/設定できるスケーラビリティにも優れた分散型構成です。ただし、ノードの故障や通信のエラーにより、複数のノード間で整合性のとれない(一貫性を損なう)ケースが発生します。

その回避策として、読み込み時に最新のデータで古いノードのデータを更新するReadRepair機能や、Quorumをベースに結果整合性をとる方法(雑に言えば、不整合が出た場合に、なるべく多くの一致したデータを判定する多数決に似た手法)が用意されている……というところまでが、前回説明したお話です。

Apache Cassandraは、Amazon DynamoDBのデータベース分散モデルを参考にデザインされているため当然、そのデータ分散配置に関する特徴を継承しています。

まず、両者で共通して押さえておかなれければならないものの1つが、各ノードに配置される「データ」と「キー」の概念です。

Amazon DynamoDB、Apache Cassandraは「Consistent Hashing」と呼ばれるアルゴリズムにより、各ノードと配置されるデータを決定しています。大まかなイメージを掴むために、先の図の「都市テーブル」に市区情報を加えて構成されるかたちに変更してみましょう。都道府県と市/区は1:Nの関係であり、都道府県を区別するキーを「親キー」、市や区を区別するキーを「子キー」とします。DynamoDBとCassandraには、これらのキーに対して、以下のような名称で対応付けられるキーがあります。

データベース 親キー 子キー
Amazon DynamoDB パーティションキー(Partition Key) ソートキー(Sort Key)
Apache Cassandra パーティションカラム(Partition Column) クラスタカラム(Cluster Column)

※ なお、Amazon DynamoDBでは以前、パーティションキーは「ハッシュキー(Hash Key)」、ソートキーは「レンジキー(Range Key)」という名称で呼ばれていました。また現在、パーティションキーとソートキーを合わせて「プライマリキー(Primary Key)」と呼んでいます。

どちらのデータベースにおいても、以下のルールを押さえておくことが必要です。

  1. 親キーで配置されるノードが決定する。
  2. ノード内のデータ順序を決定する子キーを任意に設定できる。
  3. 子キーを作成しない場合は親キーでデータを一意に特定できるようにする必要がある。
  4. 子キーにはインデックスを設定できる。

また、Amazon DynamoDBとApache Cassandraでは分散データ方式として、以下のような違いがあります。

特性 Amazon DynamoDB Apache Cassandra
配置するノード数上限 上限はAWSにより決定 上限なしで任意に設定
レプリケーションファクタ (ノードに配置するデータのレプリケーション数)
同一リージョンで3つのレプリケーション
(DynamoDBはリージョンごとのサービス)
テーブルごとに任意設定が可能
結果整合性のオプション 【読込】結果整合性か強い読込整合性かを選択
 [結果整合性] 2/3以上の読込で結果一致した場合正常応答
 [強い読込整合性] 全てのReadRepairが完了し、結果を応答
【書込】2/3以上の書込が成功した場合正常応答
ユーザー側で設定可能な読込/書込の一貫性。読み込むレプリカ数と書き込むレプリカ数を指定できる。指定に達しない場合エラーとなる

こうした分散DBアーキテクチャを踏まえると、当然、RDBでできていた以下のような当たり前のことができなくなります。

制約 できない理由
テーブル間結合ができない データがテーブルごとに分散して配置されているので、テーブル同士を結合して、データを射影するといった操作はできない
外部キーがない プロダクトの性質上、キーはプライマリーキー(親キー)とセカンダリキー(子キー)に限定される
条件指定でプライマリキー以外使用できない データが分散して配置されているので、プライマリキー以外で検索をかけることができない。
※ 対処策として、インデックスを作成する、もしくはセカンダリキーを指定することができる(ただし、性能上問題が出る可能性がある)
副問い合せができない データが分載して配置されているので、検索結果のデータを条件とすることはできない
GROUP BYなど集約関数が存在しない データが分散して配置されているので、集約に必要なデータが検索時に足りない
OR、NOTの演算子はなくANDのみ プロダクトの性質上、サポートしていない

上記の制約はプロダクトによって差がありますが、RDBで実現できる機能を使いたい場合は、RDBを導入すべきであり、NoSQLデータベースは、その特性を生かしたユースケースに対して導入を検討すべきです。

ただし、AP型NoSQLデータベースを導入する場合でも、上記のようなさまざまな機能要件を求められるケースもあるため、アプリケーションの設計時に制約をしっかりと意識し、データベースの機能に委ねるべきか、不足する機能に代替する処理をアプリケーションで実装すべきかを判断できるようにしておきましょう。

次回以降は、Amazon DynamoDBのより詳細な特徴を整理し、実際にDynamoDBを構築していきます。