2010年11月7日日曜日

Cassandraのインストール、設定からRubyによる操作までのメモ


目的
Cassandra(ver 0.6)をインストールし、最低限動くまでの設定をする。
そしてThrift APIとしてRubyを使いCassandraを操作できるようにする。



Cassandraのデータモデルの予備知識
言葉の定義だけは覚えておく。

SQLと比較しながら見るとイメージしやすいだろう。

(SQLでの挿入文)
INSERT INTO Keyspace.ColumnFamily (age) VALUES("30") WHERE id="user";

(Cassandraでの挿入文)
set Keyspace1.ColumnFamily_Standard1["user"]["age"] = "30"
    \          \                      \       \        \
     \          \                      \ key   \ name   \ value 
      \ keySpace \                              \        
                  \ ColumnFamily                 \ column
                                                                        

● キースペース(KeySpace) ※SQLでいうところのデータベース
   複数のカラムファミリを持つ。
   設定ファイルに指定。

カラムファミリ(ColumnFamily) ※SQLでいうところのテーブル
  カラムまたはスーパーカラムの集合。
  設定ファイルに指定。

● カラム(Column)
   Cassandraのデータ最小単位。
   nameとvalueから成る。
   設定は動的。

● ロウ(Row)
   キーに紐づいて取得できるカラムの集合。
   一つのキーに対してカラムは一つとは限らない。
   上の例でいうと、userというキーに対して、
   age以外に、genderなどのカラムを持っていてもよい。
   use名をキーにして年齢と性別という2つのカラムを取得できる。
   このカラム群がロウである。
     
set Keyspace1.ColumnFamily_Standard1["user"]["age"] = "30"
                                            ["gender"] = "man"
                                             \
                                              \ row(複数のcolumn)
カラムファミリはロウごとにソートされており、
アクセスされる場合もこのロウが基本単位となる。


ダウンロード
# cd /usr/local/src

# wget http://www.meisei-u.ac.jp/mirror/apache/dist/cassandra/0.6.6/apache-cassandra-$VERSION-bin.tar.gz

# tar zxvf apache-cassandra-$VERSION.tar.gz



必要なディレクトリの作成
# cd apache-cassandra-$VERSION

# mkdir -p /var/log/cassandra

# mkdir -p /var/lib/cassandra



初期設定
【環境の設定】
# cp bin/cassandra.in.sh bin/cassandra.in.sh.default

# vi bin/cassandra.in.sh
JAVA_HOME=/usr/bin

JVM_OPTS=" \
-Xms512M \
-Xmx512M \
-Dcom.sun.management.jmxremote.port=8080 \


-Xms : 初期ヒープサイズ
-Xmx : 最大ヒープサイズ

 Xms ≦ Xmx とすること

JMXでの接続ポート : 8080


【ログの保存先の設定】
# cp conf/log4j.properties conf/log4j.properties.default

# vi conf/log4j.properties

システムログの保存先の設定
log4j.appender.R.File=/var/log/cassandra/system.log


【起動時の各種設定】
# cp conf/storage-conf.xml conf/storage-conf.xml.default

# vi conf/storage-conf.xml

ThriftでのRPCポートの設定
<ThriftPort>9160</ThriftPort>

複数Cassandrraノードのコミュニケーションポートの設定
<StoragePort>7000</StoragePort>

コミットログディレクトリの保存先の設定
<CommitLogDirectory>/var/lib/cassandra/commitlog</CommitLogDirectory>

データディレクトリの保存先の設定
<DataFileDirectories>
  <DataFileDirectory>/var/lib/cassandra/data</DataFileDirectory>
</DataFileDirectories>

ノードの設定
さしあたり、単一ノードで動作させる
<Seeds>
  <Seed>127.0.0.1</Seed>
</Seeds>

キースペース/カラムファミリの設定
(設定前の備忘録)
・ColumnType属性
  Standart : カラムファミリ内にカラムが含まれる
  Super    : カラムファミリ内にスーパーカラムが含まれる

・CompareWith属性
  スーパーカラムのソートオプション

・CompareSubcolumnsWith
  スーパーカラム内のカラムのソートオプション

<Keyspaces>
  <Keyspace Name="Keyspace1">

    <ColumnFamily Name="ColumnFamily_Standard1"
      ColumnType="Standart"
      CompareWith="BytesType"
      KeysCached="1000"
      RowsCached="100"
     RowCacheSavePeriodInSeconds="0"
      KeyCacheSavePeriodInSeconds="3600"/>
      ※ColumnTypeの指定をしなければ、ディフォルトStandard

    <ColumnFamily Name="ColumnFamily_Super1"
      ColumnType="Super"
      CompareWith="BytesType"
      CompareSubcolumnsWith="BytesType" />

  </Keyspace>
