HAProxyを使用してUbuntuVPSでHTTP負荷分散を設定する方法

提供:Dev Guides
移動先:案内検索

HAProxyについて


HAProxy(High Availability Proxy)は、任意のTCPサービスの負荷を分散できるオープンソースのロードバランサーです。 セッションの永続性とレイヤー7処理をサポートするため、HTTP負荷分散に特に適しています。

DigitalOcean Private Networking を使用すると、HAProxyをフロントエンドとして構成して、プライベートネットワーク接続を介して2つのVPSの負荷を分散できます。

プレリュード


ここでは3つのVPS(ドロップレット)を使用します。

ドロップレット1-ロードバランサーホスト名:haproxy OS:UbuntuパブリックIP:1.1.1.1プライベートIP:10.0.0.100

ドロップレット2-ノード1ホスト名:lamp1 OS:UbuntuプライベートIP上のLAMP:10.0.0.1

ドロップレット2-ノード2ホスト名:lamp2 OS:UbuntuプライベートIP上のLAMP:10.0.0.2

HAProxyのインストール


apt-getコマンドを使用してHAProxyをインストールします。

apt-get install haproxy

initスクリプトでHAProxyを起動できるようにする必要があります。

nano /etc/default/haproxy

ENABLEDオプションを1に設定します

ENABLED=1

この変更が適切に行われたかどうかを確認するには、パラメータなしでHAProxyのinitスクリプトを実行します。 次のように表示されます。

root@haproxy:~# service haproxy
Usage: /etc/init.d/haproxy {start|stop|reload|restart|status}

HAProxyの設定


デフォルトの構成ファイルを移動して、独自の構成ファイルを作成します。

mv /etc/haproxy/haproxy.cfg{,.original}

新しい構成ファイルを作成および編集します。

nano /etc/haproxy/haproxy.cfg

このファイルにブロックごとに構成を追加することから始めましょう。

global
    log 127.0.0.1 local0 notice
    maxconn 2000
    user haproxy
    group haproxy

logディレクティブは、ログメッセージの送信先となるsyslogサーバーについて言及しています。 Ubuntuでは、rsyslogはすでにインストールされ実行されていますが、IPアドレスをリッスンしません。 rsyslogの設定ファイルは後で変更します。

maxconnディレクティブは、フロントエンドでの同時接続の数を指定します。 デフォルト値は2000であり、VPSの構成に応じて調整する必要があります。

userおよびgroupディレクティブは、HAProxyプロセスを指定されたユーザー/グループに変更します。 これらは変更しないでください。

defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    retries 3
    option redispatch
    timeout connect  5000
    timeout client  10000
    timeout server  10000

このセクションではデフォルト値を指定しています。 変更する値は、さまざまなtimeoutディレクティブです。 connectオプションは、VPSへの接続試行が成功するのを待機する最大時間を指定します。

clientおよびserverタイムアウトは、クライアントまたはサーバーがTCPプロセス中にデータを確認または送信することが期待される場合に適用されます。 HAProxyは、clientserverのタイムアウトを同じ値に設定することをお勧めします。

retriesディレクティブは、接続障害後にVPSで実行する再試行回数を設定します。

option redispatchは、接続障害が発生した場合のセッションの再配布を可能にします。 したがって、VPSがダウンすると、セッションのスティッキネスが上書きされます。

listen appname 0.0.0.0:80
    mode http
    stats enable
    stats uri /haproxy?stats
    stats realm Strictly\ Private
    stats auth A_Username:YourPassword
    stats auth Another_User:passwd
    balance roundrobin
    option httpclose
    option forwardfor
    server lamp1 10.0.0.1:80 check
    server lamp2 10.0.0.2:80 check

これには、フロントエンドとバックエンドの両方の構成が含まれます。 アプリケーションを識別するための単なる名前であるappnameをポート80でリッスンするようにHAProxyを構成しています。 statsディレクティブは、接続統計ページを有効にし、stats authディレクティブで指定された資格情報を使用してHTTP基本認証で保護します。

