2013年06月07日

一般的な Web Application というのはロードバランサ、Webサーバ、アプリケーションサーバという HTTP を喋るサーバで構成されていると思います。
ロードバランサは高級なハードウェアからソフトウェア(lvs, httpd, etc..)で作るものまで色々ありますね。
アプリケーションサーバでは各種言語に合わせた実装でデーモンが常駐してるでしょう。これはいわゆる普通の Web サーバよりは単純なコンテンツを返す性能が低いです。

そんなわけで動的なアプリケーションサーバが有る構成では js や css や画像など静的なファイルは Apache や nginx などの専用の Web サーバでサービスして、動的なリクエストだけバックエンドのアプリケーションを返す構成を取ります。
構成としては

構成A
  +---------------+
  | reverse proxy |
  +---------------+
          /\
         /  \
        /    \
       /      \
+--------+  +---------+ 
| static |  | dynamyc |
+--------+  +---------+ 
とか
構成B
+------------------------------------+
| static contents with reverse proxy | (Web Server)
+------------------------------------+
                  |
         +------------------+ 
         | dynamyc contents | (application server)
         +------------------+ 
のような二通りの構成が取れると思いますが、このエントリでは後者のシンプルな方で話を進めます。
そしてアプリケーションの種類によっては Web サーバとアプリケーションサーバを一つのインスタンスに同居させる事もあるでしょう。

そして冗長性を考えると、それぞれのパーツが1台づつで運用されてるとかマジありえないので普通のサービスの最小セットは以下のようになります。

構成C
+----------+ +----------+
| balancer | | balancer |
+----------+ +----------+
     |     \  /   |
     |      \/    |
     |      /\    |
     |     /  \   |
+----------+ +----------+
|   web    | |    web   | (Web サーバ)
|    |     | |     |    |
|   app    | |    app   | (アプリケーションサーバ)
+----------+ +----------+

app が落ちたらアウト

上の構成の場合だと app が落ちたら前段の web が 502 を返してしまって、折角 balancer が良い感じにバランシングしてくれてるのに可用性が下がってしまいます。

注意深く balancer をセットアップしていれば、 app のダウンを検知して故障のある app を抱えてる web をはずす事は出来ますが, 検知に時間はかかるし構成にかかる設定が複雑になります。

特にアプリケーションサーバの再起動を伴う作業の時に一瞬止まったりする可能性のあるアプリケーションサーバを使った場合には、再起動のたびに 502 を連発してしまってダウンタイム多発になります。
(この問題は近代的な環境である Unicorn や Server::Sterter などを使う事によりホットデプロイで対応可能になっています。)

app が落ちても平気にする

この問題を解決する手段としては web と app の間で更で以下のようにしてバランシングしてあげるという事です。

構成D
+----------+ +----------+
| balancer | | balancer |
+----------+ +----------+
     |     \  /   |
     |      \/    |
     |      /\    |
     |     /  \   |
+-----------+ +-------------+
|   web (A) | |    web (B)  | (Web サーバ)
+-----------+ +-------------+
     |     \  /   |
     |      \/    |
     |      /\    |
     |     /  \   |
+-----------+ +-------------+
|   app (A) | |    app (B)  | (アプリケーションサーバ) 
+-----------+ +-------------+

# web (A) と app (A) ならびに web (B) と app (B) はそれぞれ同一インスタンス
web サーバが Apache だったり nginx だったりする時は、良い感じにバランシングしながら後ろの web サーバに reverse proxy する方法があるので捗ります。

ただしこの手法でもバランシングの設定が必要になるので、サーバクラスタに web(C) app(C) を追加して balancer で web(C) を追加して満足して httpd.conf などに app(C) を追加し忘れて分散してるつもりが負荷が偏る悲しい問題も発生し得ます。

httpd.conf にちゃんと追加さえすれば、同じサービスの全部の設定は一度書けばかってにバラまかれて良い感じに再起動されるので balancer 側で頑張るよりはだいぶ柔軟な運用ができるがそれは後ほど。

特殊な環境の場合

たとえば JSON API しかサービスしないよ!っていうケースの場合は静的コンテンツをサービスする為の Web サーバが実質不要になるため balancer と app だけの以下の構成を取るかもしれません。

構成E
+----------+ +----------+
| balancer | | balancer |
+----------+ +----------+
     |     \  /   |
     |      \/    |
     |      /\    |
     |     /  \   |
+-----------+ +-------------+
|   app (A) | |    app (B)  | (アプリケーションサーバ) 
+-----------+ +-------------+

# web (A) と app (A) ならびに web (B) と app (B) はそれぞれ同一インスタンス
これの構成だと致命的な問題としてアプリケーションサーバの根っこの設定を変えたいとかで、ホットデプロイ不可能な再起動したい時に balancer 側を相殺してバランシングからはずさないといけないときに面倒いのです。最初から考慮した運用してれば大丈夫なのかもですが。

まとめ

むりやりまとめると構成Dがいちばん安定するという結論に今なってます。

メリットとしては

  • balancer が特殊なハードやソフトウェアで構成されてる時でも、ゆるふわな人がある程度柔軟な運用が出来る
  • ゆるふわな人がアプリケーションサーバのメンテを気楽にできる
  • アプリケーションサーバが死んでも問題起きないので可用性あがる
  • 古き良きアプリケーションサーバ使ってるときの deploy がある程度ゆるふわに出来る
デメリットとしては
  • static contents が無い場合に、一個余分なサーバを挟む事になるのでパフォーマンスが下がる
  • うっかり web サーバ側のバランシング設定書き忘れて悲しくなる
な感じだとおもいます。

ぼくみたいなしろうとが書いてると机飛んで来そうでこわいけどがんばってかきました><

Posted by Yappo at 2013年06月07日 19:34 | TrackBack | tech
Comments
Post a comment









Remember personal info?






コメントを投稿する前に↓の場所にnospamと入力してください。