</Keyspaces>



起動
# bin/cassandra -f
-f: start in foreground



コマンドラインによるデータの操作
# bin/cassandra-cli --host localhost

> help
ここでコマンドは確認できる。
また、コマンドはタブ補完が可能である。

> show keyspaces

> set Keyspace1.ColumnFamily_Standard1["user"]["first"] = "John"

> set Keyspace1.ColumnFamily_Standard1["user"]["last"] = "Smith"

> set Keyspace1.ColumnFamily_Standard1["user"]["age"] = "30"

SQL的に書けばこうなる。
INSERT INTO Keyspace1.ColumnFamily_Standard1 (age) VALUES("30") WHERE id="user";


> get Keyspace1.ColumnFamily_Standard1["user"]

> del Keyspace1.ColumnFamily_Standard1["user"]

> quit



Thrift APIによる操作
今回はRubyを利用する。

1) RubyでCassandraを操作するライブラリをRubygemsからインストールする
# gem install cassandra

※ Rubygemsがなければ先にインストールしておくこと
# yum install rubygems


2) RubyからCassandraを操作する
# vi file.rb
require 'rubygems'
require 'cassandra'

# 接続する
client = Cassandra.new("Keyspace1", "127.0.0.1:9160")

# キースペースを表示する
client.keyspaces

# 各種カラムへデータを追加する
client.insert(:ColumnFamily_Standard1, "key1", { "first" => "John" } )
client.insert(:ColumnFamily_Standard1, "key1", { "last" => "Smith" } )
client.insert(:ColumnFamily_Standard1, "key1", { "age" => "42" } )

# スーパーカラムを持っている場合は下のようにする
client.insert(:ColumnFamily_Super1, "key1", {"key2" => {"first" => "John"}})
client.insert(:ColumnFamily_Super1, "key1", {"key2" => {"last" => "Smith"}})
client.insert(:ColumnFamily_Super1, "key1", {"key2" => {"age" => "42"}})

# 各種カラムへ一度にデータを追加するには下のようにする
client.insert(:ColumnFamily_Standard1, "key1", { "first" => "John", "last" => "Smith", "age" => "42" } )

# 下記でも同様だが、ブロックを使うとアトミックに処理できる
# また、ThriftのAPIを一行ずつコールしないので効率的である
client.batch do
  client.insert(:ColumnFamily_Standard1, "key1", { "first" => "John" } )
  client.insert(:ColumnFamily_Standard1, "key1", { "last" => "Smith" } )
  client.insert(:ColumnFamily_Standard1, "key1", { "age" => "42" } )
end

# ロウを取得する
client.get(:ColumnFamily_Standard1, "key1")

# スーパーカラムを持っている場合は下のようにする
client.get(:ColumnFamily_Super1, "key1", "key2")

# 特定のカラムの値を取得する
client.get_columns(:ColumnFamily_Standard1, "key1", ["first"])

# キーとロウのペア群を取得する
# キーの一覧を出したい場合にも利用できる
client.get_range(:ColumnFamily_Standard1).each do |obj|
  obj.columns.each do |column|
  end
end

# また下記のようにキーの始まりと終りを指定し、範囲を絞ってのデータ取得も可能である
# その他オプションとして":count"、":consistency"も指定ができる
client.get_range(:ColumnFamily_Standard1, \
  :start => "カラムの始まり", :finish => "カラムの終わり")

# スーパーカラムを持っている場合の範囲を絞ってのデータ取得は下記である
# スーパーカラムを特定するキー"key1"は固定していることに注意すること
# ここでは、カラムを特定するキーの範囲を指定している
client.get(:ColumnFamily_Standard1, "key1", \
  :start => "キーの始まり", :finish => "キーの終わり")

# 指定したキーのカラムを削除する
client.remove(:ColumnFamily_Standard1, "key1")
client.remove(:ColumnFamily_Super1, "key1", "key2")

# カラムの存在を調べる(存在しなければnilが返る)
client.exists?(:ColumnFamily_Standard1, "key1", "age")
client.exists?(:ColumnFamily_Standard1, "key1", "hoge")

# カラムの数を数える
client.count_columns(:ColumnFamily_Standard1, "key1")


Cassandraの基礎が理解できただろうか。
次はログ検索を高速に行うための、独自アプリケーションを作成してみる。