このページはstats uriに記載されているURLで表示できるため、この場合はhttp://1.1.1.1/haproxy?statsです。 このページのデモはここで見ることができます

balanceディレクティブは、使用する負荷分散アルゴリズムを指定します。 使用可能なオプションは、ラウンドロビン(roundrobin)、静的ラウンドロビン(static-rr)、最小接続(leastconn)、ソース(source)、URI([ X135X] )およびURLパラメーター(url_param)。

各アルゴリズムに関する情報は、公式ドキュメントから入手できます。

serverディレクティブは、バックエンドサーバーを宣言します。構文は次のとおりです。

server <name> <address>[:port] [param*]

ここで言及する名前は、ログとアラートに表示されます。 このディレクティブでサポートされている多くのパラメーターがあり、この記事ではcheckおよびcookieパラメーターを使用します。 checkオプションは、VPSのヘルスチェックを有効にします。それ以外の場合、VPSは常に使用可能であると見なされます。

設定が完了したら、HAProxyサービスを開始します。

service haproxy start

負荷分散とフェイルオーバーのテスト


この設定をテストするには、すべてのWebサーバー(バックエンドサーバー-ここではLAMP1とLAMP2)でPHPスクリプトを作成します。

/var/www/file.php

<?php
header('Content-Type: text/plain');
echo "Server IP: ".$_SERVER['SERVER_ADDR'];
echo "\nClient IP: ".$_SERVER['REMOTE_ADDR'];
echo "\nX-Forwarded-for: ".$_SERVER['HTTP_X_FORWARDED_FOR'];
?>

次に、curlを使用して、このファイルを複数回要求します。

> curl http://1.1.1.1/file.php

Server IP: 10.0.0.1
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.X.X

> curl http://1.1.1.1/file.php

Server IP: 10.0.0.2
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.X.X

> curl http://1.1.1.1/file.php

Server IP: 10.0.0.1
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.X.X

ここで、HAProxyがLAMP1とLAMP2の間の接続を交互に切り替えた方法に注目してください。これは、ラウンドロビンの仕組みです。 ここに表示されるクライアントIPはロードバランサーのプライベートIPアドレスであり、X-Forwarded-ForヘッダーはIPです。

フェイルオーバーがどのように機能するかを確認するには、Webサーバーにアクセスしてサービスを停止します。

lamp1@haproxy:~#service apache2 stop

curlを使用してリクエストを再度送信し、動作を確認してください。

セッションの粘着性


Webアプリケーションがユーザーのログインセッションに基づいて動的コンテンツを提供する場合(アプリケーションは提供しません)、訪問者はVPSを継続的に切り替えるために奇妙なことを経験します。 セッションのスティッキネスにより、訪問者は最初のリクエストを処理したVPSに固執することができます。 これは、各バックエンドサーバーにCookieをタグ付けすることで可能になります。

次のPHPコードを使用して、セッションのスティッキネスがどのように機能するかを示します。

/var/www/session.php

<?php
header('Content-Type: text/plain');
session_start();
if(!isset($_SESSION['visit']))
{
        echo "This is the first time you're visiting this server";
        $_SESSION['visit'] = 0;
}
else
        echo "Your number of visits: ".$_SESSION['visit'];

$_SESSION['visit']++;

echo "\nServer IP: ".$_SERVER['SERVER_ADDR'];
echo "\nClient IP: ".$_SERVER['REMOTE_ADDR'];
echo "\nX-Forwarded-for: ".$_SERVER['HTTP_X_FORWARDED_FOR']."\n";
print_r($_COOKIE);
?>

このコードは、 PHPセッションを作成し、単一セッションのページビュー数を表示します。

クッキー挿入方法

この方法では、HAProxyからクライアントへのすべての応答に、Cookie値としてバックエンドサーバーの名前が付いたSet-Cookie:ヘッダーが含まれます。 したがって、今後、クライアント(Webブラウザー)はこのCookieをすべての要求に含め、HAProxyはCookieの値に基づいて要求を適切なバックエンドサーバーに転送します。

