RitoLabo

Apacheロードバランサで負荷分散。冗長化構成を開発環境でも。~負荷分散と冗長化の基礎を添えて~

  • 公開:
  • カテゴリ: linux Apache
  • タグ: Linux,CentOS,Apache,httpd,2.4,2.2,LoadBalancer,Redundancy

ロードバランサはAWSなどクラウドサービス出現のおかげでかなり気軽に使えるようになりました。とはいえ、アプリケーションの開発時に冗長化構成下の動作確認を気軽に行いたいと思う場合もあったりします。

今回は、負荷分散や冗長化の基本をさらいつつ、Apacheを使って冗長化構成時のロードバランシングを行います。

アジェンダ
  1. 開発環境
  2. 負荷分散とロードバランサ
    1. 負荷分散方式
    2. ロードバランサ導入時の注意点
  3. ApacheのProxyと負荷分散
    1. フォワードProxy
    2. リバースProxy
  4. Apacheで負荷分散
    1. 負荷分散
    2. 冗長化
    3. 冗長化とセッション
  5. 負荷分散に必要な拡張モジュール
  6. URLでの割り振り
  7. リクエスト回数やトラフィック量での割り振り
  8. スティッキーセッションの設定
  9. Load Balancet Manager

開発環境

今回の開発環境は以下の通りです。

  • Linux CentOS 7
  • Apache 2.4

仮想環境でWEBサーバを3機用意しています。

  • 192.168.80.10 ロードバランシング用
  • 192.168.80.11 WEBサーバ1
  • 192.168.80.12 WEBサーバ2

負荷分散とロードバランサ

処理やトラフィックなどWEBサーバ1台では処理しきれない場合に、サーバを複数台用意して負荷分散装置「ロードバランサ」を用いて各サーバへ振り分けを行う事で、サーバ1台にかかる負荷を分散させる事が出来ます。

負荷分散方式

ロードバランサで用いられる負荷分散方式は以下の通りです。

ラウンドロビン方式
順番にサーバを割り振っていく
重み付けラウンドロビン方式
定義した割合でサーバを割り振っていく
最速応答時間方式
応答が最も早いサーバへ割り振る
最小コネクション方式
接続コネクション数が最も少ないサーバへ割り振る
最小トラフィック方式
一定時間で転送されたデータ量が最も少ないサーバへ割り振る
CPU負荷分散方式
CPUの負荷が最も低いサーバへ割り振る
セッション維持方式
IPやCookieなどを基にサーバへ割り振る

ロードバランサ導入時の注意点

  • システム構成が複雑化する
  • ログがサーバ台数分散らばる

ApacheのProxyと負荷分散

Apacheでの負荷分散はProxy機能を応用する事で実現しています。

フォワードProxy

  • キャッシュされたデータをWEBサーバの代わりに返す
  • 外部ネットワークから断絶されているイントラネット内のクライアントが外部のサイトを参照したりできる

リバースProxy

  • ロードバランシングはこっち
  • インターネット側からのリクエストを中継し、WEBサーバへ割り振る
  • コンテンツの分散やWEBサーバ構成を外部から隠蔽する時などで使われる
  • リバースProxy機能に負荷分散や冗長性を装備する事でロードバランサとして使用できる

ApacheでProxy機能を使うには、拡張モジュール「mod_proxy」が必要になります。

mod_proxy
Proxy機能を可能にする
mod_proxy_balancer
ロードバランス機能を可能にする
mod_proxy_ftp
FTPプロトコルをProxyできるようにする
mod_proxy_http
HTTPプロトコルをProxyできるようにする
mod_proxy_ajp
AJPプロトコルをProxyできるようにする
mod_proxy_connect
トンネリングのおためのCONNECTメソッドをProxyできるようにする

Apacheで負荷分散

負荷分散機能は拡張モジュール「mod_proxy_balancer」で実現します。HTTP/サーブレットコンテナ/AJP13/FTPのバランシングが可能です。Apache2.2以降での負荷分散、冗長化機能は以下の通りです。

負荷分散

  • リクエスト回数を基に割り振る
  • トラフィック量を基に割り振る
  • セッション変数を利用する場合、セッション情報を保持しているサーバに接続して割り振る
  • 設定を動的に変更できるマネージャを利用できる
  • マネージャを利用する事で各バックエンドサーバの状態を確認できる
  • マネージャはWEBブラウザから利用できる

冗長化

  • httpdの再起動不要でバックエンドサーバをオンライン/オフラインできる
  • バックエンドサーバのダウンを自動で検知し分散対象から外す
  • バックエンドサーバが障害から復帰した場合は自動で分散対象にする
  • バックエンドサーバのオンライン/オフラインを変更するマネージャが使える
  • マネージャを利用する事で各バックエンドサーバの状態を確認できる
  • マネージャはWEBブラウザから利用できる

冗長化とセッション

PHPではアプリケーションでログインでのユーザ認証などでセッションを使う事があります。

IPや固有IDを埋め込んだCookie情報を基に、サーバ側でクライアントを識別しクライアントごとの変数をサーバ側で保持するようにすることで、WEBブラウザが画面遷移してもログインなどの情報を引き継げます。その時にサーバ側で保存されるのが「セッション変数」です。

しかし冗長化構成下では、リクエストが振り分けられるので、認証を行ったサーバではないところへ割り振られた場合、認証情報を引き継ぐ事ができずWEBブラウザとHTTPサーバとでは永続的な処理を行う事ができません。

ロードバランサを導入して冗長化構成にする場合、サーバ間でセッション情報を共有する必要があります。

