Apache HTTP サーバ バージョン 2.2

Apache > HTTP サーバ > ドキュメンテーション > バージョン 2.2 > モジュール

# Apache モジュール mod_proxy_balancer

翻訳済み言語: en | ja

説明: | 負荷分散のための `mod_proxy` 拡張
ステータス: | Extension
モジュール識別子: | proxy_balancer_module
ソースファイル: | mod_proxy_balancer.c
互換性: | Apache 2.1 以降で使用可能

### 概要

本モジュールには `mod_proxy` が必要です。 本モジュールは `HTTP` と `FTP` と `AJP13` プロトコルのロードバランス機能を持っています。

ですから、 ロードバランスを有効にする場合 `mod_proxy` と `mod_proxy_balancer` がサーバに組み込まれて いなければいけません。

### 警告

安全なサーバにするまでプロキシ機能は有効にしないでください。 オープンプロキシサーバはあなた自身のネットワークにとっても、 インターネット全体にとっても危険です。

### ディレクティブ

このモジュールにディレクティブはありません。

### トピック

- ロードバランサのスケジューラのアルゴリズム
- ロードバランサのスティッキネス
- ロードバランサの設定例
- Request Counting アルゴリズム
- Weighted Traffic Counting アルゴリズム
- Pending Request Counting アルゴリズム
- エクスポートされる環境変数
- バランサマネージャのサポートを有効にする
- ロードバランサのスティッキネスの詳細
- ロードバランサのスティッキネスのトラブルシューティング

### 参照

- `mod_proxy`

## ロードバランサのスケジューラのアルゴリズム

現時点では 3 種類のロードバランサスケジューラアルゴリズムから選べます。 リクエスト回数によるもの (訳注: Request Counting) 、トラフィック量によるもの (訳注: Weighted Traffic Counting) と、処理中リクエスト数によるもの (訳注: Pending Request Counting) とがあります。バランサの設定 `lbmethod` 値で、どれを使うか指定します。 詳細は `ProxyPass` ディレクティブを 参照してください。

## ロードバランサのスティッキネス

バランサはスティッキネスをサポートします。リクエストがあるバックエンドに プロキシされた時、続く同じユーザからのリクエストは、すべてその同じバックエンドに プロキシされるべきです。多くのロードバランサはこの機能をクライアントの IP アドレスとバックエンドの対応表を持つことで実現します。 この方法はクライアントにもバックエンドにも透過に動作しますが、 次に挙げるいくつかの問題があります。 もしクライアント自身がプロキシの背後にいる場合、負荷分散が不均一になります。 もし動的な IP アドレスを持つクライアントのアドレスがセッション中に変わると スティッキネスは期待どおりに動作しません。 もし対応表があふれると、スティッキネスが失われます。

`mod_proxy_balancer` はスティッキネスを 2 種類の別手法をもとに実装しています。クッキーと URL エンコーディングのふたつです。 クッキーはバックエンドもしくは Apache Web サーバ自身により提供されます。 URL エンコーディングは通常バックエンドにより行われます。

## ロードバランサの設定例

技術的な詳細に入る前に例を示します。以下は、2 台のバックエンドサーバを ロードバランスするための `mod_proxy_balancer` の使い方の一例です:

`<Proxy balancer://mycluster>
BalancerMember http://192.168.1.50:80
BalancerMember http://192.168.1.51:80
</Proxy>
ProxyPass /test balancer://mycluster`

別の例として、`mod_headers` を使ってスティッキネス を実現するロードバランサの設定例を示します。バックエンドのサーバが 適切なセッションクッキーをセットしなくても動作します。

`Header add Set-Cookie "ROUTEID=.%{BALANCER_WORKER_ROUTE}e; path=/" env=BALANCER_ROUTE_CHANGED
<Proxy balancer://mycluster>
BalancerMember http://192.168.1.50:80 route=1
BalancerMember http://192.168.1.51:80 route=2
ProxySet stickysession=ROUTEID
</Proxy>
ProxyPass /test balancer://mycluster`

## Request Counting アルゴリズム

