Apache Cassandraで、クラスタを組んでみたいと思います。
Apache Cassandraのバージョンは、3.9とします。
クラスタの組み方ですが、以下のドキュメントに沿って行えばOKです。
※ここでは、単一データセンターの場合を対象にします
対象の環境
クラスタは、今回は3台で構成します。
各Nodeは、それぞれ
- 172.17.0.2 … Seed Node
- 172.17.0.3
- 172.17.0.4
とします。ここで、Seed Nodeというのは、起動時の最初のNodeと捉えればOKそうで、それ以降の意味はない
みたいです。他のNodeは、起動時にSeed Nodeに指定されたNodeを参照するように設定します。
Seed Nodeの設定
では、まずはSeed Nodeの設定を行います。
Cassandraが起動している場合は、Cassandraを停止。
$ sudo service cassandra stop
初期構築なのでデータを削除します。
$ sudo rm -rf /var/lib/cassandra/data/system/*
設定ファイル「/etc/cassandra/cassandra.yaml」を編集します。
今回、変更点は以下のようにしました。
cluster_name: 'My Cassandra Cluster' seed_provider: - class_name: org.apache.cassandra.locator.SimpleSeedProvider parameters: - seeds: "172.17.0.2" listen_address: 172.17.0.2 rpc_address: 172.17.0.2 auto_bootstrap: false
ここで、「cluster_name」はCassandraクラスタの名前(クラスタ内のNodeで同じにする必要があります)、「listen_address」は他のNodeが
このNodeに接続するためのアドレス(デフォルトはlocalhostなので接続不可)、「rpc_address」はcqlshなどのクライアントプログラムが
アクセスするためのアドレス(デフォルトはlocalhostなのでリモート接続不可)となります。
「auto_bootstrap」のみ、変更ではなく追加です。その他、クラスタ名をサンプル的に変更し、IPアドレス関係のパラメーターはすべて
自分自身(172.17.0.2)を指すように変更しました。
なお、「auto_bootstrap: false」は「データなしで新しいクラスターを初期化する場合にのみ追加」するらしいです。
説明を見ると、新しい(Seedでない)Nodeがデータを自分に移行してくるためのものみたいです(デフォルトtrue)。
cassandra.yaml構成ファイル / 高度なプロパティ
「num_tokens」は変更しませんでした。
num_tokens: 256
ここまでできたら、Seed Nodeを起動します。
$ sudo service cassandra start
ここまでで、Seed Nodeの準備はおしまいです。
その他のNodeの設定
それでは、残り2つのNodeの設定をしていきます。
Cassandraの停止とデータの削除。
$ sudo service cassandra stop $ sudo rm -rf /var/lib/cassandra/data/system/*
設定ファイル「/etc/cassandra/cassandra.yaml」を編集します。
今回、変更点は以下のようにしました。
ひとつ目のNodeの場合。
cluster_name: 'My Cassandra Cluster' seed_provider: - class_name: org.apache.cassandra.locator.SimpleSeedProvider parameters: - seeds: "172.17.0.2" listen_address: 172.17.0.3 rpc_address: 172.17.0.3
2つ目のNodeの場合。
cluster_name: 'My Cassandra Cluster' seed_provider: - class_name: org.apache.cassandra.locator.SimpleSeedProvider parameters: - seeds: "172.17.0.2" listen_address: 172.17.0.4 rpc_address: 172.17.0.4
ここで、「auto_bootstrap」については特に設定していません。また、「listen_address」と「rpc_address」は各NodeのIPアドレス
ですが、「seeds」についてはSeed NodeのIPアドレスを指定します。
あとは、各Nodeを起動。
$ sudo service cassandra start
すると、こんな感じにクラスタに参加したっぽいログが出力されます。
## Node 1追加時 INFO [HANDSHAKE-/172.17.0.3] 2017-01-21 15:58:15,575 OutboundTcpConnection.java:515 - Handshaking version with /172.17.0.3 INFO [HANDSHAKE-/172.17.0.3] 2017-01-21 15:58:15,684 OutboundTcpConnection.java:515 - Handshaking version with /172.17.0.3 INFO [GossipStage:1] 2017-01-21 15:58:17,021 Gossiper.java:1050 - Node /172.17.0.3 is now part of the cluster INFO [RequestResponseStage-1] 2017-01-21 15:58:17,117 Gossiper.java:1014 - InetAddress /172.17.0.3 is now UP INFO [GossipStage:1] 2017-01-21 15:58:17,290 TokenMetadata.java:429 - Updating topology for /172.17.0.3 INFO [GossipStage:1] 2017-01-21 15:58:17,291 TokenMetadata.java:429 - Updating topology for /172.17.0.3 ## Node 2追加時 INFO [HANDSHAKE-/172.17.0.4] 2017-01-21 16:05:25,105 OutboundTcpConnection.java:515 - Handshaking version with /172.17.0.4 INFO [HANDSHAKE-/172.17.0.4] 2017-01-21 16:05:25,157 OutboundTcpConnection.java:515 - Handshaking version with /172.17.0.4 INFO [GossipStage:1] 2017-01-21 16:05:27,116 Gossiper.java:1050 - Node /172.17.0.4 is now part of the cluster INFO [RequestResponseStage-1] 2017-01-21 16:05:27,142 Gossiper.java:1014 - InetAddress /172.17.0.4 is now UP INFO [GossipStage:1] 2017-01-21 16:05:27,202 TokenMetadata.java:429 - Updating topology for /172.17.0.4 INFO [GossipStage:1] 2017-01-21 16:05:27,203 TokenMetadata.java:429 - Updating topology for /172.17.0.4
nodetoolで確認。
$ nodetool status Datacenter: datacenter1 ======================= Status=Up/Down |/ State=Normal/Leaving/Joining/Moving -- Address Load Tokens Owns (effective) Host ID Rack UN 172.17.0.3 134.91 KiB 256 67.8% 3e61e4d1-540f-47c7-8bf2-27c1671737b5 rack1 UN 172.17.0.2 135.08 KiB 256 64.4% 3a5593f3-34f0-4a2b-850f-ae1b8566331e rack1 UN 172.17.0.4 124.2 KiB 256 67.8% ed481698-52c6-45ee-a1c4-dcf473ca83e6 rack1
OKそうですね。
クライアントから確認
クライアントプログラム側からも、確認してみましょう。
まずは、キースペースとテーブルを作成。
$ cqlsh 172.17.0.2 cqlsh> CREATE KEYSPACE IF NOT EXISTS my_keyspace WITH REPLICATION = { 'class': 'SimpleStrategy', 'replication_factor': 3 }; cqlsh> USE my_keyspace; cqlsh:my_keyspace> CREATE TABLE test (id UUID PRIMARY KEY, content text);
Node.jsでこんなプログラムを作成。1000件データを叩き込みます。
index.js
const cassandra = require("cassandra-driver"); const client = new cassandra.Client({ contactPoints: ["172.17.0.2", "172.17.0.3", "172.17.0.4"], keyspace: "my_keyspace" }); const insertCql = "INSERT INTO test (id, content) VALUES(uuid(), 'dummy')"; const queries = Array.from(Array(1000).keys()).map(i => { return { query: insertCql }; }); client .batch(queries) .then(() => client.execute("SELECT COUNT(*) FROM test")) .then(result => console.log("count = " + result.rows[0].count)) .then(() => client.shutdown());
ちょっと変わったこととしては、接続先に全Nodeを加えました。
const client = new cassandra.Client({ contactPoints: ["172.17.0.2", "172.17.0.3", "172.17.0.4"], keyspace: "my_keyspace" });
実行。
$ node index.js count = 1000
このコードだと結果がけっこう不安定で、1000にいかないこともあったりしますが、その後にcqlshで確認すると、ちゃんと1000件入っています。
cqlsh:my_keyspace> SELECT COUNT(*) FROM test; count ------- 1000 (1 rows)
なお、他のNodeにつないで確認しても同じ結果になります。
$ cqlsh 172.17.0.3 Connected to My Cassandra Cluster at 172.17.0.3:9042. [cqlsh 5.0.1 | Cassandra 3.9 | CQL spec 3.4.2 | Native protocol v4] Use HELP for help. cqlsh> use my_keyspace ; cqlsh:my_keyspace> SELECT COUNT(*) FROM test; count ------- 1000 (1 rows)
とりあえず、クラスタの構築ができましたよっと。