Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Webアプリの基礎とさまざまな実行環境を理解する#2(社内勉強会)

BPS社内勉強会のmorimorihogeさんのスライド「Webアプリの基礎とさまざまな実行環境を理解する」の第2回です。当初2分割の予定を3分割に変更しました。

2. Webサーバの役割

Webサーバの役割を一言で言うと「HTTPリクエストにHTTPレスポンスを返すソフトウェア」です。

一般には以下のWebサーバが知られています。

サーバ 説明
Nginx Apacheに比べて軽く、大量のリクエストを捌けるということでここ数年でシェアを伸ばしているWebサーバ
Apache 長い歴史を持つ世の中のWebサーバの実質的なスタンダード
IIS Windows Serverに付属のWebサーバ。ASP.NET等のMicrosoftプロダクトと多分相性がいいはず

この他にも特定機能に特化したさまざまなWebサーバがあります。なおNginxは「エンジンエックス」と読みます(公式FAQ参照)。

「特定機能に特化したWebサーバ」の例としてはリバースプロキシがあります。Nginxはリバースプロキシとしても使えますし、逆にプロキシサーバとして有名なSquidも実はWebサーバの一種ということになります。

WebサーバでサポートするHTTPバージョンはソフトウェアとバージョンによって異なりますが、当該ソフトでサポートするHTTPバージョンの仕様上「必須(MUST)」とされている機能は必ずそのWebサーバに実装されています。これができていないWebサーバはそのプロトコルバージョンに対応していると謳ってはいけないことになっているからです。

3. Webサービスの代表的な形態

Webサービスにはさまざまな形態があり、以下の最初の4つの基本構成が代表的です。複雑なWebサービスも、何らかの形でこれらの基本構成を元にしています。

morimorihoge注)

なお、ここで話す「Webサーバー」が意味する機能的な役割は、アプリケーションサーバーとしてのプログラム実行機能は含まず、一般的なファイル配信やリバースプロキシ機能程度までを処理する範囲までとしています。

※細かい定義をすると色々あれ?と思うところがあると思いますが、説明のための簡略化だということで目を瞑って下さい>詳しい人

主要な4つの構成について以下で詳しく説明します。「Webサーバ単独系」「Webサーバ+CGI系」「アプリケーションサーバ系」の3つ(I〜III)と、合わせ技としてRailsに代表される「Webサーバ+アプリケーションサーバ」(IV: 次回)の順になります。

I. Webサーバ単独系

静的なコンテンツを配信するだけの最も単純な形式のサービスですが、パフォーマンス面とセキュリティ面で有利なので、要件に合えば現在でも非常に有用な形態です

コーポレートサイトや静的な情報系サイト、あるいはコンテンツをFTPやSCPなど手動だけで更新しているサイトもこれに該当します。

メリット

  • サーバ処理が軽い: サーバーの役割はファイルを返すだけで良いので、CPU/メモリ負荷は小さい(ネットワーク帯域は必要)
  • キャッシュが効く: 同じコンテンツへのリクエストであれば、どのクライアントにも毎回同じレスポンスを返せるのでキャッシュヒットしやすい
  • セキュリティ上のリスクが非常に低い: サーバ側でアプリケーションロジックを動かす必要がないため、XSSOSコマンドインジェクションなどの代表的なWebサーバーに対する攻撃が無効(リスクがあるとすれば古いファイルの消し忘れぐらいか)

デメリット

  • 動的な要素を自前で用意できない: Google Formなどの外部サービスを埋め込めば申込みフォームぐらいは作れるが、自由度は低め
  • 毎回FTPなどで人力更新が必要: ちょっとしたコンテンツ更新の度に手間がかかってしまう(ブログシステムのようなやり方はできない)。※ビルド・アップロード自動化などを組み合わせればいちおう自動化は可能だが、システム運用は複雑になる

実際のサービス例

