これまでの記事を振り返って、まとめの意味でも、現状僕が考えうる最強の高集積型Webホスティングシステムの設計を忘れないうちに書いておこうと思います。これらは夢のような話ではなく、現実的にAmazonEC2上にプロトタイプとして作ってもいいなぁ、と思っていたりします。
最強の超高集積型Webホスティングシステム!とは
ホスティングシステムということで、ホストをかりる側がどういうコンテンツを使うのか分からないので、できるだけ自由度の高いシステムを考えた時は、やはりベースソフトウェアはApacheが良いのではと思います。また、超高集積にする事でハードウェアのコストを下げ、超低価格を実現し、かつ、セキュアで運用性が高く高機能なシステムを目指します。
高密度型Webホスティングシステムとしての重要なファクターは以下だと考えています。
- バーチャルホスト方式でとにかく高集積かつスケールアウト構成
- 仮想ホスト間でセキュリティを担保
- 動的コンテンツはCGIやFastCGI、さらにはDSOでも使用可能
- mod_vhost_aliasを使ってサーバのリロードをしない
- バーチャルホスト単位にcgroupでCPUやIOリソースを制限
- 豊富な運用機能やツール
- 足りない機能はmod_mrubyで実装
以上が特徴になります。パッと見た感じ、単体ではそれぞれ実現可能なファクターに思えますが、これらを同時に実現する事は非常に難しく、個人的に多くのWebホスティングを調査した限りではこれらを同時に満たすWebホスティングは存在しませんでした。
では、これらを同時に満たすのがなぜ難しいのかを説明しながら、それぞれの特徴を説明していきたいと思います。
1.バーチャルホスト方式でとにかく高集積かつスケールアウト構成
これは、一般的によく使われる機能ですね。単一のサーバプロセスで複数のホストを仮想的に処理する機能です。これを使えば、高集積が実現できます。
Webホスティングサービスにおいて、限られたリソースでとにかくホストの高集積・高密度を達成するためには、ホスト単位にサーバプロセスを上げたり、仮想マシンを利用していてはリソース面で非効率です。
また、少ない数からホスティングシステムを稼働でき、リソース不足に陥っても簡単にサーバを追加して効率良く負荷分散できるように、共有ストレージにコンテンツを配置し、上位で複数のWebサーバで負荷分散させるようなスケールアウト型の冗長構成を考えた場合、ホストに紐づくプロセスを動作させてしまっては、全てのWebサーバに同様のプロセスを動作させる必要があります。
そのため、ホスト数が千や万のオーダーになった場合に、プロセス数もホスト数に依存する事により、各Webサーバ上のプロセス数が多くなり過ぎるため、このような負荷分散手法はリソース効率が悪く現実的ではありません。そこで、プロセス数がホスト数に依存しない、単一のサーバプロセスで複数のホストを仮想的に処理する手法が必要になるのです。それによって、例えば以下のような構成をとることができます。
これによって、大規模になったとしても、サーバ単位のプロセス数はホスト数に依存せず、容易にスケールアウトが可能になります。まずは1台のサーバで処理していて2000ホストくらいでリソースがきつくなってきたら、同じ設定のサーバを追加することで簡単に負荷分散できます。顧客領域追加でサービス即時反映については、4.で述べることにします。
2.仮想ホスト間でセキュリティを担保
バーチャルホストの仕組みをとってしまうと、仮想ホスト間でセキュリティを担保するのが非常に難しくなります。CGIだとsuEXECによって、サーバプロセスと違う権限でスクリプトを実行することができます。
しかし、例えばPHPのDSO版でPHPスクリプトを実行してしまうと、サーバプロセスと同じ権限でスクリプトが動作してしまうため、サーバプロセスでアクセスできる他の顧客のホストにアクセスすることができてしまいます。顧客としては、CGIのような性能の悪い実行方式よりも、DSOのような性能の高い実行方式でPHPやPerlを実行したいと思うでしょう。
しかし、世の中のバーチャルホストでDSO実行方式に対応しているWebホスティングはほとんど無く、大抵がCGIで提供しています。またDSOで提供している場合はPHPのセーフモードであったりとか、普通に他の領域が覗き見できたりしてしまいます。この点に関しては、「Webサーバの仮想ホスティングにおけるパーミッション設定の答え(Apacheの場合)」で詳しく述べています。
そこで、この問題を解決するために、mod_process_securityを開発しました。これを使えば、DSOであっても実行時に制御用スレッドを挟む事で、スクリプトを顧客の権限で実行する事ができ、他の顧客領域にアクセスできなくなります。また、性能もDSOとほぼ同程度の速度(CGIの数倍以上)でスクリプトを実行する事ができます。詳しいアーキテクチャについては、「mod_process_security – Apache上でスレッド単位で権限分離を行うファイルのアクセス制御アーキテクチャ」を見てください。
これで、バーチャルホストでありながら、高セキュリティと高パフォーマンスを同時に満たす事ができました。
3.動的コンテンツはCGIやFastCGI、さらにはDSOでも使用可能
これは、本来バーチャルホスト方式ではsuEXEC等を使ってCGI上で権限分離を行ったり、mod_suid2やmod_ruidを使ってサーバプロセスそのもので権限分離を行い、サーバプロセスを都度破棄する必要がありました。
このようにセキュリティを優先した場合は、パフォーマンスが非常に悪くなるという問題がありました。こうならざるを得ない理由に関しては、「mod_process_security – Apache上でスレッド単位で権限分離を行うファイルのアクセス制御アーキテクチャ」を見てください。
しかし、上記のmod_process_securityによって、CGIやFastCGI、DSO等の実行方式によらず、統一的に制御スレッドによって権限分離を行えるので、どうのような動的コンテンツでも好きな実行方式で実行する事が可能になります。RubyはFastCGIで、とか。
4.mod_vhost_aliasを使ってサーバのリロードをしない
mod_vhost_aliasは、バーチャルホストの設定をホスト単位で追加していくのではなく、ホスト名等を変数として設定を記述する事により、単一の設定で複数のバーチャルホストを扱う事ができます。また、これによって顧客ホスト追加時に、Apacheのリロードをする必要もありません。イメージとしては以下になります。
これによって、1.で後述すると述べた「顧客領域追加でサービス即時反映」が可能になります。共有ストレージ上に、新規顧客のホストを含むパスでドキュメントルートを作ってやれば、動的にサービスを開始する事ができます。また、顧客が自分のサブドメイン用のディレクトリを作ってやれば、それも動的にホスティング領域にする、というような応用もききます。
しかし、ここでもmod_vhost_aliasはsuEXECと併用ができないという悩ましい問題がありました。なぜかというと、Apacheのリロードをmod_vhost_aliasでしないようにする設定のまま、さらに、セキュリティを担保するためにsuEXECを使いたい、そのためにはCGIで動的コンテンツを実行しなければならない、という制約がありました。
しかし、suEXECは顧客ホスト毎に顧客ホストのuserやgroupを各バーチャルホスト設定に記述する必要があり、それをmod_vhost_aliasで動的に記述する事はできませんでした。その結果、Apacheのリロードも必要になり、バーチャルホストの設定の量も増え、設定の数が多過ぎてApacheがまともに起動しなくなる問題がありました。
そこで、皆さんお気づきの通り、それもmod_process_securityを利用する事で、動的に顧客ホストの権限を取得し、制御用スレッド上で権限分離を行うため、mod_vhost_aliasを使いつつCGIにおけるsuEXECでセキュリティを担保したかったような事を、DSOやFastCGI等の実行方式によらず実現する事が可能になりました。
これによって、共有ストレージに顧客ホスト名を含むディレクトリを作るだけで、セキュリティを担保しながら即座に顧客領域がホスティング領域として提供されます。さらに、DSOで高速にプログラムを実行できるのでうはうはです。
5.バーチャルホスト単位にcgroupでCPUやIOリソースを制限
しかし、バーチャルホストにはまだまだ問題があります。サーバプロセスをリスタートすると、そのサーバプロセスに属する全ての仮想ホストがサービス停止してしまいますよね。これは、4.によって解決しました。しかし、特定のホストに対するアクセス集中が他のホストに大きく影響を与えるという問題が以前残ります。場合によっては、あるホストへのアクセス集中によって、サーバが落ちてしまうかもしれません。
しかし、これも仮想ホスト単位でcgroupによる仮想的なリソース制御を行うことで解決できます。hoge.example.comに対しては、CPUを5%だけ利用可能にするといった設定や、IOは2Mbpsを上限にするというようなチューニングが可能になります。これによって、コンテナや仮想マシン等でわざわざリソースを分離することなく、バーチャルホスト上で容易かつ効率良くリソース制御可能になります。
この機能のベータ版に関しては、「mrubyでApacheのCPU割当てを制御できるモジュール作った」を参考にして下さい。これをさらに改良する予定です。
さらに、このリソースはApacheをリロードする事なく制御可能であるため、負荷のかかる顧客ホストに対しては、リアルタイムで制限をする事が可能であったり、契約によって顧客ホストが決めれらたリソースの範囲内で、複数のホスト間で自由にリソース制限を行うような、Webホスティングにおける新しいクラウドのようなサービスを実現する事が可能になります。
例えば、とあるホストがa.example.comとb.example.comとc.example.comを借りていた場合に、CPUの割合を、aは20%、bはあまりつかってないので5%、cは人気なので75%とか自分で振り分ける事も可能になります。
6.豊富なApacheのチューニング機能やツール
既存のチューニング機能だけでは、サーバダウンを免れないような状況であっても、以下の機能を導入する事でいかなる状況でも運用可能になると考えています。豊富な運用機能として、以下のようなチューニング機能を開発しました。
- mod_vlimit
- 仮想ホストに対する同時接続数で各顧客ホストのリクエスト可否を制御
- ファイルに対する同時接続数で各顧客ホストのリクエスト可否を制御
- 送信元IPに対する同時接続数で各顧客ホストのリクエスト可否を制御
- mod_rchecker
- リクエストの処理で使用したリソース量を計測
- リソース消費量を顧客側が利用する事も可能
- mod_request_dumper
- Apache内部で謎の動きをしている場合は内部情報をDump
- mod_lalimit
- ロードアベレージで各顧客ホストのリクエストを制御
- piotop
- プロセス単位でIOを調査
- qos-control
- プロトコルやIP等で帯域を制御
- resources_management_tools
- プロセス単位でCPUやIOを制御
7.足りない機能はmod_mrubyで実装
さらに上記のモジュール以外で細かく処理を制御したい場合は、mod_mrubyによってサーバをリロードする事なく、Rubyスクリプトを変更することで、Apache内部の動作をコントロールすることができます。例えば、あるホストのトラフィックが一定以下が一週間続いた場合は、ピザを配達するとか。
これによって、隙のない僕の考える最強の超高集積型Webホスティングシステム!が実現します。
最後に
どうでしょうか。以上が僕の考える、そして、僕が現状一人で実装する事のできる最強の超高集積型のWebホスティングシステムになります。セキュリティやパフォーマンス、そして、運用性の高さをできるだけ考慮して設計してみました。また、動的コンテンツに関しては実行方式として高速なものを扱えるように工夫しました。
AmazonEC2上にでも、一回これを実装してみようかと思っています。しかし、Webホスティングサービスとして提供するところまで持っていくためには、現状僕一人で足りないと思っています。例えば以下の項目が挙げられます。
- 契約するWebページ
- 契約から納品までの仕組み
- コンパネ
- ロードバランサ使う場合のSSLをどうするか
- 契約管理
このあたりが完成すると、超低コストな最強のWebホスティングサービスができそうです。PBA Standardみたいなのがオープンソースであればいいんだけどなぁ。
とりあえず、そーゆーのをふつーに実装したらディスクI/Oが追いつきませんので、
上ものだけでなくもっと下のレイヤーの考慮もした方がよろしいかと。
まあ、そのへんのことはawsに丸投げしてしまうというのもありといえばありなんでしょうけどね。
はい、ホスティングの共有ストレージにはIO関連で痛い目を何度も見ていますので、ストレージ設計が肝であることは良くわかっています。
そういったハードウェア含むリソース設計は、また別問題として今回は言及していません。また機会があれば記事にしてみようと思います。