CLOVER🍀

That was when it all began.

Apache Cassandraでクラスタを組んでみる

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)

とりあえず、クラスタの構築ができましたよっと。

参考)
Cassandra クラスターの構築

Cassandra 3.7 のクラスタ構築 - Symfoware

EC2 インスタンス上に Cassandra クラスタを構成する(1) - ようへいの日々精進XP