サービスのスケーリングについて

サービスは、規模が大きくなっても運用できるようにしておかなければなりません。

Webの世界でも、「リバースプロキシやバランサを利用したWebサービスの分散」や「レプリケーション、Shardingなどを利用したデータベースの分散やパフォーマンスチューニング」など、数え上げればきりがない程、スケーリングに関する様々なノウハウが共有される時代になっています。

ところが、それらは主にWebサービスとデータベースを中心とした、プル型のアーキテクチャに最適化されたものです。

XMPPのようにクライアントが接続を維持し続けるようなタイプのサービスでは、また違った考え方が必要になります。

どのような課題があり、Oceanでどのようにソリューションを提供しているのかを解説します。

問題

サーバーパフォーマンスからくる同時接続数の限界

サービスの規模が拡大し、ユーザー数が増えていくといつか必ず、1サーバーあたりの同時接続数の限界に達するでしょう。サーバーの性能次第ですが、「メモリが足りなくなり、それ以上接続をもてないケース」や、「それ以上の接続を提供すると、メッセージ送信数が非常に多くなり、スループットに問題が出るケース」などが考えられます。

プロセス/スレッドのブロック

XMPPのようなサーバーでは、同時接続数が非常に多くなるために、サーバー側は多重化IOを利用してイベントドリヴンな処理をするのが一般的です。そのようなアーキテクチャ上では重い同期処理は命取りになります。例えば、一つのコネクションが何らかのIQスタンザを送ってきたときに、その要求に答えるため、データベースに同期的にクエリを飛ばします。データベースからのレスポンスを待っている間、プロセスやスレッドをブロックしてしまい、他のユーザーコネクションからのメッセージなどがつっかえてしまい、読み込みバッファがすぐに一杯になってしまいます。

HTTPでは、起動時にいくつかのプロセスを起動するpreforkや、あるいはそれぞれのプロセス上でスレッドをいくつか生成しておき、一つのリクエストに対し、一つのプロセス、スレッドでレスポンスを返していきますが、XMPPでは、場合によっては数万を超えるコネクションを維持しなければならず、スレッドを利用してもせいぜい千単位が限界であり無理があります。

サーバーライフサイクルとサービスコード更新頻度のミスマッチ

一般的なWebのサービスでは毎日開発が続けられ、そのコードがデプロイされています。サーバーは順番に再起動され、デプロイされたコードが反映されていく、というケースが多いのではないでしょうか。(ホットデプロイを除く)。

例えば一日一回このような処理をしているとします。バグが発見されたら、緊急のコード修正を行い、再びデプロイをすることになります。そうすると一日数回の再起動が発生することになります。一般的にはこのような運用が行われますが、Webサービスのようなステートレスなサービスの場合、複数並べて順番に再起動すれば、クライアントには意識させることなくサービスのリブートが可能です。

ところが、XMPPのような接続しっぱなしのサービスではそのようにはいきません。再起動するときには、ぶらさがってる全てのクライアントを一つずつ切断処理を行っていく必要があり、切断されたクライアントは再びサービスの提供を受けるために、再起動後のサーバー、あるいは別のサーバーに、接続をしなおす必要があります。

このようなサービス形態においても、上記のように一日数回の再起動をしてもよいものでしょうか。

結局のところはポリシー次第になるのですが、あまり頻繁な再起動を許可したくはないタイプのサービスであることは確かです。


Ocean Cluster

Oceanでは、前述の課題に対するソリューションとして、下の画像のような三層構成のアーキテクチャのシステムを提供しています。具体的に説明していきましょう。

もちろん、開発ガイドで説明したとおり、ハンドラやコンテキストを自由に実装できますので、開発者がこの問題に対するソリューションを、フルスクラッチで好きに実装してしまうことも可能です。

[画像が入る]

三つのレイヤーを、それぞれ

  • フロントエンドノード群
  • メッセージブローカー
  • デリバリーサービス

という名で呼んでいます。

フロントエンドノードとは、単に、開発ガイドでこれまで見てきたような、Ocean XMPPサーバーの事です。フロントエンドノードを省略して単にノードとも呼ぶことにします。

前節の同時接続数の限界で説明した通り、一台のノードで接続数の限界が来た場合、複数台のノードを並べなければなりません。これを並べたレイヤーが、フロントエンドノード群と呼ばれます。

さて、ノードを並べたところで、上で説明したノード間の配送問題が残ります。この問題のために、サードパーティ製のメッセージキューミドルウェアを利用します。

メッセージキュー

Oceanで用意されるフレームワーク

Oceanでは、上記の構成のためにフロントエンドノードのクラスタ用ハンドラフレームワーム、デリバリーサービスフレームワークを用意しています。フロントエンドノードのクラスタ用ハンドラフレームワークというのは、実際のところ、スタンドアローンモードのように、あらかじめ動作が記述されたイベントハンドラを使っているに過ぎません。

デリバリーサービスのほうも、単なるGearmanのワーカーです。

開発ガイドで説明してきたようなインテグレーションによって、フルスクラッチで自由にクラスターシステムを構築することも可能です。