2010年4月アーカイブ


複数の書き込みに対応する環境を作る。


「複数ノード立ち上げたApache Cassandraの環境にて
どのようにデータを分割するか?」
という問いに対しては

「基本的によしなにしてくれるのであまり意識しなくてもよい。」
との回答になります。

つまりはどのノードに繋いでも変わらないとということです。

Cassandraがリクエストを必要に応じてプロキシしてくれるので
「最終的に」しかるべき場所に格納してくれるという動きをしてくれます。

極端な話、接続先のノードを一つに絞ってすべてのリクエストを
そこに集中させると言う方法もありです。

もっとも、そのままそのアクセスポイントが
SPF(Single Point of Failure/シングルポイント障害)に
なってしまいます。

この点に関して、Apache Cassandraでは以下の四つの方法を提示してくれています。

  1. クライアントにおいて接続先を管理し適切な接続ノードに振り分ける。
  2. 要するにアプリケーションを作り込めと言うことですね。

  3. DNSラウンドロビンを使う。
  4. 接続先をFQDNで管理し同一名に複数のIPを割り当て特定のFQDNにアクセスさせる方法を使用する方法です。
    Cassandraはこの方法を推奨しています。ただ、DNSラウンドロビンは負荷分散としては機能的に足りない所が多いので
    自分はお勧めしません。(致命的なのが接続先ノードのステータスを管理しないこと。)

  5. ThriftのAPI、client.get_string_propertyを使用してCassandraノードからノードリストを取得する。
  6. このAPIを使うとこんなJSONが帰ってきます。

    {
    "72360816833403413813516172818645147903":"192.168.1.104",
    "53716703941129153059732412441632990819":"192.168.1.6",
    "4368941974377008489670679703283346037":"192.168.1.106",
    "123621947362397555094783433836216926846":"192.168.1.108"
    }
    レンジとIPですね。これを使って振り分けるアプリケーションを作るとの事です。
    やはりノードのステータスを見ていないので自分としてはお勧めしません。

  7. ロードバランサやプロキシを使う。
  8. LVSなどですね。Thriftのポート(デフォルト:9160)に対するセッションを捌けばよいのでわりと楽かなと。



という訳でLVSを使用した負荷分散環境を構築してみました。
イメージはこんな感じです。

lvs.png

4台ノード構成の真ん中にLVSサーバを挟んでいます。
LVSはわざわざNATにする必要もないのでDR(Direct Routing)を使用。
設定はkeepalivedを使用しています。

とりあえずはaptでkeepalivedとlvsadminをインストールします。
/etc/keepalived/keepalived.confの設定は以下の通り

 

virtual_server_group csdr9160 {
  192.168.1.105  9160
}

virtual_server group csdr9160 {

  delay_loop  3
  lvs_sched   lc
  lvs_method  DR
  protocol TCP

  real_server  192.168.1.6  9160 {

    weight 1
    inhibit_on_failure

    TCP_CHECK {
      connect_port 9160
      connect_timeout 30
    }
  }


  real_server  192.168.1.104  9160 {

    weight 1
    inhibit_on_failure

    TCP_CHECK {
      connect_port 9160
      connect_timeout 30
    }
  }

  real_server  192.168.1.106  9160 {

    weight 1
    inhibit_on_failure

    TCP_CHECK {
      connect_port 9160
      connect_timeout 30
    }
  }

  real_server  192.168.1.108  9160 {

    weight 1
    inhibit_on_failure

    TCP_CHECK {
      connect_port 9160
      connect_timeout 30
    }
  }
}

本来であればVRRPを使用して複数台立てるのが正しいのですが、単純に箱がなかったので単体構成です。

各ノードで

#iptables -t nat -A PREROUTING -d 192.168.1.105 -j REDIRECT

を実行しLVSのDRが稼働するようにします。
これで負荷分散環境は整いました。192.168.1.105:9160をた叩けば任意の
cassandraノードに書き込んでくれるようになりました。


ようやく準備が整いました。次回以降検証を行っていきたいと思います。
次はConsistencyLevelの検証を予定です。

 

