分散ストレージのCassandraについて調査中。
CassandraはNoSQL(Not only SQL)データベースの一つ。TwitterやDiggがMySQLからCassandraに移行したことでも有名です。公式サイトのOverviewにもあるように特徴は以下のようになっています。
特徴
Proven (証明) | Facebook, Twitter, Diggなど多くのサービスでの利用実績 |
Fault Tolerant (耐障害性) | レプリケーションによりサーバがダウンしても自動復帰可能 |
Decentralized (分散) | クラスタにより単一障害点がない |
Eventually Consistent (結果整合性) | 楽観的なデータ一貫性を提供 |
Rich Data Model (高度なデータモデル) | 単純なKVSを超える機能を提供 |
Highly Available (高可用性) | 一貫性のレベルを設定可能 |
分散ストレージを扱う上で、Eventually Consistent (結果整合性) は大切な概念なのでしっかり抑えておく必要があります。(参考:EventuallyConsistent – 結果整合性)
また、Cassandraはmemcachedのような従来のKVSよりリッチなデータ構造を提供していて、従来のKVSでは1つのkeyに対して1つのvalueを保持しますが、Cassandraではそのkeyの部分を4次元、もしくは5次元で扱うことができます。READMEに例が載っています。
set Keyspace1.Standard2['jsmith']['first'] = 'John' \ \ \ \ \ \ \ \_ key \ \_ value \ \ \_ column \_ keyspace \_ column family Data stored in Cassandra is associated with a column family (Standard2), which in turn is associated with a keyspace (Keyspace1). In the example above, we set the value 'John' in the 'first' column for key 'jsmith'.
Cassanndraの構造を図にしてみると以下のようになります。
RDBに置き換えると、Keyspaceがデータベース、ColumnFamilyがテーブル、keyが主キー、columnがテーブルのカラムにそれぞれ対応しているイメージです。5次元の場合はSuperColumn(columnのリスト)という次元が追加されます。columnはCassandraにおけるデータの最小単位で以下のような構造。nameがcolumnの名前、valueが値でその他にタイムスタンプも入っています。
{ "name": "site", "value": "rest-term", "timestamp": 1271591729517000 }
インストール
CassandraはJavaで書かれています。(JDK 1.6以降が必要)
* 確認
$ java -version java version "1.6.0_17" Java(TM) SE Runtime Environment (build 1.6.0_17-b04-248-10M3025) Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01-101, mixed mode)
以下からビルド済みバイナリを入手して任意の場所に置きます。
The Apache Cassandra Project
ログとデータベースを保存するディレクトリを作成し、パーミッションを変更。
$ sudo mkdir -p /var/log/cassandra $ sudo chown -R `whoami` /var/log/cassandra $ sudo mkdir -p /var/lib/cassandra $ sudo chown -R `whoami` /var/lib/cassandra
起動、接続確認
フォアグラウンドで起動
$ bin/cassandra -f
データ操作
コマンドラインクライアント cassandra-cli を利用
(‘Test Cluster’で接続、デフォルトポートは9160)
$ bin/cassandra-cli --host localhost --port 9160 Connected to: "Test Cluster" on localhost/9160 Welcome to cassandra CLI. cassandra> show cluster name Test Cluster cassandra> show keyspaces Keyspace1 system cassandra> set Keyspace1.Standard1['rt']['name'] = 'wellflat' Value inserted. cassandra> set Keyspace1.Standard1['rt']['age'] = '25' Value inserted. cassandra> set Keyspace1.Standard1['rt']['site'] = 'rest-term' Value inserted. cassandra> get Keyspace1.Standard1['rt'] => (column=73697465, value=rest-term, timestamp=1271591793931000) => (column=6e616d65, value=wellflat, timestamp=1271591729517000) => (column=616765, value=25, timestamp=1271591787205000) Returned 3 results. cassandra> del Keyspace1.Standard1['rt']['site'] column removed. cassandra> get Keyspace1.Standard1['rt'] => (column=6e616d65, value=wellflat, timestamp=1271591729517000) => (column=616765, value=25, timestamp=1271591787205000) Returned 2 results.
データの登録/取得/削除の操作が直感的でわかりやすいですね。
get Keyspace1.Standard1['rt']
で複数のカラムのvalueが取得できているところも単純なKVSとの違いです。
Cassandraの設定ファイルはconf/storage-conf.xml で、ここでKeyspaceやColumnFamily、ポート番号などを指定します。MySQLだとコマンドでtableを追加したりできますが、Cassandraの場合は起動前にこのファイルで追加することになります。
Perlクライアントの利用
ここではCPANの Net::Cassandra::Easy モジュールを使います。
[perl]
#!/usr/bin/perl
use strict;
use warnings;
use Net::Cassandra::Easy;
use Data::Dumper;
eval {
my $client = Net::Cassandra::Easy->new(
server => ‘localhost’,
port => 9160,
keyspace => ‘Keyspace1’);
$client->connect();
my $key = ‘rt’;
# get
my $result = $client->get([$key],
family => ‘Standard1’,
byname => [qw/name age site/]);
print Dumper($result);
# insert
$client->mutate([$key],
family => ‘Standard1’,
insertions => { ‘site’ => ‘rest-term’ });
# get
$result = $client->get([$key],
family => ‘Standard1’,
byname => [qw/name age site/]);
print Dumper($result);
};
die Dumper($@) if $@;
[/perl]
* 結果
$VAR1 = { 'rt' => { 'Standard1' => { 'name' => 'wellflat', 'age' => '25' } } }; $VAR1 = { 'rt' => { 'Standard1' => { 'site' => 'rest-term', 'name' => 'wellflat', 'age' => '25' } } };
なかなか良いんではないでしょうか。Thriftで通信できるので他の言語からでも簡単に使えそうです。引き続き調査を進めたいと思います。