この方法では、cookieディレクティブを追加し、listenの下のserverディレクティブを変更する必要があります。

   cookie SRVNAME insert
   server lamp1 10.0.0.1:80 cookie S1 check
   server lamp2 10.0.0.2:80 cookie S2 check

これにより、HAProxyは、S1またはS2という値を持つSRVNAMEという名前のCookieを含むSet-Cookie:ヘッダーを追加します。これは、バックエンドがリクエストに応答したことに基づいています。 これが追加されたら、サービスを再起動します。

service haproxy restart

curlを使用して、これがどのように機能するかを確認します。

> curl -i http://1.1.1.1/session.php
HTTP/1.1 200 OK
Date: Tue, 24 Sep 2013 13:11:22 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.8
Set-Cookie: PHPSESSID=l9haakejnvnat7jtju64hmuab5; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 143
Connection: close
Content-Type: text/plain
Set-Cookie: SRVNAME=S1; path=/

This is the first time you're visiting this server
Server IP: 10.0.0.1
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.X.X
Array
(
)

これは私たちが行った最初のリクエストであり、Set-Cookie: SRVNAME=S1; path=/からわかるようにLAMP1によって応答されました。 ここで、Webブラウザーが次の要求に対して行うことをエミュレートするために、curlの--cookieパラメーターを使用してこれらのCookieを要求に追加します。

> curl -i http://1.1.1.1/session.php --cookie "PHPSESSID=l9haakejnvnat7jtju64hmuab5;SRVNAME=S1;"
HTTP/1.1 200 OK
Date: Tue, 24 Sep 2013 13:11:45 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 183
Connection: close
Content-Type: text/plain

Your number of visits: 1
Server IP: 10.0.0.1
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.87.127
Array
(
    [PHPSESSID] => l9haakejnvnat7jtju64hmuab5
    [SRVNAME] => S1
)

> curl -i http://1.1.1.1/session.php --cookie "PHPSESSID=l9haakejnvnat7jtju64hmuab5;SRVNAME=S1;"
HTTP/1.1 200 OK
Date: Tue, 24 Sep 2013 13:11:45 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 183
Connection: close
Content-Type: text/plain

Your number of visits: 2
Server IP: 10.0.0.1
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.87.127
Array
(
    [PHPSESSID] => l9haakejnvnat7jtju64hmuab5
    [SRVNAME] => S1
)

これらの要求は両方ともLAMP1によって処理され、セッションは適切に維持されました。 この方法は、Webサーバー上のすべてのファイルに粘着性が必要な場合に役立ちます。

クッキープレフィックス方式


一方、特定のCookieに対してのみスティッキーが必要な場合、またはセッションのスティッキーに対して個別のCookieが必要ない場合は、prefixオプションが適しています。

この方法を使用するには、次のcookieディレクティブを使用します。

cookie PHPSESSID prefix

PHPSESSIDは独自のCookie名に置き換えることができます。 serverディレクティブは、前の構成と同じままです。

それでは、これがどのように機能するかを見てみましょう。

> curl -i http://1.1.1.1/session.php
HTTP/1.1 200 OK
Date: Tue, 24 Sep 2013 13:36:27 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.8
Set-Cookie: PHPSESSID=S1~6l2pou1iqea4mnhenhkm787o56; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 143
Content-Type: text/plain

This is the first time you're visiting this server
Server IP: 10.0.0.1
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.X.X
Array
(
)

serverクッキーS1がセッションクッキーの前に付けられていることに注目してください。 それでは、このCookieを使用してさらに2つのリクエストを送信しましょう。

> curl -i http://1.1.1.1/session.php --cookie "PHPSESSID=S1~6l2pou1iqea4mnhenhkm787o56;"
HTTP/1.1 200 OK
Date: Tue, 24 Sep 2013 13:36:45 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 163
Content-Type: text/plain