間が開いてしまいましたが引き続き複数ノードの話を書いていきたいと思います。
※この間、0.6はbetaからリリースにステータスが変わりました。
さっくり入れ替えてみましたが今のところ単純にバイナリ入れ替えで問題は出ていません。

cassandraを複数ノードで立ち上げる為、「storage-conf.xml」を以下の設定に変更しました。

簡単に解説をつけていきたいと思います。
複数ノード可に関連して変更した箇所は赤色で表示します。
青色はそれ以外の為の変更です。

<Storage>


<ClusterName>Intheforest Cluster</ClusterName> ----------------(1)
<AutoBootstrap>true</AutoBootstrap>----------------------------(2)


<Keyspaces>
<Keyspace Name="TimeStampSimpleTrees">
<ColumnFamily Name="SimpleTrees" CompareWith="BytesType" />
<ColumnFamily Name="SimpleTree-node"
ColumnType="Super"
CompareWith="BytesType"
CompareSubcolumnsWith="BytesType" />


<ReplicaPlacementStrategy>
org.apache.cassandra.locator.RackUnawareStrategy
</ReplicaPlacementStrategy>
<ReplicationFactor>1</ReplicationFactor>
<EndPointSnitch>org.apache.cassandra.locator.EndPointSnitch</EndPointSnitch>

</Keyspace>
</Keyspaces>

<Authenticator>
org.apache.cassandra.auth.AllowAllAuthenticator
</Authenticator>
<Partitioner>org.apache.cassandra.dht.RandomPartitioner</Partitioner>
<InitialToken></InitialToken>

<CommitLogDirectory>/db/cassandra/commitlog</CommitLogDirectory>
<DataFileDirectories>
<DataFileDirectory>/db/cassandra/data</DataFileDirectory>
</DataFileDirectories>


<Seeds>
<Seed>192.168.1.104</Seed>-----------------------------(3)
<Seed>192.168.1.106</Seed>
<Seed>192.168.1.107</Seed>
</Seeds>


<RpcTimeoutInMillis>10000</RpcTimeoutInMillis>
<CommitLogRotationThresholdInMB>128</CommitLogRotationThresholdInMB>


<ListenAddress>node1</ListenAddress>-----------------------------(4)

<StoragePort>7000</StoragePort>


<ThriftAddress>0.0.0.0</ThriftAddress>-----------------------------(5)

<ThriftPort>9160</ThriftPort>
<ThriftFramedTransport>false</ThriftFramedTransport>



<DiskAccessMode>auto</DiskAccessMode>
<RowWarningThresholdInMB>512</RowWarningThresholdInMB>
<SlicedBufferSizeInKB>64</SlicedBufferSizeInKB>
<FlushDataBufferSizeInMB>32</FlushDataBufferSizeInMB>
<FlushIndexBufferSizeInMB>8</FlushIndexBufferSizeInMB>
<ColumnIndexSizeInKB>64</ColumnIndexSizeInKB>
<MemtableThroughputInMB>64</MemtableThroughputInMB>
<BinaryMemtableThroughputInMB>256</BinaryMemtableThroughputInMB>
<MemtableOperationsInMillions>0.3</MemtableOperationsInMillions>
<MemtableFlushAfterMinutes>60</MemtableFlushAfterMinutes>

<ConcurrentReads>8</ConcurrentReads>
<ConcurrentWrites>32</ConcurrentWrites>

<CommitLogSync>periodic</CommitLogSync>
<CommitLogSyncPeriodInMS>10000</CommitLogSyncPeriodInMS>

<GCGraceSeconds>864000</GCGraceSeconds>
</Storage>

 

(1):ClusterName:
クラスター識別用の名前。このクラスターネームが同じCassandraノードが存在した場合、対象ノードをクラスタの一員として認識します。同一ネットワークにあるクラスタ名が同じクラスタノード間でデータの共有を行います。

