Cassandraは、AmazonのDynamoとGoogleのBigTableを元にしたオープンソースの列指向分散データベース。(リレーショナルデータベース(RDB)ではない)
Javaで作られているが、Thriftベースなので他の言語からもアクセスしやすいらしい。
Dynamoの分散システム設計とBigTableのデータモデル(ColumnFamily)を参考にしており、単なるkey/valueストアより高機能らしい。
|
|
|
まず、JDK1.6をインストールしておく。
CASSANDRA_HOME | C:\apache-cassandra-0.6.1 |
JAVA_HOME | C:\Program Files\Java\jdk1.6.0_20 |
ソースはapache-cassandra-0.6.1-src.tar.gzをダウンロードし、解凍する。
Eclipseのソースの添付では、CASSANDRA_HOME/lib/apache-cassandra-0.6.1.jarに対してapache-cassandra-0.6.1-src/src/javaのフォルダーを指定する。
が、部分的に足りないものがあるので、多少加工する必要がある。[2010-05-11]
作業内容 | 実施コマンド | 備考 | |
---|---|---|---|
1 | Cassandraを起動する。 |
%CASSANDRA_HOME%\bin\cassandra.bat Starting Cassandra Server |
cassandra.batをダブルクリックして実行すればよい。 コンソールは開きっぱなしにしておくこと。 デバッグ接続用ポート:8888 Thriftによる接続ポート:9160 で起動する。 DBの実体は「C:\var\lib\〜」 ログファイルは「C:\var\log\〜」 に出力される(勝手に作られる)。 |
2 | cassandra CLIを起動する。 |
%CASSANDRA_HOME%\bin\cassandra-cli.bat Starting Cassandra Client |
Cassandraの対話型ツール。 |
CLIでちょっと動作確認 |
cassandra> connect localhost/
|
||
3 | CLIを終了する。 |
cassandra> exit |
|
4 | Cassandraを停止する。 | Cassandraのコンソールを終了させるだけ。 (停止用のバッチファイルは特に無い) |
あと、JMXの為にポート8080を使っているようなので、他のアプリ(Tomcatとか)で8080を使っている場合はどちらかを変える必要がある。
Cassandra側を変えるなら、CASSANDRA_HOME/bin/cassandra.batを修正する。
-Dcom.sun.management.jmxremote.port=8080^
Cassandraの用語は、似たようなkey/valueストアであるHBaseとも微妙に違ってややこしい(苦笑)
まずキースペースについて。
Cassandraでは、1つのキースペース内に複数のColumnFamilyを持つ。
(HBaseではテーブルがColumnFamilyを持つのであって、Cassandraのキースペースに当たるものは無い)
Cassandraのデータモデルの説明によれば、キースペースは、RDBで言うところのスキーマやDB(テーブルの集合)に当たるものらしい。
したがってキースペースは概ね1アプリケーションにつき1つらしいので、HBaseとは考え方が違うようだ。
キースペースはstorage-conf.xmlのKeyspace要素で定義する。
キースペース名は文字列(String)。
キースペース内に複数のカラムファミリーを持つ。キースペースがRDBで言うところのDBなので、カラムファミリーはテーブルということになる。
HBaseではテーブルがColumnFamilyを持つので、位置付けが異なる。
いずれにしても「カラムファミリー名」を持ち、その名前でデータを保持することに変わりはない。
カラムファミリーは事前に定義しておく必要がある。→storage-conf.xmlのColumnFamily要素
カラムファミリーはスーパーカラムを持つかどうかで2種類に分けられる。
スーパーカラムを持たないのがColumnFamily(CF)、スーパーカラムを持つカラムファミリーはSCF(ColumnFamily of type "Super")と呼ばれることがある。
したがってカラムファミリーは、「カラムファミリー名」をキーとし、「スーパーカラムまたはカラム」を値とするマップといった感じになる。
カラムファミリー名は文字列(String)。
Cassandraでは、通常のカラムをグルーピングする層が作れる。それがスーパーカラム。
この機能はHBase(やRDB)には無い。
「スーパーカラム名」をキーとし、「カラム」を値とするマップのような位置付けになる。
スーパーカラム名は実行時(データ登録時)に好きなように付けられる。
スーパーカラム名はバイト列(byte[])。通常は文字列をUTF-8にしたもの。
スーパーカラムは有っても無くてもいいので、「Cassandraは4次元または5次元のデータ構造」と言っているのだろう。
(スーパーカラムを使う場合は5次元、使わない場合は4次元)
カラムファミリーがスーパーカラムを持つかどうかはカラムファミリーの定義で指定する。
Columnは、Cassandraの最小データ単位。
“カラム”という名前ではあるが、RDBの列名相当ではなく(カラム名だけを指すのではなく)、データ値を保持する構造体。
Column構造体は、カラム名(RDBのカラム名・列名に相当)・データ値・タイムスタンプを持つ。
カラム名は実行時(データ登録時)に好きなように付けられる。
カラム名はバイト列(byte[])。通常は文字列をUTF-8にしたもの。
値はバイト列(byte[])。文字列を扱う場合、通常はUTF-8を使う。
タイムスタンプは64ビットの整数値(long)。
データモデルの説明によると、タイムスタンプに登録する時刻
の値を決めるのは、クライアントアプリの責任。[2010-03-10]
つまり複数のマシンからDB更新を行う際に、マシン毎の日時の整合性が取れていないと とんでもない事になる可能性がある訳だ。
ちなみに、タイムスタンプはマイクロ秒単位にしておくのが無難。(CLIのsetコマンドでデータを登録するとマイクロ秒単位になるから)
(マイクロ秒で扱っても、西暦294247年までは大丈夫(笑))
Columnは
HBaseのCellに相当すると思うが、Cellではカラム名を持っていない。
また、Cellはタイムスタンプと共にデータを履歴管理している。
Cassandra内部でもタイムスタンプを使ってデータの履歴管理がされていると思うが、HBaseと違って履歴そのものを(過去のデータを明示的に)取得することは出来ないようだ。
行は、レコードに相当するもの(これはRDBもHBaseも同じ)。レコードの識別はキー(Key)によって行う。
キーは文字列(String)。
レコードを取得すると、カラムのリスト(List<Column>、厳密に言うとList<ColumnOrSuperColumn>
)が返ってくる。
(HBaseでは、カラム名をキーとし、Cellを値とした(キーでソートされた)マップが返ってくる)
cassandra CLIを使ったデータアクセスは、以下のような感じになる。
(Keyspace1は、Cassandraをインストールした直後のデフォルト状態で入っているキースペース。
Standard1・Standard2は通常のカラムファミリー、Super1・Super2はスーパーカラムを持つカラムファミリー)
cassandra> set Keyspace1.Standard2['jsmith']['first'] = 'John' Value inserted. cassandra> set Keyspace1.Standard2['jsmith']['last'] = 'Smith' Value inserted. cassandra> set Keyspace1.Standard2['jsmith']['age'] = '42' Value inserted. cassandra> get Keyspace1.Standard2['jsmith'] => (column=last, value=Smith, timestamp=1273401786421000) => (column=first, value=John, timestamp=1273401776968000) => (column=age, value=42, timestamp=1273401792781000) Returned 3 results.
cassandra> set Keyspace1.Super1['jsmith']['name']['first'] = 'John' Value inserted. cassandra> set Keyspace1.Super1['jsmith']['name']['last'] = 'Smith' Value inserted. cassandra> set Keyspace1.Super1['jsmith']['attr']['age'] = '42' Value inserted. cassandra> get Keyspace1.Super1['jsmith'] => (super_column=6e616d65, (column=6669727374, value=John, timestamp=1273401380984000) (column=6c617374, value=Smith, timestamp=1273401712765000)) => (super_column=61747472, (column=616765, value=42, timestamp=1273401719343000)) Returned 2 results.
キースペース | カラムファミリー | キー | スーパーカラム | カラム | 値 | |
---|---|---|---|---|---|---|
例1 | Keyspace1 | Standard2 | jsmith | first | John | |
Keyspace1 | Standard2 | jsmith | last | Smith | ||
Keyspace1 | Standard2 | jsmith | age | 42 | ||
次元数 | 1 | 2 | 3 | 4 | ||
例2 | Keyspace1 | Super1 | jsmith | name | first | John |
Keyspace1 | Super1 | jsmith | name | last | Smith | |
Keyspace1 | Super1 | jsmith | attr | age | 42 | |
次元数 | 1 | 2 | 3 | 4 | 5 |
要するに4次元配列(あるいは5次元配列)を扱っているのと同じイメージ。
Cassandraの実装(クライアントとの通信)は、Thriftをベースに作られているらしい。[2010-03-11]
Thriftは、RPC(リモートプロシージャーコール)を扱うフレームワークらしい。
RPCとは、サーバーで動いているプログラムのプロシージャー(関数・メソッド)をリモートで(ネットワーク経由で)呼び出すこと。
となるとサーバーアプリとそれを呼び出すクライアントアプリ、および受け渡すデータ構造(構造体)が必要になるが、Thriftを使うと、それらのプログラム(の雛形)を生成できる。
しかもThriftに対応している言語なら何でもいい。JavaとかC++とかC#とかPerlとか。
Cassandraのサーバープログラム(クライアントとの通信部分)はThriftを使って生成されているので、Thriftサーバーとして動く。
つまりThriftで生成されたクライアントアプリであれば、(Cassandra本体はJavaだが、)どの言語からでもアクセスできる。
cassandra CLIは、Javaで作られたThriftクライアントアプリということになる。