高負荷でも安定したサービスを提供するためのリバースプロキシ
KLab Advent Calendar 2011 「DSAS for Social を支える技術」の8日目です。
前回は php のプロセス数を絞ることのメリットを解説しました。
プロセス数を絞るには FPM を使うなどの方法もありますが、 DSAS for Social では php は Apache + mod_php を使っていて、 それにリバースプロキシを組み合わせて利用しています。 今日はこのリバースプロキシの役割を説明して行きます。
以降、リバースプロキシのことを単にプロキシと呼びます。
プロキシを使う理由
そもそも、なぜプロキシを使うのかを説明しておきます。
5秒ルール
ケータイ向けのソーシャルアプリでは、ユーザーからのリクエストは 一旦プラットフォームのサーバーを経由して、アプリを提供している Webサーバーに到達します。
このとき、アプリ側のレスポンスがあまりに遅いとプラットフォーム側の リソースを浪費してしまうので、プラットフォーム側は5秒でアプリへの アクセスをタイムアウトさせ、タイムアウトが頻発すると自動的に そのアプリを停止状態にしてしまいます。
なので、何らかの理由でレスポンスを5秒以内に返せない場合は、 強制的にタイムアウトしてレスポンスを返す必要があります。 そのためにプロキシサーバーのタイムアウトを利用しています。
並列接続への対応
前回 php のプロセス数を絞る設定のメリットを紹介しましたが、 Apache + mod_php で動いているサーバーの並列数を単純に絞って しまうと、たとえば通信速度が遅いクライアントとの通信などが あったときに並列数をすぐに使いきってしまいます。
並列数を多めに設定したプロキシと並列数が少ないphp用Webサーバーの 2段構成にすれば、phpのレスポンスはクライアントに転送される前に プロキシ上のバッファに載るので、クライアントへの転送の完了を待たずに phpが次のリクエストの処理を開始できます。
なぜプロキシに Apache を使うのか
いま人気の nginx などを使わない理由は、単に使う理由がないからです。 DSAS for Social では負荷分散は LVS で行っており、プロキシはアプリ用の Apache と同じ Web サーバー上で動いています。つまり、プロキシが 捌かなければいけないリクエスト数は、負荷分散後の各Webサーバーへの リクエスト数だけになります。
nginx はその速度やC10K対応で人気があると思うのですが、この構成では 速度面のメリットは php が遅いために全く活かせません。 Comet などの大量並列接続を必要とするアプリにはそもそも php は使い物に ならないので、 php のアプリを動かす Apache の前に置く プロキシは Apache でも全く問題がありません。
プロキシ設定で抑えておきたいポイント
静的ファイルはプロキシ側で配信する
静的ファイルをphpと同じApacheで配信した場合、その内容が一旦 プロキシのバッファに乗ってからクライアントに転送されるので、 メモリを大量に消費してしまいますし、大量のメモリコピーや データのプロセス間転送が発生するので静的ファイルの配信速度が 低下してしまいます。
そして、静的ファイルのサイズがプロキシのバッファとソケットバッファの 合計を超えた場合は、phpを動かしているApacheのレスポンスが待たされ、 phpが次のリクエストを処理できなくなってしまいます。
アクセスを捌ききれなくなったらすぐにエラーを返す
4000リクエスト/sec しか捌けないのに 4100リクエスト/sec のペースでリクエストが来た時、単にリクエストをphpの動いている Apache に転送してタイムアウトを設定するだけだと、ほとんどの リクエストがタイムアウトになってしまい、サイトがほぼ落ちている 状態になってしまいます。
これは、プロキシがタイムアウトさせたリクエストでも、phpは処理を 続け、CPUやMySQLなどの処理能力を使用し続けているからです。
秒間4100リクエストのうち捌ける4000リクエストは正常に処理し、 それを超える100リクエストだけをエラーにするには、プロキシ側が スロットルの役割を果たして、過負荷になったときに php が動いている Apache にリクエストを転送しないでエラーを返す必要があります。
時間が無くなってしまったので、今日はこのへんにして、 実際の設定方法は次回に回します。