`lbmethod=byrequests` で有効になります。 このスケジューラの背景にある考え方は、様々なワーカーがそれぞれ、 設定されている分担リクエスト数をきちんと受け取れるように、 リクエストを扱うという考え方です。次のように動作します:

lbfactor は、どの程度ワーカーに仕事を振るか つまりワーカーのクオータを指します。この値は "分担" 量を表す正規化された値です。

lbstatus は、ワーカーのクオータを満たすために どのぐらい急ぎで働かなければならないかを指します。

ワーカーはロードバランサのメンバで、通常は、 サポートされるプロトコルのうちの一つを提供しているリモートホストです。

まず個々のワーカーにワーカークオータを割り振り、どのワーカーが最も急ぎで 働かなければならないか (lbstatus が最大のもの) を調べます。 次に仕事をするようにこのワーカーを選択し、選択したワーカーの lbstatus から全ワーカーに割り振ったクオータの合計を引きます。ですから、lbstatus の総量は 結果的に変化しません(*)し、リクエストは期待通りに分散されます。

あるワーカーが無効になっても、他のものは正常にスケジュールされ続けます。

    for each worker in workers
        worker lbstatus += worker lbfactor
        total factor    += worker lbfactor
        if worker lbstatus > candidate lbstatus
            candidate = worker

    candidate lbstatus -= total factor

バランサを次のように設定した場合:

worker | a | b | c | d
--- | --- | --- | --- | ---
lbfactor | 25 | 25 | 25 | 25
lbstatus | 0 | 0 | 0 | 0

そして b が無効になった場合、次のようなスケジュールが 行われます。

worker | a | b | c | d
--- | --- | --- | --- | ---
lbstatus | -50 | 0 | 25 | 25
lbstatus | -25 | 0 | -25 | 50
lbstatus | 0 | 0 | 0 | 0
(repeat)

つまりこのようにスケジュールされます: a c d a c d a c d ... 次の点に注意してください:

worker | a | b | c | d
--- | --- | --- | --- | ---
lbfactor | 25 | 25 | 25 | 25

この挙動は、次の設定と全く同じになります:

worker | a | b | c | d
--- | --- | --- | --- | ---
lbfactor | 1 | 1 | 1 | 1

と言うのも、lbfactor の値は全て正規化されたもので、 他との相対値だからです。次の設定では:

worker | a | b | c
--- | --- | --- | ---
lbfactor | 1 | 4 | 1

ワーカー b は、平均して、a と c の 4 倍の数のリクエストを受け持つことになります。

次のような非対称な設定では、こうなると予想されるでしょう:

worker | a | b
--- | --- | ---
lbfactor | 70 | 30
lbstatus | -30 | 30
lbstatus | 40 | -40
lbstatus | 10 | -10
lbstatus | -20 | 20
lbstatus | -50 | 50
lbstatus | 20 | -20
lbstatus | -10 | 10
lbstatus | -40 | 40
lbstatus | 30 | -30
lbstatus | 0 | 0
(repeat)

スケジュールは 10 スケジュール後に繰り返され、a 7 回と b 3 回でまばらに選ばれます。

## Weighted Traffic Counting アルゴリズム

`lbmethod=bytraffic` で有効になります。 このスケジューラの背景にある考え方は、Request Counting と非常に似ていますが、次の違いがあります:

lbfactor は どれだけのバイト数のトラフィック量を、 このワーカーに処理してもらいたいか を表します。 この値も同様に正規化された値で、ワーカー全体のうちでの "分担" 量を表現しています。リクエスト数を単純に数える代わりに、 どれだけの転送量を処理したかを数えます。

次のようにバランサを設定した場合:

worker | a | b | c
--- | --- | --- | ---
lbfactor | 1 | 2 | 1

b には a や c の 2 倍 処理してほしいということになります。 b は 2 倍の I/O を処理するという意味になり、 2 倍のリクエスト数を処理するということにはなりません。 ですからリクエストとレスポンスのサイズが、 重み付けと振り分けのアルゴリズムに効いています。

## Pending Request Counting アルゴリズム

