Droonga 1.1.0での「hot add」の仕組みの説明

2015年4月29日付けでリリースしたDroonga 1.1.0 http://droonga.org/news/2015/04/29/release.ja.html ではreplicaノードのhot addが可能になったという事が最大のトピックでしたが、それがどのように実現されているのかについての説明です。
0
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

この辺りを見直して、「古いプロセスから新しいプロセスに主導権が移る」まさにその瞬間を境にして、それまでに来たメッセージはすべて古いプロセスが責任を持って処理しきるようになりました。これで、「いつの時点の書き込みバッファから有用で、いつ時点までが不要なのか」を判定可能になりました。

2015-05-03 09:53:44
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

これらのすべての変更があってやっと、レコード追加のリクエストが流入し続ける状況下での、Droongaクラスタへの新規replicaノードのhot addが可能となりました。1つ1つ問題を解決すという感じで少しずつ歩を進めていたため、随分時間がかかってしまいました。

2015-05-03 09:58:38
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

ともかくようやくこれで、「レプリケーション有りの、Groonga互換の全文検索システム」としてのスタート地点にちゃんと立てたと思います。

2015-05-03 10:01:17
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

シャーディングありの構成でもノードの追加を簡単にできるようにするとか、Groongaの機能でまだ対応できてない機能に対応するとか、やらなきゃいけない事はまだまだ尽きませんが、とりあえずはこれが嘘偽りのないDroongaの最新の状況です。というご報告でした。

2015-05-03 10:04:06

実際に行われる処理の流れから見た、Droonga 1.1.0でのhot addの仕組みの説明

Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

需要ないけど続ける。ここまではDroonga 1.1.0で何をどう変えたか視点の話、ここからはDroonga 1.1.0でreplicaのhot add時に何がどういう順番で起こってるかという視点の話。

2015-05-03 11:05:37
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

A,Bという2つの既存ノードと、新規にreplicaとして追加したいCの、計3つのノードがあるとします。droonga-engine-joinコマンドは、リモート操作のための命令を適宜発行してこれらのノードに順番に指示を与えて、hot addを実現します。

2015-05-03 11:08:37
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

まず、A,Bどちらをデータのコピー元にするか決めます。これはどっちでもok(3ノード以上あるなら「どれか1つをデータのコピー元にする」ということになる)。仮にBをデータのコピー元、Aをサービス継続提供のための残存ノードにするとします。

2015-05-03 11:10:50
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

最初は、Cのroleをabsorb-destinationに変更して、Cのcatalog.jsonにA,Bの情報を追加します。これでCのcatalog.jsonは最終的な状態に等しくなります。

2015-05-03 11:16:53
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

この時点でまだA,BはCの存在を知らないため、A,Bが受信した検索リクエストもレコード追加のリクエストもCには配送されません。

2015-05-03 11:17:04
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

次に、A,Bのcatalog.jsonにCの情報を登録します。これで、すべてのノードのcatalog.jsonが最終的な状態に等しくなります。と同時に、A,Bが受信したメッセージはCにも配送されうる状態になります。

2015-05-03 11:19:10
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

が、実際にはメッセージはA,BからCへは配送されません。これはA,Bのroleがservice-providerなのに対して、Cのroleはabsorb-destinationだからです。配送先決定の段階で、roleの異なるノードは配送先から除外されます。

2015-05-03 11:21:37
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

ただし、この時A,BからCは「レコード追加のリクエストだけは、後でまとめて転送するべき先」として認識されます。そこで、A,Bは自身の持つ書き込みバッファにC宛のレコード追加のリクエストを溜め込み始めます。

2015-05-03 11:24:04
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

次に、Bのroleをabsorb-sourceにします。これで、Aが受信した各種リクエストはBにも転送されなくなり、A(残存ノード)だけがサービスを提供し続ける状態になります。

2015-05-03 11:26:28
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

この時仮にBが検索やデータ追加のリクエストを受け取っても、roleがservice-providerではないため、roleがservice-providerである他のノード(今はAだけしかいない)にリクエストをbounceします。

2015-05-03 11:28:10
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

こうして、サービスから切り離されたB(absorb-source、データベースには情報が詰まってる)とC(absorb-destination、データベースは空っぽ)が用意できました。いよいよデータコピーの開始です。

2015-05-03 11:29:56
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

CはBに対して「データベースの内容をdumpして、C宛に送れ」というリクエストを送ります。Bは自分とroleが同じノードにだけそのリクエストを転送しようとしますが、Bしかいないので当然Bが処理し始めます。

2015-05-03 11:35:47
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

dumpされたメッセージを受け取ったCは、やはりroleが自分と同じノードに対してだけメッセージを配送します。

2015-05-03 11:36:53
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

こうして、同じクラスタに属しているにも関わらずBからCへのデータコピーが行われます。この間、残存ノード(A)の書き込みバッファにはB,C宛のレコード追加リクエストが溜まり続けます。

2015-05-03 11:38:22
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

いっこ忘れてた。データのコピーが始まる前に、Bは自分の「最後に処理したメッセージのタイムスタンプ」を報告して、Cにはそれを「受付可能なメッセージのタイムスタンプの判断基準のタイムスタンプ」として登録します。

2015-05-03 11:56:48
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

この情報はSerfを通じて全ノードに伝搬し、各ノードは「C宛にはいつ時点より後のメッセージだけを(書き込みバッファから)送出すればよい」ということをこの時点で把握します。

2015-05-03 11:57:54
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

さて、データコピーが終わったら復帰処理です。Bのroleがabsorb-sourceからservice-providerに戻ります。これでAからB宛のメッセージ配送が行われるようになります。

2015-05-03 11:59:34
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

この時まだ、AとBのデータベースの内容は同期が崩れています。Bのroleがservice-providerに戻ったことを受けて、AはB宛バッファに溜まっていたレコード追加のリクエストを送出し始めます。これをすべてBが処理しきると、A,Bのデータベースは同期した状態に戻ります。

2015-05-03 12:02:45
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

最後に、Cのroleをabsorb-destinationからservice-providerに戻します。この時点でもやはり、A,BとCの間ではまだデータベースの同期が崩れています。

2015-05-03 12:04:13
Piro🎉"シス管系女子"シリーズ累計5万部突破!!🎉 @piro_or

A,Bはそれぞれ、自身の持つC宛のバッファの内容を送出し始めますが、この時、先ほど通知された「Cにはいつ時点からのリクエストのみを送ればよいか」という情報を使って、BからCへのデータコピーで既に処理された後とみなしてよくなった有効期限切れリクエストは送出されず破棄されます。

2015-05-03 12:07:26