読者です 読者をやめる 読者になる 読者になる

理系学生日記

おまえはいつまで学生気分なのか

忍者TOOLS

Cassandra 入門

諸事情で Cassandra で遊ぶことになった。

Cassandra とは何なのか

一言で言えば、非中央集権型で単一故障点のない(という触れ込みの)、カラム指向分散データベースといったところだと思う。Facebook によって作成され、今は Apache のトッププロジェクトになっている。

Cassandra にはマスタノードがない。全てのノードは同じ役割を持ち、ピアツーピアプロトコロル(ゴシッピング)で動作する。
また、最近は完全に水平方向のスケーリングが主流だけれど、特に Cassandra はシームレスに、プロセスの再起動が必要のないスケールアウトが可能となる。

Cassandra = 結果整合性?

Cassandra は CAP 定理の C: 一貫性を犠牲にし、結果整合性までしか得られないという話があるが、これは実際には YES でもあり No。デフォルトでは結果整合性までだが、設定さえすればより強い一貫性(強一貫性) だって得ることができる。もちろん、CAP 定理によって、この場合は他(A: 可用性 or P: 分断耐性) が犠牲になると思う。

まず結果整合性とは何かというと、wikipedia:結果整合性 の説明がシンプル。

イベンチュアル・コンシステンシーは、厳密な一貫性を要求する考え方ではなく、結果的に一貫性が保たれればよいという考え方。長い間、データの更新がなければ、結果的に、全ての更新処理が反映され、全てのレプリケーションを含めたデータの一貫性が保たれる、とする。

ちなみにここでいう「一貫性」とは、CAP 定理にある「全てのノードにおいて同時に同じデータが見えなければならない」性質 (wikipedia:CAP定理) のこと。要するに、結果整合性とは「結果的には、ノード間におけるデータの一貫性が保たれる」ものであって、そこに至る過程においては、データの一貫性は担保されない。

Cassandra においては、どれだけ整合性(一貫性)のレベルを高めるかは設定可能である。それを設定する項目が、「レプリケーションファクタ」と「一貫性レベル(Consistency Level)」の 2 つ。この 2 つは紛らわしいのだけれど、概ね以下のようなもの。

レプリケーションファクタ
クラスタ内でデータの更新を伝搬させたい(レプリケーションさせたい)ノード数
一貫性レベル
書き込みのときは、いくつのレプリカ(ノード)に書き込みを行うのか、読み込みの場合は、いくつのレプリカからデータを返答させるのか

両者を同じ値(ノード数)に設定すれば、結果的に強一貫性が得られることになる。ただし、もちろん、パフォーマンスとのトレードオフになるし、そういう設定をしてパフォーマンスを犠牲にするのであれば、別のプロダクトを選択した方が良いと思う。

データモデル

Cassandra は NoSQL の文脈で登場するプロダクトではあるけれど、KVS かと言われるとやっぱりこも YES でもあり NO であるように思う。
いわゆる単純ハッシュ(連想配列とかマップ)のような KEY => VALUE の 2 次元構造が基本にあり、その集合を含めた 3 次元でデータを持つというのがぼくの中の KVS。しかし、Cassandra は Column と呼ばれる KEY => VALUE の基本構造の集合で、まずは行 (Row) を構成する。そしてその Row の集合でテーブル (Column Family) を構成する。従って、基本的には 4 次元でデータを保持する。

+ Column Family (RDBMS でいうテーブル)
  + Row 1 (RDBMS でいうレコード)
    - Column 1 (RDBMS でいうカラム)
      KEY1 => VALUE1
    - Column 2
      KEY2 => VALUE2
  + Row 2 
    ...

(※)本当は、さらに KeySpace という概念でてくるが、文脈上関係ないので割愛。

おやおや、これはでも JSON と同じようなもんじゃないかと思う御仁もいると思うのだけれど、ぼくはその通りだと思う。というか、JSON を DB に突っ込んだと考えた方が、変な単語を喚くよりも分かりやすい。
ただし、JSON ならばハッシュを多重に、何階層でも入れ子にできるが、Cassandra 上は(少なくとも物理的には)その階層の数は限られる。はっきり言ってしまえば、2 階層までしか入れ子は作れないし、違う言い方で言い直せば key/value の「value」として「KEY => VALUE」のペアを持たせることは 1 階層しかできない。

# これは OK (通常の Column)
{
  key => value
}

# これも OK (Super Column)
{
  key => {
    key => value
  }
}

# これは NG
{
  key => {
    key => {
      key => value
    }
  }
}

このようなデータ構造(?)をスーパーカラムといって、これを考えると Cassandra が保持するのは 5 次元のデータとなるのだけれど、実際に運用とその後の拡張を考えたときに、はたしてスーパーカラムは使えるのだろうかという思いが個人的にあるので、これもちょっと割愛する。

スキーマフリー

JSON やハッシュ(連想配列)といった話を上に出したけれど、これらの RDBMS に比べたときのメリットはそのデータ構造の柔らかさだと思う。最初にスキーマを定義する必要がない。実行時に好きなキーを突っ込んでいける。RDBMS だと、逐一 DDL を流し込んだりといった面倒な作業が必要になる。
Cassandra はそういう意味では柔らかい。好きな Row に、いくらでも好きなだけ Column を追加していける。RDBMS 脳になっていると、好きなだけっていってもせいぜい数百だろ、という感覚で話が進むがそうではない。場合によっては 1 つの Row に 数万カラムといったユースケースも存在する。こういう Row を "Wide Row"と呼ぶのだけれど、O'Reilly 本には以下のような例がでていた。

例として監視アプリケーションを考えてみましょう。ロウキーとして変更されたタイムスタンプを使い、1 時間ごとのタイムスライスをロウとして表し、そのインターバルごとにアプリケーションにアクセスした IP アドレスをカラムとして保存させます。すると 1 時間経過後に、新しいロウキーが生成されます。

とりあえず今日はここまで。明日は簡単に Cassandra を Java から触ってみる。