使いどころ

  • 静的なファイルを不特定多数に配信したいとき
  • とにかく安く配信したいとき
  • サーバサイドセキュリティ対策そのものから解放されたいとき
morimorihoge注)

なお、昨今サーバーサイドエンジニア不要説を唱える過激派フロントエンジニア界隈では、動的処理は全て外部サービスを利用して実装し、自前でホスティングするWebサーバーは完全に静的なコンテンツを配信するWebサーバーとする構成も出てきています。
ブラウザ側でできることが高機能化してきた昨今ではまだまだ増えていく界隈だと思いますので、コンテンツを静的配信する=完全に静的なサービスとは限らない(JavaScript+外部サービスを使って動的に見える)ことは頭に置いておくと良いでしょう。

II. Webサーバ+CGI系

CGI(Common Gateway Inteerface)という言葉そのものはあまり見かけなくなりましたが、CGI系Webサーバは実は今も昔も動的なWebサービスの主流です。というのも、世界のWebサイトの1/4を占めるとまで言われるWordPressもこれに該当するからです。

CGIはWebサーバがプログラムを実行した結果を返すしくみで、ざっくり「PHPやPerlのスクリプトファイルを置いたら動くやつ」ぐらいに思っていればだいたい間違いではありません。ただし、本来の意味でのCGIを使っているものは少数で、今現在の多くのWebサーバでは言語別のサーバモジュールを使っています(パフォーマンス上有利なため)。

この手のWebサーバには上述のApacheやNginxが一般に使われますが、たまにIISなども見ないことはないです。

CGI方式は動的Webページの基本であり主流なので、Web開発者はまずはここから触ることが多いのではないでしょうか。

メリット

  • 導入が簡単: 既に動かしているWebサーバにモジュールを組み込むだけで良いため、設定ファイルの更新やパッケージの追加だけで導入できる
  • 実績もノウハウも多い: 歴史が長く、使われているサービスも多い
  • プログラムの更新が簡単: ファイルを置くだけで更新できる(さくらの共有サーバ等の共有型Webサーバーでも運用できる)

デメリット

  • セキュリティ上注意が必要: 呼び出されたプログラムがWebサーバの権限で実行されるため、セキュリティ・権限管理が甘いと見られてはいけないファイルが漏洩する可能性がある
  • プログラムが常駐しない: Webサーバからのプログラム呼び出しはあくまでステートレスであり、リクエストのたびにアプリケーションプログラムが終了する(※モジュール型の場合には実際には準備されたWorkerを使い回すケースがありますが、実行するプログラムの内部コンテキスト上はリクエストの都度破棄されると考えた方が良い)

実際のサービス例

  • レンタルサーバ(さくらのレンタルサーバなど多数あります)

こうしたレンタルサーバでは、1台のWebサーバを複数ユーザーで共有する「共有型サービス」が一般的です。共有型サービスでは特定の操作だけが許可されているのが普通なので、sshで接続はできてもroot権限の必要な操作は行なえません。
また、サーバー側や利用者側のファイルなどの権限設定が適切に行われていないと、同居している他のユーザーにデータを抜かれる可能性もゼロではありません(適当に権限を777(誰でも読み書き可能)とかにしていると今でもたまに見る)。

使いどころ

  • PHPやPerlなどのスクリプト言語アプリを手軽に使いたいとき
  • インフラエンジニアの手を借りれるアテがないとき
  • OSやソフトウェアのアップグレードをやりたくないとき

レンタルサーバはWebサーバを専有できないので、その分さまざまな制限が生じます。一般的な使い方ならほぼ問題ありませんが、特殊な使い方はできないこともあるので注意しましょう。

morimorihoge注)

世の中の多くのサービスはこの形式で動作しています。WordPressその他のメジャーな「サーバーに置いたら動く」系のソフトウェアは大抵この形式で動作するので、Webサイトの実数上のシェアもかなりの割合を占めていると思います。
また、もちろん自前でサーバーを立てる場合もPHPやPerlのプログラムではこの形式を選ぶことがほとんどですので、業務アプリケーションでは使えないということも全くないです。