(2):AutoBootstrap:
起動時の同一クラスター内のデータ同期を行うかどうかの設定。trueに設定してあると起動時に自動的にデータの同期を開始します。トークンを指定していない場合はトークンもよしなにしてくれます。注)一番最初にクラスタを作成する際にすべてのノードのAutoBootstrapをtrueにしているとお互いにデータを取得しにいくのでノードが立ち上がりません。最初の一代目はマスターノードとしてfalseにするのが正しいようです。

(3):Seeds:
起動時に検索しに行くクラスターノードのIPアドレス。ringの形成には影響無いようです。複数指定可。

(4):ListenAddress:
外部とのやりとりを行うため外部から検索可能なIPに紐付けられている正引きできるホスト名。IPアドレスでも構わないのですがホスト名を指定する方が望ましいようです。デフォルトはループバックアドレスに紐付けられているlocalhost。今回は自分のホスト名を自分のアドレス「192.168.1.6」として「/etc/hosts」に書いて指定する方法を選択。正引きできればDNSでも可。

(5):ThriftAddress:
Thriftアプリケーションが外部から接続する際にその接続元を指定するアドレスを記述。デフォルトは自分自身以外からは受け付けない「localhost」。今回はどこからでも接続出来るように「0.0.0.0」を指定。

 

その他、データディレクトリとデータ構造は変更しています。このstorage-conf.xmlを用いて起動します。

起動環境は前回の手順を参照、複数ノードの起動手順としては次の通り

1.1ノード目の/etc/cassandra/storage-conf.xmlを書き換える。但し「AutoBootstrap」は「false」。

2.1ノード目を起動スクリプトで起動。

3.2ノード目の/etc/cassandra/storage-conf.xmlを書き換える。「AutoBootstrap」は「true」。

4.2ノード目を起動スクリプトで起動。

5.3ノード目の/etc/cassandra/storage-conf.xmlを書き換える。「AutoBootstrap」は「true」。

6.3 ノード目を起動スクリプトで起動。

7.4ノード目の/etc/cassandra/storage-conf.xmlを書き換える。「AutoBootstrap」は「true」。

8.4 ノード目を起動スクリプトで起動。

9.1ノード目のcassandraを停止。

10.1ノード目の「AutoBootstrap」を「true」に書き換える。

9.1 ノード目を起動スクリプトで起動。

これで無事同期が始まります。
しばらくすると下のようにリングが確認できるようになります。

$ nodetool --host 192.168.1.104 ring
Address Status Load Range Ring
123621947362397555094783433836216926846
192.168.1.106 Up 21.06 MB 4368941974377008489670679703283346037 |<--|
192.168.1.6 Up 10.33 MB 53716703941129153059732412441632990819 | |
192.168.1.104 Up 3.85 MB 72360816833403413813516172818645147903 | |
192.168.1.108 Up 10.54 MB 123621947362397555094783433836216926846 |-->|
色々の話の流れでapache-cassandraを6台起動する流れに。
あまり情報も無いようなので手順を複数回に分けて書いていこうと思います。

まず最初にapache-cassandraをサーバーとしてインストールする手順を書いていきます。
実際の話サーバー利用するときに「ホームディレクトリで./cassandra -f を手動で」 なんてやっていられませんからね。


apache-cassandraインストール

環境としては以下を使用。

