关于HAProxy
HAProxy(高可用性代理)是一个开源负载均衡器,可以负载平衡任何TCP服务。 它特别适合于HTTP负载平衡,因为它支持会话持久性和第7层处理。
通过引入共享的专用网络中DigitalOcean HAProxy的可配置为前端负载均衡通过私人网络连接2 VPS。
序幕
我们将在这里使用三个VPS(Droplet):
Droplet 1 - 负载平衡器
主机名:haproxy
操作系统:Ubuntu
公共IP:1.1.1.1
私人IP:10.0.0.100
Droplet 2 - 节点1
主机名:lamp1
操作系统:LAMP在Ubuntu上
私人IP:10.0.0.1
Droplet 2 - Node 2
主机名:lamp2
操作系统:LAMP在Ubuntu上
私人IP: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的建议将设置client
和server
超时为相同的值。
在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
这包含前端和后端的配置。 我们正在配置HAProxy的监听端口80 appname
这仅仅是用于识别应用的名称。 该stats
指令启用连接统计页面,并保护它HTTP基本身份验证使用由指定的凭据stats auth
指令。
这个页可以在提及的网址观看stats uri
所以在这种情况下,它是http://1.1.1.1/haproxy?stats
;
此页的演示可以在这里查看 。
该balance
指令指定负载均衡算法使用。 可用的选项轮循( roundrobin
),静态轮循( static-rr
),最少连接( leastconn
),来源( source
),URI( uri
)和URL参数( url_param
)。
每个算法的信息可以从获得的官方文件 。
该server
指令声明后端服务器,语法是:
server <name> <address>[:port] [param*]
我们在此处提到的名称将显示在日志和警报中。 有很多paratmeters通过这个指令支持,我们将使用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之间的连接,这就是Round Robin的工作原理。 我们在这里看到的客户端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会话 ,并显示在一个会话的页面浏览数。
Cookie插入方法
在这种方法中,从HAProxy的到客户端的所有响应将包含Set-Cookie:
头与后端服务器作为其cookie值的名称。 因此,前进的客户端(网络浏览器)将包括此cookie及其所有请求,HAProxy将根据cookie值将请求转发到正确的后端服务器。
对于这种方法,你将需要添加cookie
指令,并修改server
下指令listen
cookie SRVNAME insert
server lamp1 10.0.0.1:80 cookie S1 check
server lamp2 10.0.0.2:80 cookie S2 check
这将导致HAProxy的添加Set-Cookie:
头用一个cookie命名SRVNAME
有作为其值S1
或S2
基于其后端回答的请求。 一旦这被添加重新启动服务:
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
(
)
这是我们做的第一个请求,它是由LAMP1回答,因为我们可以从看到Set-Cookie: SRVNAME=S1; path=/
Set-Cookie: SRVNAME=S1; path=/
。 现在,模仿什么网页浏览器将下一个请求做的,我们这些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粘性或者不希望有会话粘性一个单独的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
的cookie S1
被前缀到会话cookie。 现在,让我们用这个cookie发送两个请求。
> 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现在将UDP端口514上运行的地址为127.0.0.1,但所有的消息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
。
Keepalive在HAProxy
根据listen
指令,我们使用option httpclose
增加了一个Connection: close
标头。 这告诉客户端(Web浏览器)在收到响应后关闭连接。
如果您想要启用HAProxy的保持有效指示,更换option httpclose
符合:
option http-server-close
timeout http-keep-alive 3000
明智地设置保持活动超时,以便几个连接不会耗尽负载均衡器的所有资源。
测试Keepalive
保活可以使用被测试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
Re-using existing connection! (#0) with host 1.1.1.1
,这表明卷曲用的相同的连接,使后续请求。