Your number of visits: 1
Server IP: 10.0.0.1
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.X.X
Array
(
    [PHPSESSID] => 6l2pou1iqea4mnhenhkm787o56
)

> curl -i http://1.1.1.1/session.php --cookie "PHPSESSID=S1~6l2pou1iqea4mnhenhkm787o56;"
HTTP/1.1 200 OK
Date: Tue, 24 Sep 2013 13:36:54 GMT
Server: Apache/2.2.22 (Ubuntu)
X-Powered-By: PHP/5.3.10-1ubuntu3.8
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 163
Content-Type: text/plain

Your number of visits: 2
Server IP: 10.0.0.1
Client IP: 10.0.0.100
X-Forwarded-for: 117.213.X.X
Array
(
    [PHPSESSID] => 6l2pou1iqea4mnhenhkm787o56
)

両方のリクエストがLAMP1によって処理され、セッションが完全に機能していることがはっきりとわかります。

HAProxyのロギングを設定する


HAProxyの設定を開始したときに、log 127.0.0.1 local0 noticeという行を追加しました。これはsyslogメッセージをローカルホストのIPアドレスに送信します。 ただし、デフォルトでは、Ubuntuのrsyslogはどのアドレスもリッスンしません。 だから私たちはそうさせなければなりません。

rsyslogの設定ファイルを編集します。

nano /etc/rsyslog.conf

次の行を追加/編集/コメント解除します。

$ModLoad imudp
$UDPServerAddress 127.0.0.1
$UDPServerRun 514

これで、rsyslogはアドレス127.0.0.1のUDPポート514で機能しますが、すべてのHAProxyメッセージは/var/log/syslogに送信されるため、それらを分離する必要があります。

HAProxyログのルールを作成します。

nano /etc/rsyslog.d/haproxy.conf

次の行を追加します。

if ($programname == 'haproxy') then -/var/log/haproxy.log

次に、rsyslogサービスを再起動します。

service rsyslog restart

これにより、すべてのHAProxyメッセージとアクセスログが/var/log/haproxy.logに書き込まれます。

HAProxyのキープアライブ


listenディレクティブでは、Connection: closeヘッダーを追加するoption httpcloseを使用しました。 これは、応答を受信した後に接続を閉じるようにクライアント(Webブラウザー)に指示します。

HAProxyでキープアライブを有効にする場合は、option httpclose行を次のように置き換えます。

option http-server-close
timeout http-keep-alive 3000

いくつかの接続がロードバランサーのすべてのリソースを消費しないように、キープアライブタイムアウトを適切に設定します。

キープアライブのテスト

キープアライブは、curlを使用して、同時に複数のリクエストを送信することでテストできます。 次の例では、不要な出力は省略されます。

> curl -v http://1.1.1.1/index.html http://1.1.1.1/index.html
* About to connect() to 1.1.1.1 port 80 (#0)
*   Trying 1.1.1.1... connected
> GET /index.html HTTP/1.1
> User-Agent: curl/7.23.1 (x86_64-pc-win32) libcurl/7.23.1 OpenSSL/0.9.8r zlib/1.2.5
> Host: 1.1.1.1
> Accept: */*
>
......[Output omitted].........
* Connection #0 to host 1.1.1.1 left intact
* Re-using existing connection! (#0) with host 1.1.1.1
* Connected to 1.1.1.1 (1.1.1.1) port 80 (#0)
> GET /index.html HTTP/1.1
> User-Agent: curl/7.23.1 (x86_64-pc-win32) libcurl/7.23.1 OpenSSL/0.9.8r zlib/1.2.5
> Host: 1.1.1.1
> Accept: */*
>
.......[Output Omitted].........
* Connection #0 to host 1.1.1.1 left intact
* Closing connection #0

この出力では、Re-using existing connection! (#0) with host 1.1.1.1という行を探す必要があります。これは、curlが同じ接続を使用して後続の要求を行ったことを示しています。