这份文档提供了实际工作环境中的配置样例。请注意,除非另有规定,这份文档没有描述例如logging, chrooting, limits和time-outs等global配置参数。
===================================================
1. 基于cookie插入的简单HTTP负载均衡
===================================================
由于包含脚本的原因,1个web app经常可以使得前段server有很高的CPU loads。同样,web app也依赖于没有太多负载性能的后端数据库。用户的上下文存放在server上,而不是在数据库中。因此,采用TCP/IP负载均衡的方简单增加另外的server并不能很好的工作。
+-------+
|clients| clients and/or reverse-proxy
+---+---+
|
-+-----+--------+----
| _|_db
+--+--+ (___)
| web | (___)
+-----+ (___)
192.168.1.1 192.168.1.2
采用大型的SMP系统来替换普通server则会比增加低成本的server开销大很多。一个解决方案就是购买低成本的server,并在其上安装app。在其中1个旧的server上安装haproxy,会把负载分散到新的server上。
192.168.1.1 192.168.1.11-192.168.1.14 192.168.1.2
-------+-----------+-----+-----+-----+--------+----
| | | | | _|_db
+--+--+ +-+-+ +-+-+ +-+-+ +-+-+ (___)
| LB1 | | A | | B | | C | | D | (___)
+-----+ +---+ +---+ +---+ +---+ (___)
haproxy 4 cheap web servers
配置 haproxy (LB1) :
-------------------------
listen webfarm 192.168.1.1:80
mode http
balance roundrobin
cookie SERVERID insert indirect
option httpchk HEAD /index.html HTTP/1.0
server webA 192.168.1.11:80 cookie A check
server webB 192.168.1.12:80 cookie B check
server webC 192.168.1.13:80 cookie C check
server webD 192.168.1.14:80 cookie D check
描述:
-------------
- LB1 接收clients的requests
- 如果1个request不包含cookie,则把这个request前传到分配的一个有效的server
- 作为回报, 1个拥有server名称的cookie "SERVERID"会被插入到response中
- 当client带有cookie "SERVERID=A"再此访问时,LB1就会知道这个request必须被前传到server A. 同时删除这个cookie是的server不会看到它
- 当server"webA"宕机时,request会被前传至另外一个有效的server,并且重新分配cookie
数据流:
-------
(client) (haproxy) (server A)
>-- GET /URI1 HTTP/1.0 ------------> |
( no cookie, haproxy forwards in load-balancing mode. )
| >-- GET /URI1 HTTP/1.0 ---------->
| <-- HTTP/1.0 200 OK -------------<
( the proxy now adds the server cookie in return )
<-- HTTP/1.0 200 OK ---------------< |
Set-Cookie: SERVERID=A |
>-- GET /URI2 HTTP/1.0 ------------> |
Cookie: SERVERID=A |
( the proxy sees the cookie. it forwards to server A and deletes it )
| >-- GET /URI2 HTTP/1.0 ---------->
| <-- HTTP/1.0 200 OK -------------<
( the proxy does not add the cookie in return because the client knows it )
<-- HTTP/1.0 200 OK ---------------< |
>-- GET /URI3 HTTP/1.0 ------------> |
Cookie: SERVERID=A |
( ... )
限制:
- 如果clients使用keep-alive (HTTP/1.1),只有第1个response会被插入1个cookie,并且在每个连接中只有第1个request会被解析。不过由于在第1个response中会立即插入cookie,并且在同一个连接中会把后续的request分配至同一个server,所以在insertion模式下不会产生问题。然而,haproxy会删除前传到servers的cookie,所以server必须不能对未知的cookies敏感。如果这样会导致问题,可以通过添加下面的选项关闭keep-alive:
option httpclose
- 如果由于一些原因,clients无法学到多个cookie(例如:clients确实需要一些自制的应用程序或者网关),并且应用程序已经产生了一个cookie,可以通过是“prefix”模式。
- LB1成为1个非常敏感的server。如果LB1宕机,不再正常工作。可以通过keepalived进行热备。
- 如果应用程序需要记录原始的client IP地址,可以通过使用"forwardfor"选项增加包含原始client IP地址的"X-Forwarded-For" header。同样也需要使用"httpclose"保证重写每个request而不是仅仅每个连接的第1个request:
option httpclose
option forwardfor
- 如果应用程序需要记录原始的目的IP,可以通过使用"originalto"选项增加包含原始目的IP地址的"X-Original-To" header。同样也需要使用"httpclose"保证重写每个request而不是仅仅每个连接的第1个request:
option httpclose
option originalto
web serve必须配置为使用这些可替换的header。例如,apache,可以通过使用如下LogFormat:
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b " combined
CustomLog /var/log/httpd/access_log combined
提示:
-------
有时在网络中,可以发现有一定比例的client禁用了浏览器的cookies。显然,在网上有无处不在的问题,但是仍然可以通过使用"source"负载算法代替"roundrobin"从而帮助client访问你的网站。"source"负载算法可以在server数目不变的情况下保证一个给定的IP地址总会被分配至同1台server。因为会导致分配不均,所以不要在1个proxy或者1个小型网络后使用"source"负载算法。然而,在一个大型的内部网络和互联网,却可以工作的非常好。只要clients接受cookie,具有动态地址的Clients将不会受到影响。因为Cookie总是高于负载平衡的优先级:
listen webfarm 192.168.1.1:80
mode http
balance source
cookie SERVERID insert indirect
option httpchk HEAD /index.html HTTP/1.0
server webA 192.168.1.11:80 cookie A check
server webB 192.168.1.12:80 cookie B check
server webC 192.168.1.13:80 cookie C check
server webD 192.168.1.14:80 cookie D check