共计 7628 个字符,预计需要花费 20 分钟才能阅读完成。
本文目录:
1. 配置 haproxy 需要考虑的事情
2. 配置 haproxy 提供反向代理功能
haproxy 是一个非常优秀的负载均衡工具,它的特性非常丰富,功能也非常非常强大,要想好好使用它,将它的功能和性能挖掘出来,多多阅读官方手册是必不可少的。
本文提供一个简单的配置示例,后面将分别开文章详细解释它的配置文件、cookie 会话保持、stick table 的功能、haproxy 主主模型的复制(replication)、抵御攻击等等。
1. 配置 haproxy 需要考虑的事情
尽管 haproxy 大多数配置选项都可以采用默认配置,但有些选项,特别是关于实际需求、连接数和超时时间相关的选项必须独立配置。
大致总结了下以下几点需要考虑的问题:
- haproxy 支持 5 种 http 事务模型。一般只会选择其中两种:
- (1). 当后端为静态 web 或静态缓存服务器时,使用
http-keep-alive
模型,由于响应速度快,频繁建立 tcp 连接的代价比较大; - (2). 当后端为动态应用程序服务器或者静态但传输的资源对象体积较大时,使用
http-server-close
模型,因为响应速度相对较慢,占用空闲连接的资源比建立 tcp 连接的代价更大。
- (1). 当后端为静态 web 或静态缓存服务器时,使用
- haproxy 反向代理的调度算法优先级是低于 cookie 的,因此当一个连接已经保持了会话,调度算法对该连接就无效。只有新的连接请求或者长连接已经失效时,才会使用调度算法进行调度。在调度算法的选择上,如果不考虑服务器性能差距的话:
- (1). 如果后端会话时间比较长(mysql),建议使用
leastconn
,因为调度过程中,后端释放连接时动荡不大,比较稳定。 - (2). 如果后端是静态 web,建议使用 roundrobin 算法。
- (3). 如果后端需要保持会话信息,但又不使用 cookie 时,可以使用源地址 hash 算法
source
,保证将同一客户端引导到同一后端服务器上。如果使用 cookie,则可以使用roundrobin
或leastconn
算法。源地址 hash 算法,一般只在没有办法的时候但又要调度到同一后端服务器时,才作为最后手段。 - (4). 如果配置了 session 共享,则对于 haproxy 来说,动态资源的请求是 ” 无状态 ” 的,可以使用
roundrobin
算法或leastconn
。 - (5). 如果后端是缓存服务器,为了保证命中率,建议使用
uri
算法,同时将hash-type
设置为consistent
方法(一致性 hash),保证后端缓存服务器 down 掉后对客户端的影响足够小。
- (1). 如果后端会话时间比较长(mysql),建议使用
- haproxy 是单进程、事件驱动模型的软件,单进程下工作效率已经非常好,不建议开启的多进程 / 多实例。
maxconn
指令控制最大并发连接数,可以在多处设置,设置位置不同,代表意义不同:- (1). 设置在 global 段或 frontend/listen/defaults 段的
maxconn
代表的是和客户端 (即 frontend) 的最大连接并发数;其中 global 段的值是硬限制,frontend/listen/defaults 段的maxconn
值不能超过 global 段的值。 - (2). 设置在 server 指令中时,代表的是 haproxy 和某台后端服务器维持的最大并发连接数。
- (3). 前端的最大并发数 (即 global 段的
maxconn
) 可以根据内存来估算,haproxy 为每个连接维持两个缓存区,每个大致 16K 左右,加上一些额外数据,共约 33-34K 左右,因此理论上 1G 的空闲内存能维持 2W-2.5W 个纯 HTTP 的并发连接 (只是理论上),如果代理的是 https,则允许的最大并发数量要小的多。 前端maxconn
默认值为 2000,非常有必要将其增加几倍。一般代理纯 http 服务时,如果后端能处理及时,这里设置 20000 以上都不会有什么问题。以上只是大致估算代理能力,实际设置时必须根据后端处理能力以及 haproxy 自身能力设置前端maxconn
,否则将前端接进来后端也无法立即处理。 - (4). 后端所有服务器的
maxconn
值之和应接近前端的maxconn
值,计算两者差距时,还需要考虑后端的等待队列长度maxqueue
。其中和静态 web 服务器的maxconn
可以设置大一些。
- (1). 设置在 global 段或 frontend/listen/defaults 段的
- 开启 haproxy 和后端的 连接重用 功能。当某客户端的请求到来后,haproxy 和后端某服务器建立一个 TCP 连接,并将请求调度到该服务器上,该客户端后续的请求也会通过该 TCP 连接转发给后端 (假设没有采用关闭后端连接的 http 事务模型)。但在响应后和该客户端的下一个请求到来前,这个连接是空闲的。和后端建立的 TCP 连接只是为了调度转发,保证持有合适 cookie 的客户端请求能调度到同一后端,完全可以为其它客户端的请求调度也使用这个 TCP 连接,保证 TCP 连接资源不浪费。可以使用
http-reuse strategy_name
指令设置连接重用的策略,而默认策略禁用连接重用。- (1).
never
:这是默认设置。表示禁用连接重用,因为老版本的 haproxy 认为来源不同的请求不应该共享同一个后端连接。 - (2).
safe
:这是建议使用的策略。” 安全 ” 策略下,haproxy 为客户端的每个第一个请求都单独建立一个和后端的 TCP 连接,但是后续的请求则会重用和该后端的空闲 TCP 连接。这样的转发不仅提高了资源使用率,还保持了 keep-alive 的功能。因此,safe
策略配合http-keep-alive
事务模式比http-server-close
事务模式更高效,无论后端是静态、缓存还是动态应用服务器。 - (3).
aggressive
:一种激进的策略,该策略的 haproxy 会重用空闲 TCP 连接来转发大多数客户端的第一次请求。之所以是大多数而不是所有,是因为 haproxy 会挑选那些已经被重用过至少一次的连接 (即从建立开始转发过至少两次,不管源是否是同一客户端) 进行重用,因为 haproxy 认为只有这样的连接才具有重用能力。 - (4).
always
:它将总是为第一个请求重用空闲连接。当后端是缓存服务器时,这种策略比safe
策略的性能要高许多,因为这样的请求行为都是一样的,且可以共享同一连接来获取资源。不过不建议使用这种策略,因为大多数情况下,它和aggressive
的性能是一样的,但是却带来了很多风险。
因此,为了性能的提升,将它设置为safe
或aggressive
吧,同时再将 http 事务模型设置为http-keep-alive
。
- (1).
- 对于 haproxy 是否开启 cookie 以及 stick table 相关功能的设置必须严加考虑,它直接影响调度算法的选择和负载均衡的性能。不过如果后端应用程序服务器共享了 session,haproxy 可以不用设置会话粘性相关的选项。
- haproxy 的默认配置文件中关于超时时间的设置应该修改,不少项设置都很不合理。
- 建议开启 haproxy 的
X-Forwarded-For
选项,使得后端服务器能够记录客户端的真实源 IP 地址。 - 建议开启 haproxy 的状态页面,并设置访问权限。
为了实现 Haproxy 完善的功能,上面几个问题是远远不够的,但可以在边使用 haproxy 过程中边增加功能使其不断完美。
2. 配置 haproxy 提供反向代理功能
假如要实现这样的环境:haproxy 反向代理 4 个 nginx 节点,nginx1 和 nginx2 结合 php 提供动态 web 服务,nginx3 和 nginx4 提供静态 web 服务。如下图:
由于默认配置文件中和超时时间相关的设置比较不合理,所以建议修改这些时间。另外还有些建议开启或关闭的的项也尽量开启或关闭。
默认配置如下:
global
log 127.0.0.1 local2 # 需要设置 /etc/rsyslog.conf 加上 local2 设备的日志记录级别和日志路径
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000 # 这是前段对外的最大连接数。代理 http 时,1G 空闲内存承载 20000 以上没大问题
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats # 开启动态查看、管理 haproxy 的状态文件
# 另外建议设置 spread-checks 全局项,且百分比建议为 2 - 5 之间
defaults
mode http # 7 层 http 代理,另有 4 层 tcp 代理
log global
option httplog # 在日志中记录 http 请求、session 信息等
option dontlognull # 不要在日志中记录空连接
option http-server-close # 后端为动态应用程序建议使用 http-server-close,后端为静态建议使用 http-keep-alive
option forwardfor except 127.0.0.0/8 # haproxy 将在发往后端的请求中加上 ”X-Forwarded-For” 首部字段
option redispatch # 当某后端 down 掉使得 haproxy 无法转发携带 cookie 的请求到该后端时,将其转发到别的后端上
timeout http-request 10s # 此为等待客户端发送完整请求的最大时长,应该设置较短些防止洪水攻击,如设置为 2 - 3 秒
# haproxy 总是要求一次请求或响应全部发送完成后才会处理、转发,
timeout queue 1m # 请求在队列中的最大时长,1 分钟太长了。设置为 10 秒都有点长,10 秒请求不到资源客户端会失去耐心
timeout connect 10s # haproxy 和服务端建立连接的最大时长,设置为 1 秒就足够了。局域网内建立连接一般都是瞬间的
timeout client 1m # 和客户端保持空闲连接的超时时长,在高并发下可稍微短一点,可设置为 10 秒以尽快释放连接
timeout server 1m # 和服务端保持空闲连接的超时时长,局域网内建立连接很快,所以尽量设置短一些,特别是并发时,如设置为 1 - 3 秒
timeout http-keep-alive 10s # 和客户端保持长连接的最大时长。优先级高于 timeout http-request 高于 timeout client
timeout check 10s # 和后端服务器成功建立连接后到最终完成检查的时长(不包括建立连接的时间,只是读取到检查结果的时长),
# 可设置短一点,如 1 - 2 秒
maxconn 3000 # 默认和前段的最大连接数,但不能超过 global 中的 maxconn 硬限制数
所以修改后建议配置为如下:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 20000
user haproxy
group haproxy
daemon
stats socket /var/lib/haproxy/stats
spread-checks 2
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
timeout http-request 2s
timeout queue 3s
timeout connect 1s
timeout client 10s
timeout server 2s
timeout http-keep-alive 10s
timeout check 2s
maxconn 18000
frontend http-in
bind *:80
mode http
log global
capture request header Host len 20
capture request header Referer len 60
acl url_static path_beg -i /static /images /stylesheets
acl url_static path_end -i .jpg .jpeg .gif .png .ico .bmp .css .js
acl url_static path_end -i .html .htm .shtml .shtm .pdf .mp3 .mp4 .rm .rmvb .txt
acl url_static path_end -i .zip .rar .gz .tgz .bz2 .tgz
use_backend static_group if url_static
default_backend dynamic_group
backend static_group
balance roundrobin
option http-keep-alive
http-reuse safe
option httpchk GET /index.html
http-check expect status 200
server staticsrv1 192.168.100.62:80 check rise 1 maxconn 5000
server staticsrv2 192.168.100.63:80 check rise 1 maxconn 5000
backend dynamic_group
cookie appsrv insert nocache
balance roundrobin
option http-server-close
option httpchk GET /index.php
http-check expect status 200
server appsrv1 192.168.100.60:80 check rise 1 maxconn 3000 cookie appsrv1
server appsrv2 192.168.100.61:80 check rise 1 maxconn 3000 cookie appsrv2
listen report_stats
bind *:8081
stats enable
stats hide-version
stats uri /hastats
stats realm “pls enter your name”
stats auth admin:admin
stats admin if TRUE
上面的配置中:
- (1). 静态请求将分配给 static_group 并进行 roundrobin 调度,同时通过获取 index.html 来做健康状况检查,此外还设置了 haproxy 和后端连接重用的功能。
- (2). 动态请求将分配给 dynamic_group 并进行 roundrobin 调度,但是向响应报文中插入了一个 cookie,保证被调度过的服务端和客户端能保持会话。此外还设置了通过获取 index.php 来做健康状况检查。
最后配置 nginx 和 php+php-fpm。
yum -y install nginx php php-fpm
为了区分,分别为 nginx1/nginx2 的 index.php、nginx3/nginx4 的 index.html 文件中加入响应的主机来源提示,并在 php 文件中设置 cookie 项。其中 index.php 的内容参考如下:
<h1>response from webapp 192.168.100.60</h1>
<?php
session_start();
echo “Server IP: “.”<font color=red>”.$_SERVER[‘SERVER_ADDR’].”</font>”.”<br>”;
echo “Server Name: “.”<font color=red>”.$_SERVER[‘SERVER_NAME’].”</font>”.”<br>”;
echo “SESSIONNAME: “.”<font color=red>”.session_name().”</font>”.”<br>”;
echo “SESSIONID: “.”<font color=red>”.session_id().”</font>”.”<br>”;
?>
测试。其中 php 页面返回内容大致如此:
构建高可用集群 Keepalived+Haproxy 负载均衡 https://www.linuxidc.com/Linux/2016-12/138917.htm
HAproxy 的基本配置(负载均衡 + 日志独立 + 动静分离 + 读写分离)https://www.linuxidc.com/Linux/2017-03/141614.htm
CentOS 7 下 Keepalived + HAProxy 搭建配置详解 https://www.linuxidc.com/Linux/2017-03/141593.htm
HAproxy 实现反向代理和负载均衡 https://www.linuxidc.com/Linux/2016-12/138749.htm
HAProxy+Keepalived 实现高可用负载均衡 https://www.linuxidc.com/Linux/2016-06/132225.htm
使用 HAProxy 配置 HTTP 负载均衡器 https://www.linuxidc.com/Linux/2015-01/112487.htm
Ubuntu 16.04 下安装 HAProxy 1.5.11 做 tcp 负载均衡 https://www.linuxidc.com/Linux/2016-06/132689.htm
CentOS 7.2 部署 Haproxy 1.7.2 https://www.linuxidc.com/Linux/2017-10/147553.htm
HAproxy 的详细介绍:请点这里
HAproxy 的下载地址:请点这里