一方、レンタルサーバーなどを利用する場合には「インフラはお任せ」と思いがちですが、実はレンタルサーバー業者によって細かい設定(例えばphp.iniなど)はかなり異なりますので、レンタルサーバー間でプログラムを移設する場合なんかにはそれまで「おまかせ」だと思っていたものにも気を配らないといけないことがあります。
例えば、さくらのレンタルサーバーではSNIを使ってマルチサイトTLS対応した場合にX-Sakura-Forwarded-Forというさくらのレンタルサーバー独自ヘッダに本来のホスト名が入ります。こういった落とし穴は探せば解決策は見つかりますが、落とし穴がある可能性は考慮しておかないとトラブル対処でスケジュールに影響が出たりするので注意ですね。

参考: X-Sakura-Forwarded-Forの検索結果

III. アプリケーションサーバ系

汎用的なWebサーバソフトを使わず、Webアプリケーション専用のサーバプログラムが直接リクエストに応答します。このタイプはアプリケーションサーバが何もかも引き受けるので、ApacheやNginxなどのWebサーバを持ちません

Java serverで構築されるサービスはたいていこれに該当します。Tomcatなどのサービスが有名です。

今なら、Railsのミドルウェアとして使われているRackを単体で使ったWebアプリもこれに相当します(Rackは単体でもWebサービスを構築できます)。ちなみにHerokuではRackアプリもホスティングできます。
※が、一般的には次回IVで紹介するようにRailsはNginxと組み合わせて使われることが多いです。

メリット

  • TCPレベルで通信を細かく制御できる: クライアントからのHTTPリクエストをアプリケーションサーバが直接受信して処理できる
    • 例: 動画配信でレート制御するといったことも可能(Webサーバがあると邪魔になる)
  • サーバプロセスがステートを持てる: HTTPはステートレスだが、アプリケーションサーバプロセスは起動後常駐するため、プロセスのメモリ状態を複数のリクエスト間で共有できる
    • ステートを持つことで、メモリ上のキャッシュなどのリソースを有効利用できる
  • 高速: アプリケーションで必要なデータがメモリに載った状態でリクエストを受けられる
    • CGIは呼ばれるまで起動しないし、終わったらメモリを解放してしまうので遅い

デメリット

  • アプリケーションサーバが肥大化する: あらゆるHTTP通信を処理するため、アプリケーションサーバがWebサーバと同じ機能を持たないといけない
    • SSL/TLSに対応するにはその機能をアプリケーションサーバが実装しなければならない
    • Apacheなどから移行する場合に設定ファイルを再利用できず、アプリケーションに合わせてやり直さなければならない
  • メモリ効率が悪い: 常駐するサーバはリクエストがなくてもメモリを消費してしまう
  • 静的ファイルの効率が悪い: 本来プログラム処理が不要な静的ファイルもアプリケーションサーバが扱わなければならないので、高速でないとサイト全体が重くなる
    • サーバが遅くなると静的な利用規約まで読めなくなったりとか
morimorihoge注)

現代では、ほとんどのアプリケーションサーバー型のシステムは次回説明するIVの形式を利用していると思います。ただ、例えばRailsアプリケーションをローカル環境でrails sしてlocalhost:3000にアクセスしている時なんかはこの形式になります。

また、メリットにも書いたように細かいレート制御を行いたい場合(例えばTCPの生SocketのAPIを叩きたい)にはこの形式を用いる必要があります。WebSocketやUDPを用いた高い応答性やレート制御が求められるアプリケーション開発の場合には、間にWebサーバが入ってしまうとリクエストがバッファリングされて困るというケースはあるので、アーキテクチャの一つとして理解はしておくと良いと思います。


関連記事

Rails: Puma/Unicorn/Passengerの効率を最大化する設定(翻訳)

【社内勉強会】バージョン管理の重要性とGitの運用について


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。