OS:Debian Lenny on Xen 3.3.1
メモリを512MBに制限。(ドキュメントでは1G以上推奨)
ベースHW
Intel CoreDuo 2core 1CPU
メモリ6G
準仮想環境
Dom0に1G割り当て
  1. 環境設定
    • JDKインストール
    • antインストール
  2. cassandraをインストールするにあたってソースからビルドする為の2つのパッケージと起動用に一つのパッケージが必要となるためこれらをインストールします。
    $sudo apt-get install sun-java6-jdk
    $sudo apt-get install ant
    $sudo apt-get install jsvc
    ※趣味的な問題で non-free の sun-javaを使用していますが通常のopenjdk-6-jdkで問題無いと思います。


  3. cassandraのビルド
    • ソース取得
    • 展開
    • ビルド
    • jar作成
  4. apache cassandraソースの取得
    Apache CassandraはApache Software Foundationの配下にあるので自分の場合、Apache絡みはすべてRing Serverから取得しています。
    今回は諸事情によりbeta版ですが0.6を取得。
    $wget http://www.ring.gr.jp/archives/net/apache/cassandra/0.6.0/apache-cassandra-0.6.0-beta3-src.tar.gz
    最近RingServerがだんだん寂れていく感じで少々悲しいです。
    ソースの展開
    $tar xvfz ../src/apache-cassandra-0.6.0-beta3-src.tar.gz
    ビルド
    ソースのビルドを行います。
    $cd apache-cassandra-0.6.0-beta3-src
    $ant
    jar 作成
    jar ファイルを作成します。
    ここら辺のjavaのお作法に関しては結構疎いです。
    $ant jar
  5. インストール
    • インストール
    • 起動設定
    • 起動確認
  6. インストール
    ビルドした各ファイルを各ディレクトリに配置。
    make installなんてないので自力で配置。
    debianの場合、配置の場所がdebian/cassandra.installに
    あるのでこれを元に以下の様なシェルを書いてみました。
    cassandra.install.sh
    #!/bin/sh
    mkdir -p /usr/share/cassandra
    mkdir -p /etc/cassandra

    cp -p conf/log4j.properties /etc/cassandra/
    cp -p conf/storage-conf.xml /etc/cassandra/
    cp -p debian/cassandra.in.sh /usr/share/cassandra/
    cp -p debian/init /etc/init.d/cassandra
    cp -p bin/cassandra /usr/sbin/
    cp -p bin/cassandra-cli /usr/bin/
    cp -p bin/nodetool /usr/bin/
    cp -p bin/clustertool /usr/bin/
    cp -p lib/antlr-3.1.3.jar /usr/share/cassandra/
    cp -p lib/avro-1.2.0-dev.jar /usr/share/cassandra/
    cp -p lib/clhm-production.jar /usr/share/cassandra/
    cp -p lib/high-scale-lib.jar /usr/share/cassandra/
    cp -p lib/libthrift-r917130.jar /usr/share/cassandra/
    cp -p build/lib/jars/commons-cli-1.1.jar /usr/share/cassandra/
    cp -p build/lib/jars/commons-codec-1.2.jar /usr/share/cassandra/
    cp -p build/lib/jars/commons-collections-3.2.1.jar /usr/share/cassandra/
    cp -p build/lib/jars/commons-httpclient-3.1.jar /usr/share/cassandra/
    cp -p build/lib/jars/commons-lang-2.4.jar /usr/share/cassandra/
    cp -p build/lib/jars/commons-logging-1.1.1.jar /usr/share/cassandra/
    cp -p build/lib/jars/google-collections-1.0.jar /usr/share/cassandra/
    cp -p build/lib/jars/hadoop-core-0.20.1.jar /usr/share/cassandra/
    cp -p build/lib/jars/jackson-core-asl-1.4.0.jar /usr/share/cassandra/
    cp -p build/lib/jars/jackson-mapper-asl-1.4.0.jar /usr/share/cassandra/
    cp -p build/lib/jars/jline-0.9.94.jar /usr/share/cassandra/
    cp -p build/lib/jars/json-simple-1.1.jar /usr/share/cassandra/
    cp -p build/lib/jars/junit-4.6.jar /usr/share/cassandra/
    cp -p build/lib/jars/log4j-1.2.14.jar /usr/share/cassandra/
    cp -p build/lib/jars/slf4j-api-1.5.8.jar /usr/share/cassandra/
    cp -p build/lib/jars/slf4j-log4j12-1.5.8.jar /usr/share/cassandra/
    cp -p build/apache-cassandra-0.6.0-beta3.jar /usr/share/cassandra/
    cd /usr/share/cassandra
    ln -s apache-cassandra-0.6.0-beta3.jar apache-cassandra.jar
    chmod 755 /usr/sbin/cassandra
    chmod 755 /usr/bin/cassandra-cli
    chmod 755 /usr/bin/nodetool
    chmod 755 /usr/bin/clustertool
    chmod 755 /etc/init.d/cassandra
    ※ これを元にdebパッケージでも作った方が早いかもしれません。暇があったらそのうち作るかも。
    起動設定
    起動スクリプトの修正
    debianの場合基本的にdebian/initの起動シェルがそのまま使えるので
    これを流用しています。CentOSの人はこの辺は手対応になると思います。
    自分の場合、open-jdkではなくsun-javaを使っているのでJAVA_HOMEを書き換えます。
    --- cassandra   2010-04-01 03:16:13.000000000 +0000
    +++ /home/works/build/apache-cassandra-0.6.0-beta3-src/debian/init
    2010-03-17 18:34:07.000000000 +0000
    @@ -17,7 +17,7 @@
    PIDFILE=/var/run/$NAME.pid
    SCRIPTNAME=/etc/init.d/$NAME
    CONFDIR=/etc/cassandra
    -JAVA_HOME="/usr/lib/jvm/java-6-sun/jre"
    +JAVA_HOME="/usr/lib/jvm/java-6-openjdk/jre"
    JSVC=/usr/bin/jsvc
    JVM_MAX_MEM="1G"
    JVM_START_MEM="128M"
    設定ファイルの変更
    $vim /etc/cassandra/storage-conf.xml
    とりあえず最初は起動するだけなので コミットログディレクトリとデータディレクトリだけ書き換えます。
    <commitlogdirectory>/db/cassandra/commitlog</commitlogdirectory>
    <datafiledirectories>
    <datafiledirectory>/db/cassandra/data</datafiledirectory>
    </datafiledirectories>
    </pre>
    ※ デフォルトの/var/lib/cassandraでよい方はそのままで。
    データディレクトリの作成上記で指定したディレクトリを作成します。
    $mkdir -p /db/cassandra/commitlog
    $mkdir -p /db/cassandra/data
    init設定
    OS再起動時に自動で立ち上がるように起動設定を行います。

    # update-rc.d cassandra defaults
    Adding system startup for /etc/init.d/cassandra ...
    /etc/rc0.d/K20cassandra -> ../init.d/cassandra
    /etc/rc1.d/K20cassandra -> ../init.d/cassandra
    /etc/rc6.d/K20cassandra -> ../init.d/cassandra
    /etc/rc2.d/S20cassandra -> ../init.d/cassandra
    /etc/rc3.d/S20cassandra -> ../init.d/cassandra
    /etc/rc4.d/S20cassandra -> ../init.d/cassandra
    /etc/rc5.d/S20cassandra -> ../init.d/cassandra
    起動スクリプトから起動
    #/etc/init.d/cassandra start
    起動確認
    $cassandra-cli --host localhost 
    pychodoga:/etc/cassandra# cassandra-cli --host localhost
    Connected to: "Test Cluster" on localhost/9160
    Welcome to cassandra CLI.
    Type 'help' or '?' for help. Type 'quit' or 'exit' to quit.
    cassandra>show keyspaces
    Keyspace
    system
    cassandra>
    以上が表示されればOK 表示されない場合、接続できない場合は 「/var/log/cassandra」にある「output.log」「system.log」を確認。

    自分はここまでほとんど問題なかったですねぇ。
    次回以降複数ノードでの立ち上げを書いていきます。
    ※ まだ構築途中...


P.S.ちなみにantでreleaseとか実行すると以下のようなものができます。(苦笑)
apache-cassandra-0.6.0-beta3-src.tar.gzを使った方が手っ取り早いかも。
$ant release
--中略--
[tar] Building tar: /home/works/build/apache-cassandra-0.6.0-beta3-src/build/apache-cassandra-0.6.0-beta3-bin.tar.gz
[tar] Building tar: /home/works/build/apache-cassandra-0.6.0-beta3-src/build/apache-cassandra-0.6.0-beta3-src.tar.gz
BUILD SUCCESSFUL
Total time: 13 seconds

ウェブページ