`lbmethod=bybusyness` で有効になります。このスケジューラは 現在どのぐらいのリクエストが個々のワーカーにアサインされているかを把握しています。 新しいリクエストは、最も処理途中のリクエスト数が少ないワーカーに 自動的に割り振られます。これは、ワーカーが Apache と無関係に入力リクエストを キューに溜め込む場合に有効で、キューの長さを同程度に維持しつつも、 最も早く処理できそうなワーカーに常にリクエストを割り振ります。

複数のワーカーが最少の処理中リクエスト数で並んだ場合、Request Counting アルゴリズムと同じ統計情報（と重み付け）を使って順番を決めます。 時間が経つと、割り振りの割合は `byrequests` と似たような 傾向を示すようになるでしょう。

このアルゴリズムは Apache HTTP サーバ 2.2.10以降で利用可能です。

## エクスポートされる環境変数

現在、6 つの環境変数がエクスポートされます:

BALANCER_SESSION_STICKY

  現在のリクエストに使われる stickysession 値になります。 スティッキーセッションのためのクッキー名もしくはリクエストパラメータ名です。

BALANCER_SESSION_ROUTE

  現在のリクエストをパースして得られる route 値です。

BALANCER_NAME

  現在のリクエストが使うバランサ名です。`balancer://foo` のような値です。

BALANCER_WORKER_NAME

  現在のリクエストが使うワーカー名です。`http://hostA:1234` のような値です。

BALANCER_WORKER_ROUTE

  現在のリクエストが使うワーカーの route 値です。

BALANCER_ROUTE_CHANGED

  セッションルートとワーカールートが一致しない時 (BALANCER_SESSION_ROUTE != BALANCER_WORKER_ROUTE) あるいは、セッションがまだルートを確立していない時、値が 1 になります。 スティッキーセッションを使う時、ルートの更新をクライアントに送る必要があるかを 判断するためにこの環境変数を使えます。

## バランサマネージャのサポートを有効にする

このモジュールは `mod_status` のサービスを 必要とします。 バランサマネージャを使うと、バランサのメンバーの動的な更新が できます。バランサマネージャを使って、バランス係数 (lbfactor) を変更したり、メンバーを変更したり、特定のメンバーを オフラインモードにしたりできます。

ですから、ロードバランサ管理機能を使いたければ、 `mod_status` と `mod_proxy_balancer` をサーバに組み込まなければなりません。

example.com ドメインのブラウザからロードバランサ管理機能を 使えるようにするには、次のようなコードを `httpd.conf` に追加します。

`<Location /balancer-manager>
SetHandler balancer-manager
Order Deny,Allow
Deny from all
Allow from .example.com
</Location>`

こうすると、`http://your.server.name/balancer-manager` のページ経由で、ウェブブラウザからロードバランサマネージャに アクセスできるようになります。

## ロードバランサのスティッキネスの詳細

クッキーをもとにスティッキネスを使う場合、どのバックエンドに割り振るべきか を決めるクッキーの名前を指定する必要があります。 クッキー名は `ProxyPass` または `ProxySet` のいずれか に付与する stickysession 属性で設定します。 クッキー名は大文字小文字を区別します。 バランサはそのクッキーの値を取り出し、その値に一致する route 値の ワーカーを探します。 route も `ProxyPass` または `ProxySet` のいずれかに設定しなければいけません。 クッキーはバックエンドによって設定されるか、あるいは 上記の 例 のように Apache Web サーバ自身 によって設定されます。

バックエンドの中の一部は少し異なる形式のスティッキネスクッキーを使います。 たとえば Apache Tomcat がそうです。Tomcat は自身のインスタンス名を セッション ID のクッキーの最後に付け加えます。この時、セッション ID との区切り文字にドット (`.`) を使います。 このため、Apache Web サーバがドットをスティッキネスクッキー値の中に見つけると、 route を探すためにドット以降の部分のみを使うようにします。 Tomcat 側で自身のインスタンス名を設定するには、Tomcat の設定ファイル `conf/server.xml` の中の `jvmRoute` 属性に 指定する必要があります。値はそれぞれの Tomcat に接続するワーカーの route 値と一致させます。 Tomcat およびサーブレットベースの Java Web アプリサーバが一般に使う セッションクッキーの名前は `JSESSIONID` (すべて大文字) です。 この名前は設定により変更も可能です。