Apache Tomcatのようなアプリケーションサーバではメモリ・ディスク・RDBMSにセッション情報を保存する「セッションレプリケーション」が提供されていますが、これに頼らなくてもApache2.2以降ではクライアントからのリクエストを、セッション変数が保存されているサーバに固定して割り振ることができます。これを「スティッキーセッション方式」と呼び、セッション変数を永続化して利用できます。

負荷分散に必要な拡張モジュール

Proxy関連モジュールが有効になっているかを確認します

# httpd -M | grep proxy
proxy_module (shared)
proxy_ajp_module (shared)
proxy_balancer_module (shared)
proxy_connect_module (shared)
proxy_express_module (shared)
proxy_fcgi_module (shared)
proxy_fdpass_module (shared)
proxy_ftp_module (shared)
proxy_http_module (shared)
proxy_scgi_module (shared)
proxy_wstunnel_module (shared)

最低でも以下がインストールされている必要があります。

  • proxy_module(mod_proxy)
  • proxy_balancer_module(mod_proxy_balancer)

URLでの割り振り

以下のルールでバックエンドサーバへの割り振りを設定します。

  • http://192.168.80.10/serv1 へのアクセスで 192.168.80.11 へ割り振り
  • http://192.168.80.10/serv2 へのアクセスで 192.168.80.12 へ割り振り

confファイルを設定します。

<IfModule mod_proxy.c>
ProxyRequests off

ProxyPass /serv1 http://192.168.80.11
ProxyPassReverse /serv1 http://192.168.80.11

ProxyPass /serv2 http://192.168.80.12
ProxyPassReverse /serv1 http://192.168.80.12
</IfModule>

ProxyRequestsディレクティブをoffにする事でフォワードProxy機能を無効化し、リバースProxyを有効化しています。

ProxyPass/ProxyPassReverseディレクティブでURLのマッピングを行っています。リモートサーバをローカルサーバの名前空間にマップしています。

httpdを再起動し、ブラウザからアクセスしてみます。

URLでの振り分け結果

URLによってサーバが割り振られている事が確認できました。

リクエスト回数やトラフィック量での割り振り

vim /etc/httpd/conf/httpd.conf
<IfModule mod_proxy.c>
ProxyRequests off

ProxyPass / balancer://samplecluster lbmethod=byrequests timeout=1 maxattempts=2

<Proxy balancer://samplecluster>
BalancerMember http://192.168.80.11 loadfactor=3
BalancerMember http://192.168.80.12 loadfactor=2
</Proxy>
</IfModule>

ProxyPass には以下の順で設定します。

  • バランシング対象のパス
  • balancer://任意の名前
  • lbmethod=負荷分散アルゴリズム
  • timeout=接続タイムアウト(秒)
  • maxattempts=接続試行回数

負荷分散アルゴリズムは以下の2つで設定します。

  • リクエスト回数「byrequests
  • トラフィック量「bytraffic

また、loadfactor を設定する事で、振り分けの比率を設定することが出来ます。(設定値は1~100)

maxattemptsに関して、バックエンドサーバがダウンした場合は自動で振り分け対象から外れます(フェイルオーバー)が、それを判断する為の接続試行回数になります。

ちなみに、振り分け対象から外れた時には、ロードバランサ側のerror_logに以下のようにロギングされます。

[Sun Jul 01 07:28:09.431996 2018] [proxy:error] [pid 4644] (111)Connection refused: AH00957: HTTP: attempt to connect to 192.168.80.12:80 (192.168.80.12) failed
[Sun Jul 01 07:28:09.432040 2018] [proxy:error] [pid 4644] AH00959: ap_proxy_connect_backend disabling worker for (192.168.80.12) for 60s

尚、これらの項目は全てが必ず設定しなくてはいけないものではなく、以下に関しては未設定ならばデフォルト値が設定されます。

  • timeout=1
  • maxattempts=1
  • loadfactor=1

httpd再起動の後、ブラウザからアクセスしてみます。

トラフィックでの振り分け結果

振り分けが行われている事が確認できました。

スティッキーセッションの設定

スティッキーセッションを設定しセッション情報を維持するには以下のように設定します。

vim /etc/httpd/conf/httpd.conf
ProxyPass /sample balancer://samplecluster lbmethod=byrequests timeout=1 maxattempts=1 nofailover=On stickysession=PHPSESSIONID 

PHPの場合、stickysession=PHPSESSIONID を追加します。

尚、バックエンドサーバ側でセッションレプリケーション機能を持たない場合は nofailover=On を追加します。

Load Balancet Manager

Apacheには負荷分散や冗長化機能のためのマネージャがあります。マネージャはWEBブラウザから利用でき、設定変更・バックエンドサーバの状態確認・バックエンドサーバの切り離しなどが行えます。

マネージャで変更した内容はすぐに反映され、サーバを再起動する必要もありませんが、変更した内容はconfファイルに反映されないので、再起動を行うと元に戻る点に注意が必要です。

マネージャの利用には拡張モジュール「mod_status」が必要です。

# httpd -M | grep status
status_module (shared)
vim /etc/httpd/conf/httpd.conf
<Location /balancer-manager>
SetHandler balancer-manager

Order Deny,Allow
Deny from all
Allow from 127.0.0.1 192.168.80.
</Location>

httpdの再起動後、ブラウザから確認します。

LoadBalancetManager

このように、ブラウザから設定を変更することができます。

まとめ

以上で作業は完了です。PHPでは認証機能などセッション管理を必要とするアプリケーションの開発も多く、確認環境まで上げないと冗長化構成下でのテストが行えないなど微妙にやりにくい部分がありますが、こうしてApacheを使って一時的にでもローカル環境で冗長化構成を構築してしまえば気軽にテストが行えるので、是非試してみてください。