既存のDroongaクラスタについて、新しいreplicaを追加し、既存のreplicaを削除し、および、既存のreplicaを新しいreplicaで置き換えるための手順を学ぶこと。
このチュートリアルでは、最初のチュートリアルで準備した2つの既存のDroongaノード:node0
(192.168.100.50
) 、 node1
(192.168.100.51
) と、新しいノードとして使うもう1台のコンピュータ node2
(192.168.100.52
) があると仮定します。
あなたの手元にあるDroongaノードがこれとは異なる名前である場合には、以下の説明の中のnode0
、node1
、node2
は実際の物に読み替えて下さい。
Droongaのノードの集合には、「replica」と「slice」という2つの軸があります。
「replica」のノード群は、完全に同一のデータを持っており、検索などのリクエストを各ノードが並行して処理する事ができます。 新しいreplicaを追加する事によって、増加するリクエストに対して処理能力を増強することができます。
他方、「slice」のノード群はそれぞれ異なるデータを持ちます(例えば、あるノードは2013年のデータ、別のノードは2014年のデータ、という具合です)。 新しいsliceを追加する事によって、増大するデータ量に対してクラスタとしての容量を拡大することができます。
現在の所、Groonga互換のシステムとして設定されたDroongaクラスタについては、replicaを追加することはできますが、sliceを追加することはできません。 この点については将来のバージョンで改善する予定です。
ともかく、このチュートリアルでは既存のDroongaクラスタに新しいreplicaを追加する手順を解説します。 早速始めましょう。
クラスタへのreplicaノードの「Hot-Add」(サービスのダウンタイム無しでクラスタ構成を動的に変更すること。この場合はreplicaの動的な追加)を行うためには、クラスタ内に2つ以上の既存replicaが存在している必要があります。 この操作の進行中は、既存のreplicaのうち1つが新しいreplicaに対する「データのコピー元」となり、それ以外のノードがサービスを提供することになります。
クラスタ内に既存のreplicaが1つしかない場合には、cronjobによるバッチ処理、クローラなどのデータベースに対する変更操作を、操作が完了するまでの間全て停止しておく必要があります。 でないと、追加したreplicaと既存のreplicaの内容に不整合が発生します。 以下は、データベースに変更を加える代表的な組み込みのコマンドの一覧です:
add
column_create
column_remove
delete
load
table_create
table_remove
ただし、既存のデータに一切変更を加えない種類のメッセージ(search
やsytem.status
など)については、この操作の間も利用できます。
端的に言うと、既存のreplicaが1つだけしかない場合は、新しいreplicaを追加する操作の間はクローリングを停止する必要がある、という事ですね。
ここでは、node0
と node1
の2つのreplicaノードからなるDroongaクラスタがあり、新しいreplicaノードとして node2
を追加すると仮定します。
まず、新しいコンピュータをセットアップし、必要なソフトウェアのインストールと設定を済ませます。
(on node2)
# curl https://raw.githubusercontent.com/droonga/droonga-engine/master/install.sh | \
HOST=node2 bash
# curl https://raw.githubusercontent.com/droonga/droonga-http-server/master/install.sh | \
ENGINE_HOST=node2 HOST=node2 bash
注意点として、空でないノードを既存のクラスタに追加することはできません。 もしそのコンピュータがかつてDroongaノードとして使われていた事があった場合には、最初に古いデータを消去する必要があります。
(on node2)
# droonga-engine-configure --quiet \
--clear --reset-config --reset-catalog \
--host=node2
# droonga-http-server-configure --quiet --reset-config \
--droonga-engine-host-name=node2 \
--receive-host-name=node2
では、サービスを起動しましょう。
(on node2)
# service droonga-engine start
# service droonga-http-server start
この時点で、この新しいノードは既存のクラスタのノードとしては動作していません。
この事は、system.status
コマンドを通じて確認できます:
$ curl "http://node0:10041/droonga/system/status" | jq "."
{
"nodes": {
"node0:10031/droonga": {
"status": "active"
},
"node1:10031/droonga": {
"status": "active"
}
},
"reporter": "..."
}
$ curl "http://node2:10041/droonga/system/status" | jq "."
{
"nodes": {
"node2:10031/droonga": {
"status": "active"
}
},
"reporter": "..."
}
前の項目に引き続いてこのチュートリアルを順番に読み進めている場合、クラスタに対してはデータの流入がまだ無い状態になっているはずです。 Hot-Addを試してみるために、以下のようにして、継続的に新しいレコードを追加する仮想的なデータソースを準備しましょう:
(on node0)
$ count=0; maxcount=500; \
while [ "$count" -lt "$maxcount" ]; \
do \
droonga-add --host node0 --table Store --key "dummy-store$count" --name "Dummy Store $count"; \
count=$(($count + 1)); \
sleep 1; \
done
これは、合計で500件のレコードを1秒ごとに1レコードずつ追加する例です。
droonga-add
はDroongaが提供しているコマンドラインユーティリティですが、今のところは詳細について理解していなくてもも大丈夫です。
既存のクラスタに新しいreplicaを追加するには、いずれかの既存のreplicaまたは新しく追加するreplicaの上で、droonga-engine-join
というコマンドを以下のようにして実行します:
(on node2)
$ droonga-engine-join --host=node2 \
--replica-source-host=node0 \
--receiver-host=node2
Start to join a new node node2
to the cluster of node0
via node2 (this host)
port = 10031
tag = droonga
dataset = Default
Source Cluster ID: 8951f1b01583c1ffeb12ed5f4093210d28955988
Changing role of the joining node...
Configuring the joining node as a new replica for the cluster...
Registering new node to existing nodes...
Changing role of the source node...
Getting the timestamp of the last processed message in the source node...
The timestamp of the last processed message at the source node: xxxx-xx-xxTxx:xx:xx.xxxxxxZ
Setting new node to ignore messages older than the timestamp...
Copying data from the source node...
100% done (maybe 00:00:00 remaining)
Restoring role of the source node...
Restoring role of the joining node...
Done.
このコマンドは、以下のようにして別のノード上で実行することもできます:
(on node1)
$ droonga-engine-join --host=node2 \
--replica-source-host=node0 \
--receiver-host=node1
Start to join a new node node2
to the cluster of node0
via node1 (this host)
...
--host
オプションで、その新しいreplicaノードのホスト名(またはIPアドレス)を指定して下さい。--replica-source-host
オプションで、クラスタ中の既存のノードの1つのホスト名(またはIPアドレス)を指定して下さい。--receiver-host
オプションで、コマンドを実行しているマシン自身のホスト名(またはIPアドレス)を必ず指定して下さい。すると、このコマンドは自動的にクラスタ内のデータを新しいreplicaに同期し始めます。 全てのデータを無事に同期し終えたら、新しいノードはクラスタのreplicaとしてそのまま働き始めます。
以上の操作で、新しいreplicaノードがDroongaクラスタへ無事に追加されました。
system.status
コマンドを使って、これらのノードがクラスタとして動作していることを確かめましょう:
$ curl "http://node0:10041/droonga/system/status" | jq "."
{
"nodes": {
"node0:10031/droonga": {
"status": "active"
},
"node1:10031/droonga": {
"status": "active"
},
"node2:10031/droonga": {
"status": "active"
}
},
"reporter": "..."
}
新しいノードnode2
がクラスタに参加したため、各ノードのdroonga-http-server
は自動的に、メッセージをnode2
にも分配するようになります。
全てのreplicaが同等になっているかどうかは、system.statistics.object.count.per-volume
を使って以下のように確かめられます:
(on node0)
$ curl "http://node0:10041/droonga/system/statistics/object/count/per-volume?output\[\]=total" | jq "."
{
"node0:10031/droonga.000": {
"total": 540
},
"node1:10031/droonga.000": {
"total": 540
},
"node2:10031/droonga.000": {
"total": 540
}
}
出力されている数値は、各ノードのデータベースに何個のオブジェクトが保持されているかを示しています。 全ての値が同じなので、各レプリカはお互いに同等の状態になっているということが分かります。
Droongaノードは、メモリ不足、ディスク容量不足、ハードウェア障害など、様々な致命的な理由によって動作しなくなり得ます。 Droongaクラスタ内のノードは互いに監視しあっており、動作しなくなったノードに対してはメッセージの配送を自動的に停止して、動作しないノードがあってもクラスタ全体としては動作し続けるようになっています。 このような時には、動作していないノードを取り除く必要があります。
もちろん、他の目的に転用したいといった理由から、正常動作中のノードを取り除きたいと考える場合もあるでしょう。
ここでは、node0
、 node1
、node2
の3つのreplicaノードからなるDroongaクラスタがあり、最後のノード node2
をクラスタから離脱させようとしていると仮定します。
replicaノードを既存のクラスタから削除するには、クラスタ内のいずれかのノードの上で、以下のようにしてdroonga-engine-unjoin
コマンドを実行します:
(on node0)
$ droonga-engine-unjoin --host=node2 \
--receiver-host=node0
Start to unjoin a node node2:10031/droonga
by node0 (this host)
Unjoining replica from the cluster...
Done.
--host
オプションで、クラスタから削除するノードのホスト名(またはIPアドレス)を指定して下さい。--receiver-host
オプションで、コマンドを実行しているマシン自身のホスト名(またはIPアドレス)を必ず指定して下さい。すると、指定されたノードがクラスタから自動的に離脱します。
これで、ノードのクラスタからの切り離しは無事に完了しました。
node2
が本当にクラスタから離脱しているかどうかは、`system.status コマンドを使って以下のように確かめられます:
$ curl "http://node0:10041/droonga/system/status" | jq "."
{
"nodes": {
"node0:10031/droonga": {
"status": "active"
},
"node1:10031/droonga": {
"status": "active"
}
},
"reporter": "..."
}
$ curl "http://node2:10041/droonga/system/status" | jq "."
{
"nodes": {
"node2:10031/droonga": {
"status": "active"
}
},
"reporter": "..."
}
ノードnode2
はもはやクラスタの一員ではないため、node0
とnode1
のdroonga-http-server
はnode2
のdroonga-engine
へはもうメッセージを送りません。
またその一方で、node2
のdroonga-http-server
はそのノード上のdroonga-engine
にのみ関連付けられており、他のノードへはメッセージを送りません。
ノードの置き換えは、上記の手順の組み合わせで行います。
ここでは、node0
と node1
の2つのreplicaノードからなるDroongaクラスタがあり、node1
が不安定で、それを新しいreplicaノード node2
で置き換えようとしていると仮定します。
まず、不安定になっているノードを取り除きます。以下のようにしてクラスタからノードを離脱させて下さい:
(on node0)
$ droonga-engine-unjoin --host=node1
これで、ノードがクラスタから離脱しました。この事は system.status
コマンドで確かめられます:
$ curl "http://node0:10041/droonga/system/status" | jq "."
{
"nodes": {
"node0:10031/droonga": {
"status": "active"
}
},
"reporter": "..."
}
次に、新しいreplica node2
を用意します。
必要なパッケージをインストールし、catalog.json
を生成して、サービスを起動します。
(on node2)
# curl https://raw.githubusercontent.com/droonga/droonga-engine/master/install.sh | \
HOST=node2 bash
# curl https://raw.githubusercontent.com/droonga/droonga-http-server/master/install.sh | \
ENGINE_HOST=node2 HOST=node2 bash
そのコンピュータがかつてDroongaノードの一員だったことがある場合は、インストール作業の代わりに、古いデータを消去する必要があります:
(on node2)
# droonga-engine-configure --quiet \
--clear --reset-config --reset-catalog \
--host=node2
# droonga-http-server-configure --quiet --reset-config \
--droonga-engine-host-name=node2 \
--receive-host-name=node2
そうしたら、そのノードをクラスタに参加させましょう。
(on node2)
$ droonga-engine-join --host=node2 \
--replica-source-host=node0
最終的に、node0
と node2
の2つのノードからなるDroongaクラスタができあがりました。
この事は、system.status
コマンドの結果を見ると確認できます:
$ curl "http://node0:10041/droonga/system/status" | jq "."
{
"nodes": {
"node0:10031/droonga": {
"status": "active"
},
"node2:10031/droonga": {
"status": "active"
}
},
"reporter": "..."
}
このチュートリアルでは、既存のDroongaクラスタに新しいreplicaノードを追加する方法を学びました。 また、既存のreplicaを取り除く方法と、既存のreplicaを新しいreplicaで置き換える方法も学びました。