スティッキネスを実装するふたつめの手段は URL エンコーディングです。 Web サーバはリクエストの URL の中からクエリパラメータを探します。 探すパラメータ名は同じように stickysession 属性で指定します。 パラメータ値と一致する route 値のワーカーを探します。 レスポンスに含まれるすべての URL リンクを探しだし書き換えるのは簡単ではないので、 一般にそれぞれのリンクにクエリパラメータを付け加えるのは、 そのコンテンツを生成したバックエンドの仕事です。 時には、`mod_substitute` を使って Web サーバにこの書き換えを させるのが可能な場合もあります。 ただし、パフォーマンスを落とす可能性があります。

Java 標準は URL エンコーディングを少し異なる形で実装します。 URL のパス情報をセミコロン (`;`) で区切って セッション ID を付け加えます。 クッキーの場合と同じように、 Apache Tomcat はこのパス情報に `jvmRoute` の設定値を含めます。 Apache にこの種のパス情報を見つけさせるには、 `ProxyPass` あるいは `ProxySet` の `scolonpathdelim` を `On` にします。

最後に、クッキーと URL エンコーディングの両方が指定できることを示します。 次の例のように、クッキー名と URL パラメータ名を垂直バー (`|`) で区切って指定します:

`ProxyPass /test balancer://mycluster stickysession=JSESSIONID|jsessionid scolonpathdelim=On <Proxy balancer://mycluster>
BalancerMember http://192.168.1.50:80 route=node1
BalancerMember http://192.168.1.51:80 route=node2
</Proxy>
`

もし同じリクエストが、クッキーとリクエストパラメータの両方のルーティング情報を 提供した場合、リクエストパラメータのほうが使われます。

## ロードバランサのスティッキネスのトラブルシューティング

もしアプリのセッションが失われてユーザが再ログインしなければいけないなど スティッキネス関連のエラーに遭遇したら、 この原因はバックエンドの応答に支障があったせいか、 あるいは設定ミスによるものかを最初に切り分けたいでしょう。 バックエンドの安定性に関して起きうる問題を見つけるには、 Apache のエラーログにプロキシエラーのメッセージがないか確認してください。

設定が正しいかを確認するには、最初にスティッキネスを クッキーと URL エンコーディングのどちらで行っているかを確認してください。 次に、`LogFormat` を変更して アクセスログに適切なデータが残るようにするとよいでしょう。 次のフィールドが便利です:

`%{MYCOOKIE}C`
  `MYCOOKIE` という名前のクッキーの値。 この名前は stickysession 属性の指定値と同じはずです。
`%{Set-Cookie}o`
  これによりバックエンドがセットするクッキーをログに出せます。 バックエンドが期待するセッションクッキーをセットしているかと、 どんな値がセットされているかを追跡できます。
`%{BALANCER_SESSION_STICKY}e`
  ルーティング情報を決めるために使われたクッキー名もしくは リクエストパラメータ名。
`%{BALANCER_SESSION_ROUTE}e`
  リクエスト内に見つかった route 値の情報
`%{BALANCER_WORKER_ROUTE}e`
  選択されたワーカーの route 値
`%{BALANCER_ROUTE_CHANGED}e`
  リクエストの route 値がワーカーの route 値と異なる場合に `1` になります。つまり、リクエストはスティッキーとして 処理されていません。

セッションが失われる原因でよくあるものは、セッションタイムアウトですが、 これは通常バックエンドのサーバで変更可能です。

ログレベルを `debug` 以上に設定すると、 バランサはスティッキネス動作の詳細な情報をエラーログに書き出します。 これはスティッキネスの問題のトラブルシューティングする簡単な手法ですが、 高負荷な本番サーバではログの分量が膨大になってしまうかもしれません。

翻訳済み言語: en | ja