Apache HTTP Serverで実現する高可用性 - mod_proxy: ProxySetと他の選択肢
ProxySet
ディレクティブは、Apache HTTP Server の mod_proxy
モジュールにおいて、プロキシの負荷分散構成を設定するために使用されます。特に、バックエンドサーバーのグループを定義し、それらへのリクエストの転送方法(バランスアルゴリズム、重み付け、健康状態のチェックなど)を制御する際に非常に重要です。
ProxySet とは何か?
主な用途
- セッション維持: 特定のバランサーメンバーに対して、クライアントからの特定のセッションを維持するように設定できます。
- 高可用性(ハイアベイラビリティ): バックエンドサーバーのいずれかがダウンした場合でも、他の利用可能なサーバーにリクエストを自動的に振り分けることで、サービスの継続性を確保します。
- 負荷分散(ロードバランシング): 複数のアプリケーションサーバーやバックエンドサービス間でトラフィックを均等に、または設定された重み付けに従って分散させ、単一のサーバーへの負荷集中を防ぎます。
構文と主な引数
基本的な構文は以下のようになります。
<Proxy balancer://balancer_name>
ProxySet option=value [option=value ...]
</Proxy>
または、ProxySet
を <Proxy>
ディレクティブの子ディレクティブとして記述することもできます。
ProxySet balancer://balancer_name option=value [option=value ...]
主なオプションと引数は以下の通りです。
-
noentireservername=On|Off
:- プロキシされたリクエストの
Host
ヘッダーに、元のリクエストのホスト名ではなく、プロキシ先(バックエンド)のホスト名をそのまま渡すかどうかを制御します。通常はOff
(元のホスト名を維持) が一般的です。
- プロキシされたリクエストの
-
failonstatus=status_code[,status_code...]
:- バックエンドサーバーから特定のHTTPステータスコードが返された場合、そのサーバーを一時的に「ダウン」とみなすように設定します。例えば、
failonstatus=500
と設定すると、500 Internal Server Error を返したサーバーは一時的に負荷分散の対象から外されます。
- バックエンドサーバーから特定のHTTPステータスコードが返された場合、そのサーバーを一時的に「ダウン」とみなすように設定します。例えば、
-
nofailover=On|Off
:stickysession
と組み合わせて使用されることが多く、セッションの固定先がダウンした場合でも、他のサーバーへのフェイルオーバーを許可するかどうかを制御します。On
にするとフェイルオーバーしません。
-
timeout=seconds
:- バックエンドサーバーへの接続タイムアウトを設定します。指定された秒数以内に応答がない場合、そのサーバーはダウンしているとみなされる可能性があります。
-
lbmethod=byrequests|bytraffic|bybusyness|heartbeat
:- 負荷分散アルゴリズムを指定します。
byrequests
(デフォルト): リクエスト数に基づいて負荷分散を行います。bytraffic
: 送受信されたデータ量に基づいて負荷分散を行います。bybusyness
: 各ワーカーのビジー状態(現在処理中のリクエスト数)に基づいて負荷分散を行います。最も負荷が低いサーバーにリクエストを転送します。heartbeat
: ApacheのHeartbeat機能を有効にし、バックエンドサーバーの健康状態と負荷情報を利用して負荷分散を行います。
- 負荷分散アルゴリズムを指定します。
-
stickysession=cookie_name|JSESSIONID
:- セッションを維持するためのメカニズムを指定します。例えば、
JSESSIONID
のようなセッションIDを含むCookie名を設定することで、同じクライアントからの後続のリクエストが常に同じバックエンドサーバーにルーティングされるようにします。これは、セッションを共有しない複数のアプリケーションサーバーでステートフルなアプリケーションを運用する際に非常に重要です。 NOFAILOVER
を追加すると、指定されたメンバーがダウンしてもセッションがフェイルオーバーしないように設定できます(通常は推奨されません)。
- セッションを維持するためのメカニズムを指定します。例えば、
設定例
一般的な設定例を見てみましょう。
# mod_proxy と mod_proxy_balancer を有効にする
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
<VirtualHost *:80>
ServerName example.com
<Proxy balancer://mycluster>
# セッションID "JSESSIONID" を使ってセッションを維持
# セッション固定されたサーバーがダウンしてもフェイルオーバーしない
ProxySet stickysession=JSESSIONID nofailover=On
# リクエスト数に基づいて負荷分散 (デフォルトなので省略可能)
ProxySet lbmethod=byrequests
# バックエンドサーバーへの接続タイムアウトを5秒に設定
ProxySet timeout=5
# メンバーの追加
BalancerMember http://backend1.example.com:8080 route=node1 loadfactor=10
BalancerMember http://backend2.example.com:8080 route=node2 loadfactor=10
BalancerMember http://backend3.example.com:8080 route=node3 loadfactor=5
</Proxy>
# /app のリクエストをバランサーに転送
ProxyPass /app balancer://mycluster/app
ProxyPassReverse /app balancer://mycluster/app
# バランサーマネージャーへのアクセスを許可 (デバッグ用)
<Location /balancer-manager>
SetHandler balancer-manager
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>
</VirtualHost>
解説:
<Location /balancer-manager>
は、バランサーの状態を確認・管理するためのWebインターフェース(balancer-manager
)へのアクセスを設定しています。これはデバッグや監視に役立ちます。ProxyPassReverse
は、バックエンドサーバーからのリダイレクト応答のURLをApacheが書き換えるために必要です。ProxyPass /app balancer://mycluster/app
により、/app
へのアクセスをmycluster
バランサーに転送します。BalancerMember
ディレクティブで、個々のバックエンドサーバー(メンバー)を定義しています。route
はstickysession
と連携し、セッション固定のためのサーバー識別子として使用されます。loadfactor
は、そのサーバーに割り当てる相対的な重み付けを示します。timeout=5
は、バックエンドサーバーへの接続タイムアウトを5秒に設定しています。lbmethod=byrequests
は、リクエスト数に基づいて負荷分散を行うことを明示しています(デフォルト値)。nofailover=On
により、セッション固定されたサーバーがダウンしても、他のサーバーへのフェイルオーバーを行いません。これは、セッション情報が特定のサーバーにしか存在しない場合に重要ですが、可用性の観点からは注意が必要です。stickysession=JSESSIONID
により、JSESSIONID というCookie名を使ってセッションを維持するように設定しています。balancer://mycluster
という名前のバランサーグループを定義しています。
注意点
- 設定の複雑さ: 高度な負荷分散や特定のセッション要件がある場合、設定は複雑になることがあります。Apacheの公式ドキュメントや関連リソースを参照して、詳細な設定オプションを理解することが重要です。
- 健康状態のチェック:
mod_proxy
は、バックエンドサーバーの死活監視を自動的に行い、ダウンしたサーバーを負荷分散の対象から一時的に外します。 - セッションの共有:
stickysession
を使用しない場合や、特定のサーバーにセッションを固定しない場合は、バックエンドのアプリケーションサーバー間でセッション情報を共有する仕組み(例:データベース、Redisなど)が必要になることがあります。 mod_proxy_balancer
の有効化:ProxySet
を使用するためには、mod_proxy_balancer
モジュールが有効になっている必要があります。
モジュールが有効になっていない (AH00534: httpd: Configuration error: No ProxySet directive found.)
エラーの症状:
Apache を起動または再起動しようとすると、ProxySet
ディレクティブが見つからないというエラーが表示される。
原因:
ProxySet
は mod_proxy_balancer
モジュールの一部であり、このモジュールが有効になっていない場合に発生します。また、mod_proxy
および mod_proxy_http
も必要です。
トラブルシューティング:
- 必要なモジュールが有効になっているか確認する:
httpd.conf
またはmods-available
ディレクトリ内の設定ファイルで、以下のLoadModule
ディレクティブがコメントアウトされていないことを確認します。LoadModule proxy_module modules/mod_proxy.so LoadModule proxy_http_module modules/mod_proxy_http.so LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
- Ubuntu/Debian 系の場合:
sudo a2enmod proxy sudo a2enmod proxy_http sudo a2enmod proxy_balancer sudo systemctl restart apache2 # または sudo service apache2 restart
- CentOS/RHEL 系の場合:
sudo systemctl restart httpd # または sudo service httpd restart # 必要に応じてモジュールファイルを編集し、LoadModule を有効にする
- 設定ファイルの構文チェック:
- 変更後、必ず構文チェックを行います。
apachectl configtest # または httpd -t
- 変更後、必ず構文チェックを行います。
バックエンドサーバーへの接続タイムアウト (Proxy Error: The timeout specified has expired (70007).)
エラーの症状:
クライアントからのリクエストがタイムアウトし、Apache のエラーログに The timeout specified has expired
や AH00957: HTTP: attempt to connect to ... failed
といったメッセージが表示される。
原因:
ProxySet
またはProxyPass
で設定されたタイムアウト値が短すぎる。- ネットワークの問題(ファイアウォール、ルーティングなど)により、Apache からバックエンドサーバーに接続できない。
- バックエンドサーバーがダウンしている、応答が遅い、または過負荷状態である。
トラブルシューティング:
- バックエンドサーバーの稼働状況を確認する:
- 直接バックエンドサーバーにアクセスして、アプリケーションが正常に動作しているか確認します。
- バックエンドサーバーのログを確認し、エラーがないか、パフォーマンスの問題がないかを確認します。
- ネットワーク接続を確認する:
- Apache サーバーからバックエンドサーバーへ
ping
やcurl
コマンドでアクセスし、ネットワーク接続性を確認します。# 例: curl -v http://backend.example.com:8080/
- 途中のファイアウォール(OSのファイアウォール、AWSのセキュリティグループなど)でポートがブロックされていないか確認します。
- Apache サーバーからバックエンドサーバーへ
- タイムアウト値を調整する:
ProxySet
ディレクティブ内でtimeout
オプションを増やします。<Proxy balancer://mycluster> ProxySet timeout=30 # 例: 30秒に延長 # ... </Proxy>
- または、
ProxyPass
ディレクティブに直接timeout
を指定することもできます。ProxyPass /app balancer://mycluster/app timeout=30
ProxyTimeout
ディレクティブの確認:- グローバルまたは仮想ホストレベルで
ProxyTimeout
ディレクティブが設定されている場合、その値も影響します。ProxyTimeout 60 # 全てのプロキシ接続に適用されるデフォルトのタイムアウト
- グローバルまたは仮想ホストレベルで
セッションが維持されない、またはセッションが失われる (stickysession の問題)
エラーの症状:
セッション情報が維持されず、ユーザーが頻繁にログインを求められたり、ショッピングカートの内容が失われたりする。Apache のエラーログに BALANCER_ROUTE_CHANGED
関連のメッセージが出力されることがある(LogLevel を Debug に設定した場合)。
原因:
jvmRoute
の設定がバックエンド(Tomcatなど)とApacheで一致していない。- バックエンドサーバーがダウンし、セッションが他のサーバーにフェイルオーバーされた(
nofailover=Off
の場合)。 - バックエンドアプリケーションのセッションIDがApacheの
stickysession
設定と一致していない。 - バックエンドアプリケーションがセッションIDを適切に発行していない。
ProxySet stickysession
の設定が正しくない。
トラブルシューティング:
stickysession
オプションの確認:ProxySet stickysession=CookieName
が正しく設定されているか確認します。CookieName
は、バックエンドアプリケーションがセッションIDを格納するために使用するCookie名(例:JSESSIONID
)と完全に一致している必要があります。
- バックエンドアプリケーションのセッションID発行を確認する:
- 開発者ツール(ブラウザのF12)でネットワークタブを開き、クライアントとバックエンドの間でやり取りされるHTTPヘッダーを確認します。特に、アプリケーションがセッションIDを返すCookie名が
ProxySet stickysession
で指定した名前と一致しているか確認します。 - Tomcat の場合、
server.xml
の<Engine>
または<Host>
要素にjvmRoute
属性が設定されていることを確認します。<Engine name="Catalina" defaultHost="localhost" jvmRoute="node1">
- Apache の
BalancerMember
のroute
オプションとjvmRoute
の値が一致しているか確認します。BalancerMember http://backend1.example.com:8080 route=node1
- 開発者ツール(ブラウザのF12)でネットワークタブを開き、クライアントとバックエンドの間でやり取りされるHTTPヘッダーを確認します。特に、アプリケーションがセッションIDを返すCookie名が
nofailover
オプションの動作を理解する:ProxySet stickysession=JSESSIONID nofailover=On
の場合、セッション固定されたバックエンドがダウンすると、そのセッションは他のサーバーにフェイルオーバーされず、エラーになります。これは意図的な動作ですが、可用性にとっては問題となる場合があります。nofailover=Off
(または省略)の場合、固定先のサーバーがダウンすると、他のサーバーにフェイルオーバーを試みます。この場合、セッションデータが共有されていないと、ユーザーはセッションを失う可能性があります。
- Apache のログレベルを Debug に設定する:
LogLevel debug
を設定することで、mod_proxy_balancer
の詳細な動作(どのリクエストがどのワーカーに送られたか、セッション固定の動作など)をログで追跡できます。LogLevel debug proxy_balancer:debug
バックエンドサーバーがエラーを返す (failonstatus の問題)
エラーの症状: バックエンドサーバーが特定のHTTPステータスコード(例: 500 Internal Server Error)を返しているにもかかわらず、Apache がそのサーバーをダウンと認識せず、リクエストを送り続けてしまう。
原因:
- バックエンドサーバーが返すエラーページが、期待するHTTPステータスコードではなく、常に200 OK を返している。
ProxySet failonstatus
オプションが設定されていない、または間違ったステータスコードが指定されている。
トラブルシューティング:
failonstatus
オプションを確認する:- バックエンドサーバーがエラー時に返すHTTPステータスコードを正確に把握し、
ProxySet failonstatus=500,503
のように設定します。<Proxy balancer://mycluster> ProxySet failonstatus=500,503 # 500または503エラーでワーカーを一時停止 # ... </Proxy>
- バックエンドサーバーがエラー時に返すHTTPステータスコードを正確に把握し、
- バックエンドサーバーの応答を確認する:
curl -I http://backend.example.com:8080/error_path
のようにヘッダーのみを取得し、実際に返されるHTTPステータスコードを確認します。- 一部のアプリケーションフレームワークは、エラー発生時でもカスタムエラーページを200 OKで返すことがあります。その場合は、アプリケーション側の設定を変更するか、Apache側で別の検出方法(例えば、特定のレスポンスボディの文字列をチェックする)を検討する必要がありますが、これは
mod_proxy
の範囲外で、mod_rewrite
などと組み合わせる必要があるかもしれません。
ProxyPass / ProxyPassReverse と ProxySet の競合や順序の問題
エラーの症状: リクエストが意図したバックエンドにルーティングされない、またはリダイレクトが正しく処理されない。
原因:
- 複数の
ProxyPass
ディレクティブの順序が間違っている(より具体的なパスを先に記述する必要がある)。 ProxyPass
やProxyPassReverse
のパスとProxySet
で定義されたバランサーのパスの間に矛盾がある。
トラブルシューティング:
- パスの一致を確認する:
ProxyPass /app balancer://mycluster/app
とProxySet
で定義されたバランサーの名前が一致していることを確認します。ProxyPass
とProxyPassReverse
のパスが一致しているか確認します。末尾のスラッシュの有無も重要です。
ただし、# 正しい例: 末尾スラッシュを揃える ProxyPass /app/ balancer://mycluster/app/ ProxyPassReverse /app/ balancer://mycluster/app/ # または末尾スラッシュなしで揃える ProxyPass /app balancer://mycluster/app ProxyPassReverse /app balancer://mycluster/app
ProxyPass /app balancer://mycluster/app
は、/app
へのアクセスをbalancer://mycluster/app
にマッピングします。クライアントが/app/page.html
をリクエストすると、バックエンドにはhttp://backend_host:port/app/page.html
が送られます。
ProxyPass
ディレクティブの順序:- Apache は設定ファイルを上から順に処理します。より具体的な
ProxyPass
ルールを先に記述し、より一般的なルールを後から記述するようにします。# NG: /api が先に評価されてしまう ProxyPass / balancer://general_cluster/ ProxyPass /api balancer://api_cluster/ # OK: /api が先に評価される ProxyPass /api balancer://api_cluster/ ProxyPass / balancer://general_cluster/
- Apache は設定ファイルを上から順に処理します。より具体的な
SELinux による接続拒否 (CentOS/RHEL)
エラーの症状:
Apache のエラーログに (13)Permission denied: AH00957: HTTP: attempt to connect to ... failed.
のようなメッセージが表示されるが、ネットワーク接続自体は問題ないように見える。
原因: SELinux が Apache プロセスから外部ネットワークへの接続をブロックしているため。
トラブルシューティング:
- SELinux の状態を確認する:
sestatus
- HTTPD がネットワーク接続を許可するように設定する:
sudo /usr/sbin/setsebool -P httpd_can_network_connect 1
-P
オプションは、設定を永続化します。
SSL/TLS 証明書関連の問題 (HTTPS プロキシ)
エラーの症状: HTTPS のバックエンドサーバーにプロキシする際にエラーが発生する。特に、自己署名証明書や信頼できない証明書を使用している場合に顕著。
原因: Apache がバックエンドサーバーのSSL証明書を信頼できないため。
トラブルシューティング:
- 必要なモジュールの有効化:
mod_ssl
とmod_proxy_http
が有効になっていることを確認します。
- SSLProxyEngine の有効化:
- HTTPS バックエンドに接続する場合、Apache の仮想ホスト設定で
SSLProxyEngine on
を設定する必要があります。<VirtualHost *:443> ServerName example.com SSLEngine on SSLCertificateFile /path/to/your/certificate.crt SSLCertificateKeyFile /path/to/your/private.key SSLProxyEngine on # 開発/テスト環境でのみ使用: バックエンド証明書の検証をスキップ # SSLProxyVerify none # SSLProxyCheckPeerCN off # SSLProxyCheckPeerName off <Proxy balancer://mycluster> # ... </Proxy> ProxyPass /app balancer://mycluster/app ProxyPassReverse /app balancer://mycluster/app </VirtualHost>
- 本番環境では、バックエンドサーバーの証明書が信頼できる認証局によって署名されていることを確認し、検証をスキップする設定は避けるべきです。信頼されたCA証明書をApacheにロードする方法を検討します。
- HTTPS バックエンドに接続する場合、Apache の仮想ホスト設定で
- 証明書パスの確認:
SSLCertificateFile
とSSLCertificateKeyFile
のパスが正しいことを確認します。
一般的なトラブルシューティングのヒント
- 設定ファイルをシンプルにする: 複雑な設定はエラーの温床となります。段階的に設定を追加し、その都度テストを行うことで、問題の特定が容易になります。
balancer-manager
を活用する:mod_proxy_balancer
の状態をリアルタイムで確認できる便利なツールです。
ブラウザから<Location /balancer-manager> SetHandler balancer-manager Order deny,allow Deny from all Allow from 127.0.0.1 # アクセスを許可するIPアドレス </Location>
http://your-apache-server/balancer-manager
にアクセスして、ワーカーの状態(Up/Down、ロードファクター、エラー回数など)を確認できます。- バックエンドサーバーのログも確認する: Apache 側だけでなく、プロキシ先のアプリケーションサーバーのログも確認することで、問題の切り分けに役立ちます。
apachectl configtest
を常に実行する: 設定変更後、Apache を再起動する前に構文エラーがないか確認します。- Apache エラーログを確認する: 最も重要な情報源です。
LogLevel
をwarn
またはinfo
、問題が解決しない場合はdebug
に設定して、詳細な情報を取得します。- ログの場所は通常
/var/log/apache2/error.log
(Debian/Ubuntu) または/var/log/httpd/error_log
(CentOS/RHEL) です。
- ログの場所は通常
ProxySet
ディレクティブは、特に mod_proxy_balancer
と組み合わせて使用され、複数のバックエンドサーバー(ワーカー)を管理し、リクエストを分散させる方法を定義します。
前提条件:
以下のモジュールが有効になっていることを確認してください(httpd.conf
で LoadModule
ディレクティブのコメントを解除するか、適切なコマンドで有効にします)。
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so # byrequests 方式を使用する場合
LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so # bytraffic 方式を使用する場合
LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so # bybusyness 方式を使用する場合
# 必要に応じて、AJPプロトコルを使用する場合は mod_proxy_ajp.so など
# WebSockets を使用する場合は mod_proxy_wstunnel.so
例1: シンプルな負荷分散 (byrequests)
最も基本的な負荷分散の例です。クライアントからのリクエストを、定義されたバックエンドサーバー間で均等に(リクエスト数に基づいて)分散します。
# httpd.conf または仮想ホスト設定ファイル (例: /etc/httpd/conf.d/vhosts.conf または /etc/apache2/sites-available/your_site.conf)
<VirtualHost *:80>
ServerName yourdomain.com
ServerAdmin [email protected]
# バランサーグループの定義
# ここで 'mycluster' という名前のバランサーを作成します
<Proxy balancer://mycluster>
# 各バックエンドサーバー (BalancerMember) を定義
# ここでは 'node1' と 'node2' の2つのバックエンドサーバーを設定しています
BalancerMember http://192.168.1.101:8080 route=node1
BalancerMember http://192.168.1.102:8080 route=node2
# 負荷分散アルゴリズムをリクエスト数に基づいて設定 (デフォルトなので明示しなくても同じ動作)
ProxySet lbmethod=byrequests
# バックエンドへの接続タイムアウトを5秒に設定
ProxySet timeout=5
</Proxy>
# /app へのリクエストを mycluster バランサーに転送
ProxyPass /app/ balancer://mycluster/app/
# バックエンドからのリダイレクトURLを書き換える
ProxyPassReverse /app/ balancer://mycluster/app/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
解説:
ProxyPassReverse /app/ balancer://mycluster/app/
: バックエンドサーバーからのリダイレクト応答(Location
ヘッダーなど)に含まれるURLを、クライアントがアクセスできるプロキシのURLに書き換えます。ProxyPass /app/ balancer://mycluster/app/
:yourdomain.com/app/
へのすべてのリクエストをmycluster
バランサーに転送し、バックエンドサーバーの/app/
パスにマッピングします。ProxySet timeout=5
: Apacheがバックエンドサーバーへの接続を試行する際のタイムアウトを5秒に設定します。これを超えると、そのバックエンドは一時的にダウンしていると見なされる可能性があります。ProxySet lbmethod=byrequests
: ロードバランシングの方法を「リクエスト数に基づく」に設定します。これはデフォルトの動作ですが、明示的に指定することで意図が明確になります。BalancerMember http://192.168.1.101:8080 route=node1
:mycluster
グループにhttp://192.168.1.101:8080
をワーカーとして追加します。route=node1
はセッション固定に使用される識別子です(この例ではセッション固定は設定されていませんが、将来的な拡張のために含めています)。<Proxy balancer://mycluster>
:mycluster
という名前のバランサーグループを定義するコンテナです。
例2: セッション維持 (Sticky Session) と重み付け負荷分散
特定のユーザーセッションを常に同じバックエンドサーバーにルーティングしたい場合に stickysession
を使用します。また、各バックエンドサーバーの処理能力に応じて重み付けを行う loadfactor
も組み合わせます。
<VirtualHost *:80>
ServerName yourdomain.com
<Proxy balancer://mycluster_sticky>
BalancerMember http://192.168.1.101:8080 route=node1 loadfactor=10
BalancerMember http://192.168.1.102:8080 route=node2 loadfactor=10
BalancerMember http://192.168.1.103:8080 route=node3 loadfactor=5 # このサーバーは他の半分
# JSESSIONID という名前のCookieを使ってセッションを維持
# セッションが固定されたワーカーがダウンしてもフェイルオーバーしない
ProxySet stickysession=JSESSIONID nofailover=On
# 負荷分散アルゴリズムをビジー状態に基づいて設定 (最もアイドルなサーバーに転送)
ProxySet lbmethod=bybusyness
# バックエンドへの接続タイムアウトを10秒に設定
ProxySet timeout=10
# 500 (Internal Server Error) または 503 (Service Unavailable) を返した場合、ワーカーを一時停止
ProxySet failonstatus=500,503
</Proxy>
ProxyPass /app/ balancer://mycluster_sticky/app/
ProxyPassReverse /app/ balancer://mycluster_sticky/app/
# バランサーマネージャーへのアクセスを許可 (監視・管理用)
<Location /balancer-manager>
SetHandler balancer-manager
Order deny,allow
Deny from all
Allow from 127.0.0.1 192.168.1.0/24 # アクセスを許可するIPアドレス
</Location>
</VirtualHost>
解説:
<Location /balancer-manager>
: バランサーのリアルタイムの状態を表示し、動的に設定を変更できるbalancer-manager
インターフェースを有効にします。アクセス制限を適切に行うことが重要です。ProxySet failonstatus=500,503
: バックエンドサーバーがHTTPステータスコード 500 または 503 を返した場合、そのワーカーを一時的に「ダウン」と見なし、負荷分散の対象から外します。これにより、クライアントへのエラー応答を減らし、サービスの健全性を維持できます。ProxySet lbmethod=bybusyness
: 各ワーカーの現在の処理中リクエスト数(ビジー状態)に基づいて負荷分散を行います。最も負荷の低いワーカーにリクエストを転送しようとします。ProxySet stickysession=JSESSIONID nofailover=On
:JSESSIONID
というCookie名を使用してセッションを固定します。TomcatなどのJavaアプリケーションサーバーでよく使用されるセッションIDです。nofailover=On
は、特定のワーカーにセッションが固定されている場合、そのワーカーがダウンしても他のワーカーへのフェイルオーバーを行わないことを意味します。セッション情報がサーバー間で共有されていない場合に、セッションの整合性を保つために使用されます。ただし、これを使用すると、固定先がダウンした場合にユーザーはサービスを利用できなくなります。
BalancerMember ... loadfactor=X
:loadfactor
は、そのワーカーに割り当てる相対的な重み付けです。node1
とnode2
はnode3
の2倍のリクエストを受け取ることになります(lbmethod
に応じて動作が変わります)。
例3: HTTPS バックエンドへのプロキシ (SSLProxyEngine)
Apache が HTTPS を使用してバックエンドサーバーに接続する場合の設定です。
<VirtualHost *:443>
ServerName secureapp.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/secureapp.com.crt
SSLCertificateKeyFile /etc/ssl/private/secureapp.com.key
# 必要に応じてSSLCertificateChainFileも設定
# HTTPSバックエンドへのプロキシを有効にする
SSLProxyEngine on
# バックエンド証明書の検証に関する設定 (本番では通常、証明書検証を推奨)
# 開発/テスト環境でのみ: バックエンド証明書の検証をスキップ
# SSLProxyVerify none
# SSLProxyCheckPeerCN off
# SSLProxyCheckPeerName off
<Proxy balancer://secure_cluster>
BalancerMember https://192.168.1.201:8443 route=secure_node1
BalancerMember https://192.168.1.202:8443 route=secure_node2
ProxySet lbmethod=byrequests
ProxySet timeout=15
</Proxy>
ProxyPass / secure_app/ balancer://secure_cluster/secure_app/
ProxyPassReverse / secure_app/ balancer://secure_cluster/secure_app/
ErrorLog ${APACHE_LOG_DIR}/ssl_error.log
CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
</VirtualHost>
解説:
SSLProxyVerify none
,SSLProxyCheckPeerCN off
,SSLProxyCheckPeerName off
: これらの設定は、ApacheがバックエンドサーバーのSSL証明書の検証を行わないようにします。これはセキュリティリスクを伴うため、本番環境では強く非推奨です。 本番環境では、バックエンドサーバーが信頼できる認証局によって署名された証明書を使用し、ApacheにそのCA証明書を信頼させる設定(SSLProxyCACertificateFile
やSSLProxyCACertificatePath
など)を行うべきです。SSLProxyEngine on
: これが最も重要で、ApacheがバックエンドサーバーとSSL/TLSハンドシェイクを行うことを許可します。SSLEngine on
,SSLCertificateFile
,SSLCertificateKeyFile
: クライアントとApache間のHTTPS接続のためのSSL設定です。
例4: WebSockets プロキシ
WebSockets を使用するアプリケーションをプロキシする場合、mod_proxy_wstunnel
モジュールと upgrade=websocket
オプションを使用します。
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
<VirtualHost *:80>
ServerName websocketapp.com
<Proxy balancer://websocket_cluster>
BalancerMember ws://192.168.1.301:8080/websocket route=wsnode1
BalancerMember ws://192.168.1.302:8080/websocket route=wsnode2
ProxySet lbmethod=byrequests
</Proxy>
# WebSocket プロキシのための特別な設定
# Upgrade ヘッダーを処理し、WebSocket 接続をトンネルする
ProxyPass /ws/ balancer://websocket_cluster/ upgrade=websocket
ProxyPassReverse /ws/ balancer://websocket_cluster/
ErrorLog ${APACHE_LOG_DIR}/ws_error.log
CustomLog ${APACHE_LOG_DIR}/ws_access.log combined
</VirtualHost>
解説:
ProxyPass /ws/ balancer://websocket_cluster/ upgrade=websocket
:upgrade=websocket
オプションが重要です。これにより、Apache はクライアントからのUpgrade: websocket
ヘッダーを検知し、バックエンドへの接続をWebSocketプロトコルにアップグレードします。- パスの末尾にスラッシュを付けるかどうかは、アプリケーションのパス構造に合わせる必要があります。
BalancerMember ws://...
: WebSocketプロトコルを使用する場合、ws://
(またはwss://
for secure WebSockets) スキームを指定します。LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
: WebSocketプロキシのためにこのモジュールが必要です。
例5: ヘッダーの操作とカスタマイズ
mod_headers
と組み合わせて、Apache がバックエンドに転送するリクエストヘッダーや、クライアントに返すレスポンスヘッダーを操作できます。
LoadModule headers_module modules/mod_headers.so
<VirtualHost *:80>
ServerName myapp.com
<Proxy balancer://myapp_cluster>
BalancerMember http://192.168.1.401:8080 route=appnode1
BalancerMember http://192.168.1.402:8080 route=appnode2
ProxySet lbmethod=byrequests
</Proxy>
# クライアントの元のIPアドレスをX-Forwarded-Forヘッダーに追加
ProxyPreserveHost On
RequestHeader set X-Forwarded-Proto "http" # HTTPの場合
RequestHeader set X-Forwarded-Port "80" # HTTPの場合
# HTTPSの場合: RequestHeader set X-Forwarded-Proto "https"
# HTTPSの場合: RequestHeader set X-Forwarded-Port "443"
# Apacheによって設定されたセッション固定ルートをクライアントに返すCookieに追加
# env=BALANCER_ROUTE_CHANGED が重要: ルートが変更された場合にのみCookieを設定
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; Path=/" env=BALANCER_ROUTE_CHANGED
ProxyPass / balancer://myapp_cluster/
ProxyPassReverse / balancer://myapp_cluster/
</VirtualHost>
解説:
Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; Path=/" env=BALANCER_ROUTE_CHANGED
:- これは、バックエンドアプリケーションがセッションCookieを発行しない場合に、Apache自身がセッション固定用のCookieを発行する一般的なパターンです。
%{BALANCER_WORKER_ROUTE}e
は、Apacheが現在リクエストをルーティングしているワーカーのroute
値から取得される環境変数です。env=BALANCER_ROUTE_CHANGED
は、セッション固定のルーティングが変更された場合にのみこのヘッダー(Cookie)を追加するように条件を付けます。
RequestHeader set X-Forwarded-Proto "http"
など: ロードバランサーの後ろに配置されたアプリケーションが、元のプロトコル(HTTPかHTTPSか)やポートを知るために必要なヘッダーを追加します。これは、アプリケーションが正しいリダイレクトURLを生成するのに役立ちます。ProxyPreserveHost On
: クライアントから受け取ったHost
ヘッダーをそのままバックエンドに転送します。
Nginx (エンジンエックス)
Nginx は、Webサーバーとしてだけでなく、高性能なリバースプロキシおよびロードバランサーとしても非常に広く利用されています。イベント駆動型アーキテクチャを採用しており、高負荷時でも低いメモリ使用量で多数の同時接続を処理できるのが特徴です。
特徴と利点:
- Kubernetesとの親和性: KubernetesのIngress Controllerとして広く利用されています。
- WebSocketsサポート: WebSocketプロキシも容易に設定できます。
- レイヤー7の機能: HTTPヘッダーに基づいたルーティング、SSL終端、キャッシュなどの高度な機能を提供します。
- シンプルな設定: Apacheに比べて設定ファイルが簡潔で分かりやすいことが多いです。
- 高パフォーマンス: 特に静的ファイルの配信や大量の同時接続処理に優れています。
設定例 (Nginx):
# /etc/nginx/nginx.conf または sites-available/your_site.conf
http {
upstream backend_servers {
# ロードバランシング方式 (デフォルトは round-robin)
# least_conn; # 最もアクティブな接続数が少ないサーバーに転送
# ip_hash; # クライアントのIPアドレスに基づいてセッション固定
server 192.168.1.101:8080;
server 192.168.1.102:8080;
server 192.168.1.103:8080;
}
server {
listen 80;
server_name yourdomain.com;
location /app/ {
# upstream で定義されたバックエンドサーバーグループにリクエストを転送
proxy_pass http://backend_servers/app/;
# 実際のクライアントIPアドレスをバックエンドに伝える
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocketのアップグレードを許可
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
# セッション固定用のCookieを扱う例 (Nginxのupstream_hashを使用する場合)
# upstream backend_servers {
# hash $cookie_JSESSIONID consistent;
# server 192.168.1.101:8080;
# server 192.168.1.102:8080;
# }
}
}
}
HAProxy (エイチエープロキシ)
HAProxy は、高可用性と高性能な負荷分散に特化したオープンソースのプロキシサーバーです。TCP/HTTPアプリケーションの両方に対応し、非常に多くのロードバランシングアルゴリズムと詳細なヘルスチェック機能を提供します。
特徴と利点:
- SSL終端: フロントエンドでのSSL終端が可能です。
- スティッキーセッション: さまざまな方法でセッション固定をサポートします。
- ACL (Access Control List): URL、ヘッダー、Cookieなどに基づいて高度なルーティングルールを設定できます。
- 詳細なヘルスチェック: バックエンドサーバーの健全性を細かく監視し、問題のあるサーバーを自動的にプールから除外できます。
- 多様なロードバランシングアルゴリズム: ラウンドロビン、最小接続数、ソースIPハッシュなど、多数のアルゴリズムをサポートします。
- 非常に高いパフォーマンス: 特に大量の同時接続を処理することに特化しています。
設定例 (HAProxy):
# /etc/haproxy/haproxy.cfg
global
log /dev/log daemon
maxconn 20000
chroot /var/lib/haproxy
user haproxy
group haproxy
daemon
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor # X-Forwarded-For ヘッダーを追加
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
# フロントエンド (外部からのリクエストを受け付ける部分)
frontend http_front
bind *:80
acl is_app path_beg /app
use_backend app_backends if is_app
default_backend default_webserver
# バックエンド (アプリケーションサーバー群)
backend app_backends
balance roundrobin # ロードバランシングアルゴリズム (ラウンドロビン)
# balance leastconn # または最小接続数
# セッション固定 (JSESSIONID クッキーに基づいて)
# `app_backends` はアプリケーションサーバーが生成する `JSESSIONID` の末尾に付加される `jvmRoute` と一致させる
# `route` は BalancerMember の `route` に相当する
cookie JSESSIONID insert indirect nocache # クッキー名を指定し、挿入モードに
option httplog
option httpchk GET /health # /health エンドポイントへのHTTPヘルスチェック
server app1 192.168.1.101:8080 cookie node1 check
server app2 192.168.1.102:8080 cookie node2 check
server app3 192.168.1.103:8080 cookie node3 check backup # app3 はバックアップサーバー
backend default_webserver
server web1 192.168.1.100:80 check
クラウドプロバイダのロードバランサー (AWS ALB/NLB, GCP Cloud Load Balancing, Azure Load Balancer/Application Gateway)
クラウド環境でアプリケーションを運用している場合、各クラウドプロバイダが提供するマネージドロードバランサーサービスが最も一般的な代替手段です。これらは高度な可用性、スケーラビリティ、セキュリティ機能を備えています。
特徴と利点:
- 統合された監視・ロギング: クラウドの監視ツールとシームレスに連携します。
- 多様なロードバランシングアルゴリズム: クラウドプロバイダによって異なりますが、様々なアルゴリズムをサポートします。
- セキュリティ: SSL/TLS終端、WAF (Web Application Firewall)、DDoS保護などの機能が統合されています。
- 高可用性: 複数のアベイラビリティゾーン/リージョンにまたがる構成で、単一障害点を排除します。
- 自動スケーリング: トラフィック量に応じて自動的にスケールイン/アウトします。
- フルマネージド: インフラの構築・運用・保守がクラウドプロバイダによって行われるため、運用負荷が大幅に軽減されます。
例 (AWS Application Load Balancer - ALB):
ALBはレイヤー7(HTTP/HTTPS)のロードバランサーで、パスベースのルーティング、ホストベースのルーティング、セッション固定、SSL終端、WebSocketsなどをサポートします。
- 設定方法: AWSマネジメントコンソール、AWS CLI、CloudFormation、Terraformなどを利用して設定します。コード例は複雑になるため省略しますが、設定の概念はApacheの
ProxySet
と似ています。- ターゲットグループ: バックエンドサーバー(EC2インスタンス、コンテナなど)をグループ化し、ヘルスチェックを設定します。
- リスナー: クライアントからの接続を待機するポートとプロトコル(例: HTTPS 443)を設定します。
- ルール: リスナーにアタッチされ、リクエストのパスやホスト名に基づいてターゲットグループにトラフィックをルーティングするルールを定義します。セッション維持(スティッキーセッション)もここで設定します。
例 (AWS Network Load Balancer - NLB):
NLBはレイヤー4(TCP/UDP)のロードバランサーで、非常に高いスループットと低レイテンシが特徴です。IPアドレスとポートに基づいてトラフィックを転送します。
- 設定方法: ALBと同様に、ターゲットグループとリスナーを設定しますが、機能はよりシンプルです。SSL終端も可能ですが、HTTPヘッダーベースのルーティングはできません。
- API Gateway (例: Nginx Plus, Kong, Apigee): APIに特化したプロキシで、負荷分散だけでなく、認証、認可、レート制限、モニタリング、API変換などの機能を提供します。
- Traefik Proxy: コンテナやマイクロサービス環境に特化したエッジルーター・ロードバランサーです。Docker、Kubernetesなどのオーケストレーターと密接に連携し、動的なサービスディスカバリやルーティングが可能です。
- Caddy: 自動HTTPS機能を備えたモダンなWebサーバーで、リバースプロキシ機能もシンプルに設定できます。小規模なプロジェクトや開発環境で手軽に利用できます。
- Envoy Proxy: クラウドネイティブ環境で広く利用される高機能なプロキシです。サービスメッシュのデータプレーンとしても機能し、高度なルーティング、トラフィック管理、可観測性を提供します。
代替手段 | 最適なユースケース | 利点 | 考慮事項 |
---|---|---|---|
Nginx | 汎用的なWebサーバー、リバースプロキシ、中規模の負荷分散 | 高性能、設定の簡潔さ、多様な機能 | 大規模なエンタープライズ機能は限定的 |
HAProxy | 高可用性、高パフォーマンスなレイヤー4/7負荷分散 | 高いパフォーマンス、豊富なロードバランシング機能、詳細なヘルスチェック | 設定がやや複雑、Webサーバー機能はない |
クラウドLB | クラウドネイティブな環境、大規模、高可用性 | フルマネージド、自動スケーリング、高いセキュリティ | クラウドベンダーへのロックイン、コスト |
Envoy/Traefik | マイクロサービス、コンテナ環境、サービスメッシュ | 動的ルーティング、高度なトラフィック制御、可観測性 | 設定が複雑、学習曲線、主にコンテナ環境向け |
Caddy | 小規模プロジェクト、開発環境、シンプルなHTTPSプロキシ | 自動HTTPS、設定の容易さ | 大規模な負荷分散には不向き |