Cassandraを使用している際、容量が足りない、負荷が高いなどの理由でノードを増やしたい場合があります。
また、負荷が長期的に落ち着き、予算を抑えるためにノードを減らすこともあります。
そこで今回は、ノードの追加と削除を行います。
○トークンの算出
ノードを追加するケースをリングの負荷状態によって大きく分けてみると、下記2通りかと思います。
- 保存するデータのハッシュやアクセスに偏りが大きく、特定ノードの容量または処理の負荷が高いため
負荷集中を分散したい。 - リング全体の容量、または処理の負荷が高いため、全体的に数を増やして均一に分散したい。
1.の場合、負荷の高いノードの近くにノードを追加し、ノードの均一化はせずに特定のトークンの範囲にノードを
集中させた方が良さそうです。
2.の場合、ノードを追加したら、全ノードが均等にリング上に再配置したほうが全体としての負荷は
抑えられそうです。
今回は1.の場合を例に挙げてみます。
まず、トークンを計算するためのツールを作っておくと便利です。
引数にノードの数を与えるとそれがリング上に均等に配置されるようなトークンのリストを返すツールです。
計算式はPartitionerによってことなり、以下のようになります。
#RandomPartitionerの場合
def tokens(nodes):
for x in xrange(nodes):
print 2 ** 127 / nodes * x
#Murmur3Partitionerの場合
def tokens(num_nodes):
for i in range(num_nodes):
print ((2**64 / num_nodes) * i) - 2**63
今回はMurmur3Partitionerを使用しているため、以下のようなpythonスクリプトを作ります。
#!/usr/bin/python
import sys
argvs = sys.argv
tokenc = int(argvs[1])
def tokens(num_nodes):
for i in range(num_nodes):
print ((2**64 / num_nodes) * i) - 2**63
tokens(tokenc)
引数にノード数を入れて実行すると、ノードリングに均等に配置された場合のハッシュトークンのリストが
出力されます。
$ ./tokens.py 4
-9223372036854775808
-4611686018427387904
0
4611686018427387904
$ ./tokens.py 8
-9223372036854775808
-6917529027641081856
-4611686018427387904
-2305843009213693952
0
2305843009213693952
4611686018427387904
6917529027641081856
既存のノードが4つだったとして、トークンが以下のように配置されているとします。
- A:0
- B:4611686018427387904
- C:-9223372036854775808
- D:-4611686018427387904
この場合、Aの両脇にノードを2つ追加しておくと良さそうです。
また、追加ノードのトークンは、次のように配置する形になります。
- B、DもCに比べて負荷が高めであればA-B, A-Cのそれぞれ中間
- BDの負荷はそれほどでもなければもっとAより
前者であれば、./tokens 8、後者であれば./tokens 12 などでAの位置の両脇のトークンを使用します。
例えば、後者のパターンで追加してみます。
$ ./tokens 12
-9223372036854775808
-7686143364045646507
-6148914691236517206
-4611686018427387905
-3074457345618258604
-1537228672809129303
-2
1537228672809129299
3074457345618258600
4611686018427387901
6148914691236517202
7686143364045646503
-2の部分がAのノード位置で、その両脇にある下記が、今回の追加ノードとなります。
- -1537228672809129303
- 1537228672809129299
以前の記事で少し触れましたが、自動でリングに追加されるようなAMIを作ってみます。
○AMIの作成
AMIを作成するのですが、cassandraをインストールしただけでまだ一度も起動していないインスタンスを
ベースに作業を行うとスムーズです。
以下の設定ファイルには、IPなどノード固有の情報(『』の部分)が含まれます。
/usr/local/cassandra/conf/cassandra.yaml
cluster_name: 'クラスタ名'
initial_token: 『トークン』
seed_provider:
- class_name: org.apache.cassandra.locator.SimpleSeedProvider
parameters:
- seeds: "『シードIP』"
listen_address: 『自分のIP』
endpoint_snitch: Ec2Snitch
auto_bootstrap: 『シードならfalse,非シードならtrue』
/etc/hosts
127.0.0.1 localhost.localdomain localhost 『ip-10-0-1-10』
この固有の項目を書き換えるようなシェルスクリプトを書きます。
このスクリプトは後でUserDataから呼び出され、第1引数にトークン、
第2引数にauto_bootstrapのブーリアン文字列、第3引数にシードIPが渡されます。
/etc/cloud/cassandra.sh
sed -i "1s/ip-.*//g" /etc/hosts
sed -i "1s/$/ $(hostname)/g" /etc/hosts
sed -i "s/^listen_address:.*$/listen_address: $(curl -s http://169.254.169.254/latest/meta-data/local-ipv4)/" /usr/local/cassandra/conf/cassandra.yaml
sed -i "s/^initial_token:.*$/initial_token: $1/" /usr/local/cassandra/conf/cassandra.yaml
sed -i "s/^auto_bootstrap:.*$/auto_bootstrap: $2/" /usr/local/cassandra/conf/cassandra.yaml
sed -i "s/^ - seeds:.*/ - seeds: "$3"/" /usr/local/cassandra/conf/cassandra.yaml
/etc/init.d/cassandra start
ここまで設定したらno rebootでAMIを作成します。
○ノードの自動追加
このAMIを使い、新規ノードを追加します。
クラスタも何もない状態で、一番最初のノードを立ち上げる場合は以下のようにUserDataを指定します。
#!/bin/sh
/etc/cloud/cassandra.sh "0" false 10.0.1.10
そして、プライベートIPアドレスを10.0.1.10に固定して起動します。
また、2個目以降(ここでは例として6個目)の追加ノードは以下のようにUserDataを指定します。
ここで、第1引数のトークンは冒頭で記した計算ツールで算出しておきます。
#!/bin/sh
/etc/cloud/cassandra.sh "1537228672809129299" true 10.0.1.10,10.0.1.146,10.0.1.176,10.0.1.232,10.0.1.134
特にプライベートIPを指定する必要はありません。
これにより、立ち上がったインスタンスでは、hostsファイルとcassandra.yamlが自動的に設定され、
cassandraが起動し、リングに自動的に追加されます。
起動前の状態
# /usr/local/cassandra/bin/nodetool ring
Datacenter: ap-northeast
==========
Replicas: 3
Address Rack Status State Load Owns Token
-4611686018427387905
10.0.1.146 1a Up Normal 75.43 KB 66.67% -1537228672809129303
10.0.1.10 1a Up Normal 61.65 KB 50.00% 0
10.0.1.176 1a Up Normal 58.33 KB 58.33% -9223372036854775808
10.0.1.232 1a Up Normal 58.45 KB 50.00% 4611686018427387901
10.0.1.134 1a Up Normal 58.48 KB 75.00% -4611686018427387905
起動後の状態
# /usr/local/cassandra/bin/nodetool ring
Datacenter: ap-northeast
==========
Replicas: 3
Address Rack Status State Load Owns Token
-4611686018427387905
10.0.1.213 1a Up Normal 49.55 KB 33.33% 1537228672809129299
10.0.1.146 1a Up Normal 63.7 KB 66.67% -1537228672809129303
10.0.1.10 1a Up Normal 66.59 KB 50.00% 0
10.0.1.176 1a Up Normal 63.28 KB 50.00% -9223372036854775808
10.0.1.232 1a Up Normal 63.4 KB 33.33% 4611686018427387901
10.0.1.134 1a Up Normal 63.43 KB 66.67% -4611686018427387905
上記のようにノードが追加されていることが分かります。
○ノードの取り外し
逆に問題があるノードを取り外すときは、そのノードに入り以下のようにすれば外れます。
# /usr/local/cassandra/bin/nodetool decommission
再び接続させるには、cassandraを追加します。
#/etc/init.d/cassandra stop
#/etc/init.d/cassandra start
○接続できない場合
時々、リングに接続できなかったりした場合は、まず7000(ノード間), 9160(Thrift), 7199(JMX)などのポートを
準備できているか、セキュリティグループやnetstatで確認します。
netstatでlistenできていない場合は、cassandraを再起動させる、ログを調べる等して原因を探していく流れに
なります。
# netstat -tupln | grep -i listen | grep java
tcp 0 0 0.0.0.0:9160 0.0.0.0:* LISTEN 3967/java
tcp 0 0 0.0.0.0:38250 0.0.0.0:* LISTEN 3967/java
tcp 0 0 0.0.0.0:53170 0.0.0.0:* LISTEN 3967/java
tcp 0 0 10.0.1.213:7000 0.0.0.0:* LISTEN 3967/java
tcp 0 0 0.0.0.0:7199 0.0.0.0:* LISTEN 3967/java
以上で、ノードを簡単に増やせるようになりました。
こちらの記事はなかの人(memorycraft)監修のもと掲載しています。
元記事は、こちら