Droongaで理解する、分散処理の基本のキ：負荷の分散

こんにちは。Droonga開発チームの結城（Piro）です。

2014年の11月29日（いい肉の日）に行われた「[全文検索エンジンGroongaを囲む夕べ5](http://groonga.doorkeeper.jp/events/15816)」では、[Droonga](http://droonga.org/ja/)の現状について[発表をさせて頂きました](http://slide.rabbit-shocker.org/authors/Piro/droonga-as-groonga-with-replication/)。
イベントまで足をお運び頂いた皆様、本当にありがとうございます。

先の発表では、なるべくDroongaのキャッチーな面をお見せしてアピールしたい！という思いの基、今何ができるのか・どう使えるのか・どの程度の性能なのかということに重点を置いたため、それ以外の事についてはほとんど解説しないままとなってしまいました。
そこで、先の発表で端折った実装面の話を、Groonga Advent Calendar内で補完していきたいと思っています。

といっても、筆者自身、Droongaプロジェクトに関わるまで分散処理という物には馴染みがありませんでした。
ですので、Groonga Advent Calendar6日目から何度かに分けて、Droongaの実装の紹介を肴に、（Droongaにおける）分散処理とはどういうものか？を初歩の初歩から解説してみようと思います。


## Droongaとは何なのか？

[Droonga](http://droonga.org/ja/)は、*分散型アーキテクチャを採用した「データ処理エンジン」兼「全文検索エンジン」*です。
Droongaでは、「Droongaノード」と呼ばれるコンピュータ群によって構築された「Droongaクラスタ」が、全体で1つのシステムとして動作します。
現在の所、Droongaクラスタは「レプリケーション機能を持った、GroongaのHTTPサーバとAPIレベルで互換性がある全文検索システム」として利用できます。
また近い将来には、パーティショニング（シャーディング）にも対応する予定です。

![GroongaとDroongaクラスタの比較](https://qiita-image-store.s3.amazonaws.com/0/61387/9ebc3d8c-aa41-1e90-d0ef-1ae083c822ff.png)


……という説明を見て全体像を把握できる人は良いのですが、分散処理に馴染みがないと、そもそも「クラスタって簡単に言うけど、一体何をどうやって連携してるんだ？」「っていうか、処理を分散するってどういう事なんだ？」「何の役に立つんだ？」と思ってしまうのではないでしょうか。


## 分散型のメリットとは？

分散分散とよく言われますが、分散すると一体何が嬉しいのでしょうか。
ざっくり言うと、以下の3つが分かりやすい利点と言えます。

 * *負荷の分散*により、1台のマシンの性能の限界を超えた処理が可能になる。
 * *リスクの分散*により、可用性が高まる。
 * *データの分散*により、今までは扱いきれなかった量のデータを扱えるようになる。

普通のGroongaでも、運用の工夫によってこれらを実現することはできますが、どうしても面倒事が多くなってしまいます。
でも、分散型システムであるDroongaであれば、自分で運用の工夫に頭を悩ませずともこれらのメリットを享受できます。

この記事では、これらのうちの*負荷の分散*に焦点を当てて、分散のメリットを解説します。
また、他の利点についても後の記事で解説していきます。

## 負荷の分散

### 性能の限界

高性能が売りのGroongaですが、処理能力には上限（性能限界）があります。

筆者の手元で、少しずつリクエスト数を増やしていってGroongaがどこまでの負荷に耐えられるかを調べる、というベンチマークを実施しました。
結果を見てみましょう。

![Groongaのスループット性能のグラフ（例）](https://qiita-image-store.s3.amazonaws.com/0/61387/08d28a73-8cfa-9ead-e101-ff1882a12b0d.png)

このグラフは、ある一定の条件下において、Groongaが1秒間に処理できたリクエストの件数（＝スループット）を縦軸に、一度にアクセスしてくるクライアントの数（＝リクエスト数）を横軸にとった物です。

途中まではグラフが傾いているのに、ある時点から急に傾きがなくなってしまっています。
これは、途中までは増えていくリクエストを順調に捌き切っていたのに、ある一定のリクエスト数を超えると、それ以上は処理できていない、という事実を示しています。
これが*性能の限界*で、このグラフからは、「*この条件下では*毎秒150件程度までが処理能力の限界である」ということが読み取れます。
（※あくまで、*この条件下での*性能限界の値であるという事に注意して下さい。CPUの速度、メモリの量、データベースのサイズ、検索リクエストの内容の傾向などによって、性能限界として出てくる数値は変わります。）

リクエスト数が性能限界よりも少ない間は、Groongaは待ち時間ほぼ無しで検索結果を返すことができます。

![処理能力に余裕がある状態](https://qiita-image-store.s3.amazonaws.com/0/61387/0112c86d-ba13-14d1-8ae1-6ba744ddfaf7.png)

では、性能限界を超える多数のリクエストが殺到するとどうなるでしょうか？

こういう時に起こるのが、処理の大渋滞です。

![処理能力を超えている場合](https://qiita-image-store.s3.amazonaws.com/0/61387/991a137c-d81b-15b3-b282-9ccfc4e473e2.png)

処理が渋滞していると、Groongaがリクエストを処理しても処理しても、待ち行列の長さは増える一方ですし、新しく行列に加わったリクエストにとっては、10秒待っても20秒待ってもまだ自分の番が回ってこないということになります。

![Groongaのレイテンシーのグラフ（例）](https://qiita-image-store.s3.amazonaws.com/0/61387/8035e4cd-3e99-e039-676e-018c24eba88d.png)

これは、先程のベンチマークの結果について、リクエストに対するレスポンスがGroongaから返ってくるまでの待ち時間（＝レイテンシー）を縦軸に、一度にアクセスしてくるクライアントの数（＝リクエスト数）を横軸にとってグラフにした物です。
リクエスト数が増えるに連れて、待ち時間が急激に増大していっているのが見て取れるでしょう。
これがいわゆる「アクセス過多」の状態で、「詰まっている」や「溢れている」などと表現することもあります。


### 負荷分散で、性能の限界を突破する

負荷を分散すると、そのような状況の発生を防ぐことができます。
以下は、Droongaが検索リクエストを受け取って結果を返すまでの処理の流れの概略図です。

![リクエストの転送の概要](https://qiita-image-store.s3.amazonaws.com/0/61387/9c94a83b-ae67-e743-e748-5de2102dcb75.png)

さて、ここに1つの検索リクエストが送られてきたとしましょう。
Droongaでは、各ノードはそれぞれが同じ内容のデータベースを持っています。
検索リクエストを受け取ったノードは、そのHTTPリクエストをDroongaクラスタ内部での通信用メッセージに変換してから、クラスタ内での通信用プロトコル（fluentdプロトコル）に乗せて、そのノード自身を含むクラスタ内のノード群のうちいずれか1つにランダムに転送します。
転送先のノードは、リクエストの内容に従って全文検索の処理を行い、処理の結果を含んだメッセージを返却します。
最終的に、返却された検索結果はHTTPレスポンスに変換されて、クライアントまで返されます。

Droongaではこのようなメッセージの転送が常に行われており、検索リクエストは各ノードに均等に分配されることになります。

![複数のDroongaノードで負荷を分担している様子](https://qiita-image-store.s3.amazonaws.com/0/61387/52b57c61-a84c-4e07-9cbf-e5e79915676c.png)


その結果何が起こるかというと、*システム全体で見た時の性能限界*が引き上げられます。

![GroongaとDroongaのスループット性能の比較](https://qiita-image-store.s3.amazonaws.com/0/61387/d64ff244-e82b-89fb-328c-a42e2e095e52.png)

これは、Groongaの性能限界を示すベンチマーク結果のグラフに、Droongaのベンチマーク結果を重ねた物です。
Droongaでは、ノード数が2台に増えると最大で秒間280件程度、3台になると秒間430件程度までのリクエストを処理できています。
（※数値が綺麗に2倍3倍と増えていないのは、上記のメッセージ転送処理によるオーバーヘッドや、ノードごとのハードウェアの性能差などの影響があるためです。）

また、性能限界が引き上げられたことで、待ち行列の大渋滞も発生しにくくなっています。

![GroongaとDroongaのレイテンシーの比較](https://qiita-image-store.s3.amazonaws.com/0/61387/f436f4c5-45c5-9f6c-146d-281d5093110c.png)

これは、Groongaでの待ち時間のグラフに、Droongaでの待ち時間の計測結果を重ねた物です。
Droongaではノード数が2台、3台と増えるに連れてグラフの傾きの角度が緩やかになっていて、大渋滞が発生せずに済んでいることが見て取れるでしょう。

このように、負荷を分散させると、サーバ1台だけでは処理しきれなかった大量のリクエストでも安定して処理することができます。



## まとめ

では、ここまでの話を一旦まとめます。

 * Droongaは、分散型アーキテクチャを採用した「データ処理エンジン」兼「全文検索エンジン」です。
   現時点では「レプリケーションありのGroonga互換の全文検索システム」として利用できます。
 * Droongaは負荷の分散により、単一のGroongaサーバの性能の限界を超えることができます。
   また、ノードの追加により性能の限界を引き上げられます。

## 次回予告

この記事では、「負荷の分散によって処理能力の限界を超えられる」という事を述べました。
ということは、逆に考えると「処理能力に余裕がある状況ならば分散する必要は無い」とも言えそうです。
本当にそうでしょうか？

処理能力に余裕があっても、分散にはメリットがあります。
次の記事では、冒頭に挙げた分散処理の利点の2つ目「*リスクの分散*により、可用性が高まる」という事について解説します。
乞う御期待！