开源软件负载均衡器
现在常用的三大开源软件负载均衡器分别是Nginx、LVS、Haproxy。 在之前的文章中已经对比了这三个负载均衡软件, 下面根据自己的理解和使用经验, 再简单说下这三个负载均衡软件各自特点:
LVS负载均衡的特点
1) 抗负载能力强。抗负载能力强、性能高,能达到F5硬件的60%;对内存和cpu资源消耗比较低
2) 工作在网络4层,通过vrrp协议转发(仅作分发之用),具体的流量由linux内核处理,因此没有流量的产生。
3) 稳定性、可靠性好,自身有完美的热备方案;(如:LVS+Keepalived)
4) 应用范围比较广,可以对所有应用做负载均衡;
5) 不支持正则处理,不能做动静分离。
6) 支持负载均衡算法:rr(轮循)、wrr(带权轮循)、lc(最小连接)、wlc(权重最小连接)
7) 配置 复杂,对网络依赖比较大,稳定性很高。
Ngnix负载均衡的特点
1) 工作在网络的7层之上,可以针对http应用做一些分流的策略,比如针对域名、目录结构;
2) Nginx对网络的依赖比较小,理论上能ping通就就能进行负载功能;
3) Nginx安装和配置比较简单,测试起来比较方便;
4) 也可以承担高的负载压力且稳定,一般能支撑超过1万次的并发;
5) 对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测。
6) Nginx对请求的异步处理可以帮助节点服务器减轻负载;
7) Nginx仅能支持http、https和Email协议,这样就在适用范围较小。
8) 不支持Session的直接保持,但能通过ip_hash来解决。、对Big request header的支持不是很好,
9) 支持负载均衡算法:Round-robin(轮循)、Weight-round-robin(带权轮循)、Ip-hash(Ip哈希)
10) Nginx还能做Web服务器即Cache功能。
HAProxy负载均衡的特点
1) 支持两种代理模式:TCP(四层)和HTTP(七层),支持虚拟主机;
2) 能够补充Nginx的一些缺点比如Session的保持,Cookie的引导等工作
3) 支持url检测后端的服务器出问题的检测会有很好的帮助。
4) 更多负载均衡策略比如:动态加权轮循(Dynamic Round Robin),加权源地址哈希(Weighted Source Hash),加权URL哈希和加权参数哈希(Weighted Parameter Hash)已经实现
5) 单纯从效率上来讲HAProxy更会比Nginx有更出色的负载均衡速度。
6) HAProxy可以对Mysql进行负载均衡,对后端的DB节点进行检测和负载均衡。
9) 支持负载均衡算法:Round-robin(轮循)、Weight-round-robin(带权轮循)、source(原地址保持)、RI(请求URL)、rdp-cookie(根据cookie)
10) 不能做Web服务器即Cache。
这三大主流软件负载均衡器适用业务场景
1) 网站建设初期,可以选用Nigix/HAproxy作为反向代理负载均衡(或者流量不大都可以不选用负载均衡),因为其配置简单,性能也能满足一般的业务场景。如果考虑到负载均衡器是有单点问题,可以采用Nginx+Keepalived/HAproxy+Keepalived避免负载均衡器自身的单点问题。
2) 网站并发达到一定程度之后,为了提高稳定性和转发效率,可以使用LVS、毕竟LVS比Nginx/HAproxy要更稳定,转发效率也更高。不过维护LVS对维护人员的要求也会更高,投入成本也更大。
需要注意的是
Niginx与Haproxy比较: Niginx支持七层、用户量最大,稳定性比较可靠。Haproxy支持四层和七层,支持更多的负载均衡算法,支持session保存等。具体选型看使用场景,目前来说Haproxy由于弥补了一些Niginx的缺点致使其用户量也不断在提升。
衡量负载均衡器好坏的几个重要因素
1) 会话率 :单位时间内的处理的请求数
2) 会话并发能力:并发处理能力
3) 数据率:处理数据能力
经过官方测试统计,haproxy 单位时间处理的最大请求数为20000个,可以同时维护40000-50000个并发连接,最大数据处理能力为10Gbps。综合上述,haproxy是性能优越的负载均衡、反向代理服务器。
Haproxy简介
HAProxy是法国人Willy Tarreau开发的一款可应对客户端10000以上的同时连接的高性能的TCP和HTTP负载均衡器。由于其丰富强大的功能在国内备受推崇,是目前主流的负载均衡器。Haproxy是一个开源的高性能的反向代理或者说是负载均衡服务软件之一,它支持双机热备、虚拟主机、基于TCP和HTTP应用代理等功能。其配置简单,而且拥有很好的对服务器节点的健康检查功能(相当于keepalived健康检查),当其代理的后端服务器出现故障时,Haproxy会自动的将该故障服务器摘除,当服务器的故障恢复后haproxy还会自动重新添加回服务器主机。
Haproxy实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户空间(User-Space)实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么必须对其进行优化以使每个CPU时间片(Cycle)做更多的工作。
Haproxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。haproxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进当前架构中,同时可以保护web服务器不被暴露到网络上。
Haproxy软件引入了frontend,backend的功能,frontend(acl规则匹配)可以根据任意HTTP请求头做规则匹配,然后把请求定向到相关的backend(server pools等待前端把请求转过来的服务器组)。通过frontend和backend,可以很容易的实现Haproxy的7层负载均衡代理功能。
Haproxy是一种高效、可靠、免费的高可用及负载均衡解决方案,非常适合于高负载站点的七层数据请求。客户端通过Haproxy代理服务器获得站点页面,而代理服务器收到客户请求后根据负载均衡的规则将请求数据转发给后端真实服务器。
同一客户端访问服务器,Haproxy保持回话的三种方案:
1) Haproxy将客户端ip进行Hash计算并保存,由此确保相同IP访问时被转发到同一真实服务器上。
2) Haproxy依靠真实服务器发送给客户端的cookie信息进行回话保持。
3) Haproxy保存真实服务器的session及服务器标识,实现会话保持功能。
Haproxy工作原理
Haproxy提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。Haproxy特别适用于那些负载特别大的web站点,这些站点通常又需要会话保持或七层处理。Haproxy运行在时下的硬件上,完全可以支持数以万计的并发连接,并且它的运行模式使得它可以很简单安全的整合进您当前的架构中,同时可以保护你的web服务器不被暴露到网络上。
Haproxy实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space)实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以使每个CPU时间片(Cycle)做更多的工作。
Haproxy的优点
1)免费开源,稳定性也是非常好。单Haproxy也跑得不错,稳定性可以与硬件级的F5相媲美。
2)根据官方文档,Haproxy可以跑满10Gbps,这个数值作为软件级负载均衡器是相当惊人的。
3)Haproxy支持连接拒绝:因为维护一个连接的打开的开销是很低的,有时我们很需要限制攻击蠕虫(attack bots),也就是说限制它们的连接打开从而限制它们的危害。这个已经为一个陷于小型DDoS攻击的网站开发了而且已经拯救了很多站点,这个优点也是其它负载均衡器没有的。
4)Haproxy支持全透明代理(已具备硬件防火墙的典型特点):可以用客户端IP地址或者任何其他地址来连接后端服务器。这个特性仅在Linux 2.4/2.6内核打了tcp proxy补丁后才可以使用。这个特性也使得为某特殊服务器处理部分流量同时又不修改服务器的地址成为可能。
5)Haproxy现在多用于线上的Mysql集群环境,常用于它作为MySQL(读)负载均衡。
6)自带强大的监控服务器状态的页面,实际环境中我们结合Nagios进行邮件或短信报警。
7)Haproxy支持虚拟主机,许多朋友说它不支持虚拟主机是错误的,但是通过测试可知,Haproxy是支持虚拟主机的。
Haproxy主要工作位置
- Haproxy支持http反向代理
- Haproxy支持动态程序的反向代理
- Haproxy支持基于数据库的反向代理
Haproxy 相关术语
访问控制列表(ACL)
在负载均衡当中,ACL用于测试某些状况,并根据测试结果执行某些操作(例如选定一套服务器或者屏蔽某条请求), 如下ACL示例
1 |
|
如果用户请求的路径以/blog开头,则匹配这条ACL。举例来说,http://yourdomain.com/blog/blog-entry-1请求即符合这一条件。要了解更为具体的AC使用方法,请参阅HAProxy配置指南。
Backend
所谓backend是指一组服务器,负责接收各转发请求。Backend在HAProxy配置中的backend部分进行定义。一般来讲,backend的定义主要包括:
- 使用哪种负载均衡算法
- 一套服务器与端口列表
一条backend能够容纳一套或者多套服务器——总体而言向backend中添加更多服务器将能够将负载扩散至更多服务器,从而增加潜在负载容量。这种方式也能够提升可靠性,从而应对部分后端服务器发生故障的情况。
下面来看一套双backend配置示例,分别为web-backend与blog-backend,其各自包含两套Web服务器,且监听端口80:
1 2 3 4 5 6 7 8 9 10 |
|
其中:
.balance roundrobin行指定负载均衡算法, 具体细节请参阅负载均衡算法部分
.mode http则指定所使用的7层代理机制,具体请参阅负载均衡类型部分。
.结尾处的check选项指定在这些后端服务器上执行运行状态检查。
Frontend
一条frontend负责定义请求如何被转发至backend。Frontend在HAProxy配置中的frontend部分进行定义。其定义由以下几部分组成:
.一组IP地址与一个端口(例如10.1.1.7:80, *:443,等等)
.ACL
.use_backend规则,其负责根据当前ACL条件定义使用哪个backend,而default_backend规则处理一切其它情况
我们可以将同一frontend配置至多种不同网络流量类型
可以将同一frontend配置至多种不同网络流量类型!
下面了解负载均衡的基本类型。
无负载均衡
简单的无负载均衡Web应用环境, 用户会直接接入Web服务器,即kevin.com且其中不存在负载均衡机制。如果单一Web服务器发生故障,用户将无法接入该服务器。另外,如果多位用户同时访问该服务器,且其无法处理该负载,则可能出现响应缓慢或者无法接入的情况。
四层负载均衡
最为简单的负载均衡方式,将网络流量引导至多台服务器以使用四层(即传输层)负载均衡。这种方式会根据IP范围与端口进行用户流量转发(如果有请求指向http://kevin.com/anything,则该流量将被转发至backend,并由其处理全部指向kevin.com在端口80上的请求)
1 2 3 4 5 6 7 8 9 |
|
用户访问负载均衡器,后者将用户请求转发至后端服务器的web-backend组。被选定的后端服务器将直接响应用户请求。总体而言,web-backend中的全部服务器都应当拥有同样的内容, 否则用户可能会遭遇内容不一致问题。请注意后端两个Web服务器都接入同样的数据库服务器。
七层负载均衡
另一种更为复杂的负载均衡方式,网络流量使用7层(即应用层)负载均衡。使用7层意味着负载均衡器能够根据用户的请求内容将请求转发至不同后端服务器。这种方式允许大家在同一域名及端口上运行多套Web应用服务器。下图为一套简单的7层负载均衡示例在本示例中,如果用户向kevin.com/blog发送请求,则会被转发至blog后端,其包含一组运行有同一blog应用的服务器。其它请求则会被转发至web-backend,其负责运行其它应用。本示例中的两套backend皆使用同样的数据库服务器。下面来看本示例中frontend配置片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
这部分片段配置一套名为http的frontend,其负责处理端口80上的所有输入流量。
.acl url_blog path_beg 这里的/blog表示匹配那些用户请求路径以/blog开头的请求。
.use_backend blog-backend if url_blog 这里采用该ACL将流量代理至blog-backend。
.default_backend web-backend 这里指定全部其它流量被转发至web-backend。
负载均衡算法
负载均衡算法用于检测后端中的哪套服务器被负载均衡机制选定进行请求响应。HAProxy提供多种算法选项。除了负载均衡算法之外,我们还能够为服务器分配一个weight参数以指定该服务器被选定的频率。由于HAProxy提供多种负载均衡算法,因此我们下面只提及其中的一部分。来看几种常用算法:
roundrobin
Round Robin会对服务器进行轮流选定,亦为HAProxy的默认算法。即客户端每访问一次, 请求就跳转打到后端不同的节点机器上.
leastconn
选定连接数量最少的服务器——建议在周期较长的会话中使用这一算法。同一后端中的服务器亦会以轮循方式进行轮流选定。
source
其根据源IP(即用户IP地址)进行服务器选定。通过这种方式,我们可以确定同一用户接入同一服务器。
粘性会话
部分应用要求用户始终接入同一后端服务器,这一点需要利用粘性会话实现,其要求在backend中使用appsession参数。
运行状态检查
HAProxy利用运行状态检查来检测后端服务器是否可用于处理请求。通过这种方式,我们不必以手动方式撤下不可用的后端服务器。默认运行状态检查会与目标服务器建立一条TCP连接,即检查后端服务器是否在监听所配置的IP地址与端口。
如果某套服务器未能通过运行状态检查,并因此无法响应请求,则其会在后端中被自动禁用——意味着流量将不再被转发到该服务器处,直到其重新恢复正常。如果后端中的全部服务器皆发生故障,则服务将不再可用,直到至少一套后端服务器重新恢复正常。
对于特定后端类型,例如特定状态下的数据库服务器,默认运行状态检查可能无法正确识别其正常与否。
其它解决方案
如果大家认为HAProxy可能太过复杂,那么以下解决方案同样值得考虑:
.Linux虚拟服务器(LVS) - 一套简单且快速的4层负载均衡器,多数Linux发行版都内置有这套方案。
.Nginx - 一套快速且可靠的Web服务器,亦可用于代理及负载均衡。Nginx通常与HAProxy相结合以实现缓存及压缩功能。
Haproxy 使用细节梳理
以上简单介绍了Haproxy, 下面来整体梳理下Haproxy的使用:
Haproxy 程序环境
1 2 3 4 |
|
一. global 全局配置段
1.1) log:全局日志配置
默认发往本机的日志服务器;
1) 系统默认:log 127.0.0.1 local2 //表示发往远端可添加:log 远端IP local2
2) 修改本机日志配置文件
1 2 3 4 |
|
3) 远端日志配置(配合前端log配置)
1 2 |
|
1.2) 性能调整(依据生产环境适当调整)
.maxconn
.maxconnrate
.maxsessrate
.maxsslconn
.spread-checks <0..50, in percent>: 健康检测延迟时长比建议2-5之间
二. proxies 代理配置段结构
1) defaults:为frontend, backend, listen提供默认配置;
2) fronted:前端,指定接收客户端连接侦听套接字设置;
3) backend:后端,指定将连接请求转发至后端服务器的相关设置;
4) listen:同时拥有前端和后端,适用于一对一环境;
三. 简单haproxy代理案例
实验拓扑:
3.1) 方法一
配置 /etc/haproxy/haproxy.cfg, 将frontend段、backend段注释,新建如下配置
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
在浏览器访问http://172.18.43.62 刷新即可看到轮询效果, 即访问结果为192.168.43.61和192.168.43.63的web端口(80端口)展示的内容, 每次刷新, 访问结果都不一样, 即交替展示两个机器的web内容.
3.2) 方法二
上面两段配置也可以配置在一段实现相同功能,配置如下
1 2 3 4 5 6 7 8 9 10 |
|
配置参数 bind:指定一个或多个前端侦听地址和端口
语法: bind [
1 2 3 |
|
option选项说明
option httpclose
haproxy会针对客户端的第一条请求的返回添加cookie并返回给客户端,客户端发送后续请求时会发送此cookie到HAProxy,HAProxy会针对此cookie分发到上次处理此请求的服务器上,如果服务器不能忽略此cookie值会影响处理结果。如果避免这种情况配置此选项,防止产生多余的cookie信息。"option httpclose" 和 "no option httpclose" 是两个对立设置, 分别表示启用或禁止消极的HTTP连接关闭
默认的,客户端与服务端的通讯,HAProxy只做分析、日志和分析每个连接的第一个request。如果设置了 "option httpclose" , 则会检查双向的http头是否有"Connection: close",如果没有则自动添加,使每个客户端或服务端在每次传输后,都主动关闭TCP连接,使HTTP传输处于HTTP close模式下。任何 "Connection" 头如果不是"close",都会被移除。
很少会有服务器不正确的忽略掉头,即使收到"Connection: close"也不关闭连接,否则就是不兼容HTTP 1.0浏览器标准。 如果发生这种情况,可以使用"option forceclose",在服务端响应后主动关闭请求连接。选项 "forceclose"还可以及早释放服务连接,而不必等到客户端的应答确认。
这个选项可以设置在frontend或backend上,只要其上可以建立连接。如果同时设置了"option forceclose",那么它比"httpclose"优先。如果同时设置了 "option http-server-close",则会实现"option forceclose"的效果。
option forceclose 启用response后的主动关闭连接 (no option forceclose 表示禁止)
有的HTTP服务器收到"option httpclose"设置的"Connection: close",也不会关闭连接,如果客户端也不关闭,连接会 一直打开,直到超时。这会造成服务器上同一时段内的大量连接,日志中也会显示较高的全局会话时间。
此时,可以使用 "option forceclose",当完成响应时,立即关闭对外的服务通道。该选项隐式打开httpclose选项。需要注意,该选项允许解析完整的request 和 response,所以可以很快关闭至服务器的连接,比httpclose更早释放一些资源。
如果同时启用了"option http-pretend-keepalive",虽然会禁止发送 "Connection: close"头,但是依然会在整个response被接收后,关闭连接。
option http-server-close 启用关闭服务端的HTTP连接 (no option http-server-close 表示禁止)
默认的,客户端与服务端通讯,haproxy 只是分析、记日志,并处理每个连接的第一个请求。该选项设置server端为HTTP 连接关闭模式,并支持客户端为HTTP keep-alive的pipelining模式。提供了最低的客户端延迟和最快的服务端会话重用,以节省服务资源,类似"option forceclose"。还允许无keepalive能力的服务端在keep-alive模式下为客户端提供服务,但是需要符合 RFC2616。需要注意的是,有些服务器遇到"Connection: close" 时并不总是执行关闭,那么keep-alive 则无法使用,解决方法是启用 "option http-pretend-keepalive".
目前,日志无法指明请求是否来自同一会话;日志中的接收日期为前一个请求的结束;请求时间为新请求的等待时间;keep-alive request time 存活请求时间为超时时间,绑定 "timeout http-keep-alive" 或 "timeout http-request"的设置。
这个操作可以设置在frontend或backend上,只要其上可以建立连接。需要注意的是,这个选项可以与 "option httpclose"结合, 但 "option httpclose"优先级更高,结合后基本实现了forceclose的效果。
option http-pretend-keepalive (表示http-假装-长连接, 即haproxy 与服务器是否是 keepalive 的) (如果不开启该配置, 则为no option http-pretend-keepalive )
当声明了 "option http-server-close" 或 "option forceclose", haproxy会在给server的request头中添加 "Connection: close" 。然而有些服务器看到这个头,会返回未知长度的response,并自动避免chunked encoding,其实这是不对的。它会阻止haproxy保持客户端长连接,还会使客户端或缓存接收了未完成的响应,却认为响应结束了。
设置 "option http-pretend-keepalive", haproxy会在服务器端保持长连接,服务端则不会出现前面的问题。当 haproxy 获取了完整的response, 才会以类似forceclose的方式关闭服务端。这样客户端得到一个普通的响应,连接也在服务端被正常关闭。
建议不将其设为默认值,因为大部分服务器会在发送完最后一个包之后更高效的关闭连接,并释放缓存,而且网络上的数据包也会略微降低整体的峰值性能。但是启用该选项,haproxy会略微少做一些工作。所以如果haproxy在整个架构中是个瓶颈,可以启用该操作,以节省CPU。
这个选项可以设置在frontend或backend上,只要其上可以建立连接。这个选项可以与 "option httpclose"结合, 使服务端keepalive,客户端close,但并不建议这样做。
option forwardfor
如果服务器上的应用程序想记录发起请求的客户端的IP地址,需要在HAProxy上配置此选项,这样haproxy会把客户端的IP信息发送给服务器,在HTTP请求中添加"X-Forwarded-For"字段。
option originalto
如果服务器上的应用程序想记录发起请求的原目的IP地址,需要在HAProxy上配置此选项,这样haproxy会添加"X-Original-To"字段。
option dontlognull (即记录空连接)
保证haproxy不记录上级负载均衡发送过来的用于检测状态没有数据的心跳包。
其他option相关设置:
option abortonclose 丢弃由于客户端等待时间过长而关闭连接但仍在haproxy等待队列中的请求
option accept-invalid-http-request 接受无效的http请求,建议关闭(开启可能有安全隐患)
option accept-invalid-http-response 接受无效的response ,建议关闭
option allbackups 应该是后备服务器,如果正常的后端无法使用,就使用这些后备的设备,balance方式还是用原来的,没有优先的选择,常用来提供错误的页面
option checkcache 分析后端response,阻止可缓存的cookie,它对response 进行严格检查,包括"Cache-control", "Pragma" and "Set-cookie" ,查看在客户端代理那边保存是否有风险,如果这个允许的话,符全以下条件 的response 将被允许,其它的将被阻止。
option clitcpka 是否允许客户端发送tcp keepalive 包,这个和http 的keepalive 没有关系
option contstats 允许连续的流量统计更新
option dontlog-normal 开启正常连接的日志
option forceclose 允许关闭session 在后端把response 发送后
option forwardfor [ except
option http-pretend-keepalive 定义是否haproxy要宣布同server keepalive
option http-server-close 是否开启在server 端 connection closing
option http-use-proxy-header 用non-standard Proxy-Connection 替换 connection
option httpchk
option httplog [ clf ] 定制日志格式
option http_proxy 开启http 代理模式,只有最基本的代理功能
option ignore-persist { if | unless }
option independant-streams 启用双向超时处理,如socket 的read 和write
option log-health-checks 记录健康检查日志
option log-separate-errors 对非完全成功的连接改变日志记录等级
option logasap 大传输大文件时可以提前记录日志
option mysql-check mysql 健康检查
option nolinger 清除肮脏连接后开成的tcp 状态及占用的资源,不过并不是强列要求你用这个选项,当然如果你有thousands of FIN_WAIT1 sessions on your system ,那肯定得用了
option originalto [ except
option persist 强制将http请求发往已经down 掉的server
option redispatch 是否允许重新分配在session 失败后, 即serverId对应的服务器挂掉后,强制定向到其他健康的服务器!
option smtpchk smtp 检查;
option socket-stats 允许对单个socket进行统计;
option srvtcpka 是否允许向server 发送keepalive;
option tcpka 是否允许向server和client发送keepalive;
option tcplog 允许记录tcp 连接的状态和时间;
option transparent 允许客户端透明代理;
rate-limit sessions
mode http 所处理的类别 (#7层 http;4层tcp);
mode tcp 所处理的类别 (#7层 http;4层tcp);
stats hide-version 隐藏统计页面上的HAproxy版本信息;
四. 代理配置段常见配置参数
4.1) Balance相关
balance:后端服务器组内的服务器调度算法
语法: balance
balance url_param [check_post]
调度算法:
① roundrobin:基于权重轮询,动态算法, 支持权重的运行时调整,支持慢启动;每个后端backend中最多支持4095个server; haproxy把请求轮流的转发到每一个服务器上,依据每台服务器的权重,此权重会动态调整。这是最常见的默认调度算法的配置。即客户端每一次访问, 都跳转到后端不同的服务器上.
② static-rr:基于权重轮询,静态算法,不支持权重的运行时调整及慢启动;后端主机数量无上限;
③ leastconn:加权最少连接,动态算法,最少连接的后端服务器优先分配接收新连接,相同连接时轮询,推荐在较长会话的场景使用,例如MySQL、 LDAP等,不适合http;
④ first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务器;
⑤ hdr(name):对于每个http请求,此处由
例:hdr(host) hdr(Cookie)
hash类算法:
需配合参数:hash-type
method:
map-based:除权取余法,哈希数据结构是静态数组;
consistent:一致性哈希,哈希数据结构是一棵树;
⑥ source:源地址hash,新连接先按权重分配,后续连接按source分配请求; 如果想让haproxy按照客户端的IP地址进行负载均衡策略,即同一IP地址的所有请求都发送到同一服务器时,需要配置此选项。
⑦ uri:对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,以后派发至某挑出的服务器,适用于后端缓存服务器;
左半部分: /
整个uri: /
⑧ url_param:对用户请求的uri听
Haproxy中balance的算法总结,见下表
4.2) server:定义后端主机相关选项
语法:
server
:服务器地址,支持使用主机名
[:[port]]:端口映射;省略时,表示同bind中绑定的端口
[param*]:server后可加的参数
weight
maxconn
backlog
backup:设定当前server为备用服务器
check:对当前server做健康状态检测,只用于四层检测
注意: httpchk, “smtpchk”, “mysql-check”, “pgsql-check” and “sslhello-chk” 用于定义应用层检测方法
addr :检测时使用的IP地址(检测的不一定是vip)
port :针对此端口进行检测
inter
rise
fall
disabled:标记为不可用
redir
cookie
基于cookie的session sticky的实现
1 2 3 4 5 6 7 8 9 10 11 |
|
4.3) 实现图形化配置页面
stats enable 添加这条参数后会在web页面启用统计页;在frontend段添加stats enable ,重启haproxy。浏览器访问172.18.43.62/haproxy?stats即可。
相关参数:
① stats refresh
若服务器出现故障,默认手动刷新才能才能看到状态的变化,可设置自动刷新
例:添加stats refresh 2s
② stats uri
默认为/haproxy?stats 可自定义uri
例:stats uri /hastas
重启后访问http://172.18.43.62/hastas即可
③ stats hide-version
如上图所示界面会显示haproxy版本信息,若想隐藏版本加上此参数即可
④ stats auth
stats auth ha1:centos1
stats auth ha2:centos2
⑤ stats realm
例:stats realm "haproxy info"
⑥ stats admin { if | unless }
例:stats admin if TRUE
将stats分离出单独语句块,采用内网的6666端口提高访问安全性示例
1 2 3 4 5 6 7 8 9 |
|
访问http://192.168.43.62:6666/status
4.4) default中定义的内容
可以在frontend、backend、listen中分别进行定义,如没有指定将默认default中设置,如:
maxconn
mode { tcp|http|health } 定义haproxy的工作模式(默认http)
tcp:基于layer4实现代理;可代理mysql, pgsql, ssh,ssl等协议,https时使用此模式,默认模式
http:仅当代理协议为http时使用,centos实际默认模式
health:工作为健康状态检查的响应模式,当连接请求到达时回应“OK”后即断开连接,较少使用
TCP模式的健康状态检测示例
1 2 3 4 5 6 |
|
4.5) forwardfor配置
语法 :option forwardfor [ except
在由haproxy发往后端主机的请求报文中添加“X-ForwardedFor”首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP
[ except
[ header
[ if-none ] 如果没有首部才添加首部,如果有使用默认值
默认defaults中有一条配置option forwardfor except 127.0.0.0/8
若想后端日志记录真实请求客户端IP,需更改后端两台服务器配置文件
1 2 3 4 5 |
|
重载客户端httpd服务,浏览器刷新请求。在客户端观看日志即可看到真实请求服务器
1 |
|
4.6) 自定义错误页面
① errorfile
: HTTP status code. 支持200, 400, 403, 408, 500, 502, 503, 504.
例:errorfile 400 /etc/haproxy/errorfiles/400badreq.http
② rrorloc
例:errorloc 503 http://www.magedu.com/error_pages/503.html
4.7) 修改报文首部
① reqadd
例:在frontend中添加 reqadd X-via:\ haproxy1
后端修改httpd.conf中logformat添加%{X-via}i
再次访问日志就会看到是通过哪个调度器调度到本机
② rspadd
示例: rspadd X-Via:\ HAPorxy
③ reqdel
reqidel
从请求报文中删除匹配正则表达式的首部
④ rspdel
rspidel
从响应报文中删除匹配正则表达式的首部
示例: rspidel Server.* 用于隐藏web服务器版本信息
rspadd Server:\ Apache 15.1 结合上例可伪造server信息
4.8) 定义连接超时
① timeout client
② timeout server
③ timeout http-keep-alive
④ timeout http-request
⑤ timeout connect
⑥ timeout client-fin
⑦ timeout server-fin
五. ACL灵活转发详解
acl:访问控制列表(ACL)的使用提供了一个灵活的解决方案来执行内容交换,并且通常基于从请求中提取的内容、响应或任何环境状态进行决策,是haproxy的重要特色。
5.1) 语法
acl
dst 目标IP
dst_port 目标PORT
src 源IP
src_port 源PORT
示例: acl invalid_src src 172.16.100.200
-i 不区分大小写
-m 使用指定的pattern匹配方法
-n 不做DNS解析
-u 强制每个ACL必须唯一ID,否则多个同名ACL或关系
-- 强制flag结束. 当字符串和某个flag相似时使用
[operator]
匹配整数值: eq、 ge、 gt、 le、 lt
匹配字符串:
- exact match (-m str) :字符串必须完全匹配模式
- substring match (-m sub) :在提取的字符串中查找如果包含, ACL将匹配
- prefix match (-m beg) :在提取的字符串首部中查找模式,如果其中任何一个被发现, ACL将匹配
- suffix match (-m end) :将模式与提取字符串的尾部进行比较,如果其中任何一个匹配,则ACL进行匹配
- subdir match (-m dir) :查看提取出来的用斜线分隔(“/”)的字符串, 如果其中任何一个匹配,则ACL进行匹配
- domain match (-m dom) :查找提取的用点(“.”)分隔字符串,如果其中任何一个匹配,则ACL进行匹配
- boolean
- integer or integer range
- IP address / network
- string (exact, substring, suffix, prefix, subdir,domain)
- regular expression
- hex block
5.2) 匹配条件
(1)base : string
返回第一个主机头和请求的路径部分的连接,该请求从第一个斜杠开始,并在问号之前结束,对虚拟主机有用;
base : exact string match #字符串匹配
base_beg : prefix match #前缀匹配
base_dir : subdir match #目录匹配
base_dom : domain match #域名匹配
base_end : suffix match #后缀匹配
base_len : length match #长度
base_reg : regex match #正则
base_sub : substring match #字符串
(2)path : string
提取请求的URL路径,该路径从第一个斜杠开始,并在问号之前结束(无主机部分);
path : exact string match
path_beg : prefix match
path_dir : subdir match
path_dom : domain match
path_end : suffix match
path_len : length match
path_reg : regex match
path_sub : substring match
例:acl adminpath path_beg -i /admin
acl imagefile path_end .jpg .png .bmp
(3)url : string
提取请求中的URL。 一个典型的应用是具有预取能力的缓存,以及需要从数据库聚合多个信息并将它们保存在缓存中的网页门户入口
url : exact string match
url_beg : prefix match
url_dir : subdir match
url_dom : domain match
url_end : suffix match
url_len : length match
url_reg : regex match
url_sub : substring match
(4)req.hdr([
提取在一个HTTP请求报文的首部
hdr([
hdr_beg([
hdr_dir([
hdr_dom([
hdr_end([
hdr_len([
hdr_reg([
hdr_sub([
(5)status : integer
返回在响应报文中的状态码
5.3) acl作为条件时的逻辑关系
- 与:隐式(默认)使用
- 或:使用“or” 或 “||”表示
- 否定:使用“!“ 表示
同一个组名可定义多次
示例:
if invalid_src invalid_port #与关系
if invalid_src || invalid_port #或
if ! invalid_src #非
5.4) 预定义ACL(部分)
5.5) 配置block拒绝访问
语法:block { if | unless }
例1
1 2 3 4 5 6 7 8 |
|
例2(阻止curl访问)
1 2 |
|
5.6) 指定backend组
语法:use_backend
当if/unless一个基于ACL的条件匹配时切换指定backend(可实现动静分离)
例1
1 2 3 4 |
|
例2
例3
1 2 3 4 |
|
5.7) http 7层访问控制
语法:http-request { allow | deny |add-header
对7层请求的访问控制
5.8) tcp4层连接控制
语法:tcp-request connection {accept|reject} [{if | unless}
根据第4层条件对传入连接执行操作
例子
1 2 3 4 5 6 7 8 |
|
5.9) 配置HAProxy支持https协议
① 支持ssl会话;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
crt 后证
为实验方便自签证书方法:
在etc/pki/tls/certs/目录下执行make命令可获得同时包含证书和所有私钥的证书
1 2 |
|
证书和私钥分离的情况可通过重定向获得:cat demo.crt demo.key > demo.pem
② 把80端口的请求重向定443
bind *:80
redirect scheme https if !{ ssl_fc } #注意花括号里面有空格
③ 向后端传递用户请求的协议和端口(frontend或backend)
http_request set-header X-Forwarded-Port %[dst_port]
http_request add-header X-Forwared-Proto https if { ssl_fc }
例子
测试
向后端传递用户请求
修改后端httpd.conf中日志格式即可
六. 基于ACL的动静分离示例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
分享一个小案例
如下的一个haproxy代理需求:
1) 域名跳转
客户端访问http://beijing.kevin.com时,要把请求分发到172.16.51.171:8080、172.16.51.174:8080、172.16.51.178:8080,这三台服务器上。
客户端访问http://anhui.kevin.com时,要把请求分发到web01.kevin.com这台服务器上。
2) IP地址跳转
客户端访问http://172.16.51.171时,要把请求分发到172.16.51.174:80、172.16.51.178:80这两台服务器上。同时还要求客户端每一次访问,都跳转到不同的服务器上。
2.3) 端口跳转
客户端访问http://beijing.kevin.com:8090和http://anhui.kevin.com:8090这两个地址时,要把请求分发到172.16.51.174:8090、172.16.51.178:8090这两台服务器上。
2.4) 默认跳转
如果客户端访问的不是beijing.kevin.com与172.16.51.171,这两个地址的话,要把请求全部分发到172.16.51.178:8080上。
2.5) 多ACL匹配
如果客户端的IP是172.16.51.140,同时访问的是http://172.16.51.171时,要把请求分发到www.anhui.com上。
proxy.cfg配置内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
|
补充下ACL规则的一些说明
ACL(Access Control List)访问控制列表,HAProxy中的ACL的匹配条件和控制条件有许多种,功能很强大,可以通过源地址、源端口、目标地址、目标端口、请求的资源类型、请求的主机等。
haproxy的ACL用于实现基于请求报文的首部、响应报文的内容或其它的环境状态信息来做出转发决策,这大大增强了其配置弹性。其配置法则通常分为两 步,首先去定义ACL,即定义一个测试条件,而后在条件得到满足时执行某特定的动作,如阻止请求或转发至某特定的后端。
定义ACL的语法格式:acl
aclname:自定义acl的名称,必填项,只能是大小写、数字、'-'、'_'、'.'、':' , 也就是说这个是定义ACL名称,区分字符大小写,且其只能包含大小写字母、数字、-(连接线)、_(下划线)、.(点号)和:(冒号);haproxy中,acl可以重名,这可以把多个测试条件定义为一个共同的acl;
criterion:表示检查那些数据或内容,例如USERAGENT这个首部的值. 测试标准,即对什么信息发起测试;测试方式可以由[flags]指定的标志进行调整;而有些测试标准也可以需要为其在
四个最为常用的criterion为:
src:ip 源IP
src_port:integer 源端口
dst:ip 目标IP
dst_port:integer 目标端口
flags:定义控制条件,例如是否区分字符大小写等,flags的可选参数如下:
-i 忽略字符大小写
-m 启用特定的匹配方式,一般不用
-n 禁止DNS反向解析
-u 不允许aclname重复,默认是可以重名的,当两个acl的名称相同时,运算为或机制。
-- 标志符的强制结束标记,在模式中的字符串像标记符时使用;
operator:判断匹配条件,与
若匹配整数值:eq,ge,gt,le,lt
若匹配字符串:
value: 访问控制的具体内容或值。这是acl测试条件支持的值。value的类型如下:
boolean:布尔值
integer or integer range:整数或整数范围. 如1024:65535表示从1024至65535;仅支持使用正整数(如果出现类似小数的标识,其为通常为版本测试),且支持使用的操作符有5个,分别为eq、ge、gt、le和lt;
IP address/network:网络地址
string(exact, substring, suffix, prefix, subdir, domain):字符串. 支持使用“-i”以忽略字符大小写,支持使用“\”进行转义;如果在模式首部出现了-i,可以在其之前使用“--”标志位;
regular expression:正则表达式
hex block
同一个acl中可以指定多个测试条件,这些测试条件需要由逻辑操作符指定其关系。条件间的组合测试关系有三种:“与”(默认即为与操作)、“或”(使用“||”操作符)以及“非”(使用“!”操作符);
常用的测试标准(criteria):
1) be_sess_rate(backend)
用于测试指定的backend上会话创建的速率(即每秒创建的会话数)是否满足指定的条件;常用于在指定backend上的会话速率过高时将用户请求转发至另外的backend,或用于阻止攻击行为。例如:
backend dynamic
mode http
acl being_scanned be_sess_rate gt 50
redirect location /error_pages/denied.html if being_scanned
2) fe_sess_rate(frontend)
用于测试指定的frontend(或当前frontend)上的会话创建速率是否满足指定的条件;常用于为frontend指定一个合理的会话创建速率的 上限以防止服务被滥用。例如下面的例子限定入站邮件速率不能大于50封/秒,所有在此指定范围之外的请求都将被延时50毫秒。
frontend mail
bind :25
mode tcp
maxconn 500
acl too_fast fe_sess_rate ge 50
tcp-request inspect-delay 50ms
tcp-request content accept if ! too_fast
tcp-request content accept if WAIT_END
3) hdr(header)
用于测试请求报文中的所有首部或指定首部是否满足指定的条件;指定首部时,其名称不区分大小写,且在括号“()”中不能有任何多余的空白字符。测试服务器 端的响应报文时可以使用shdr()。例如下面的例子用于测试首部Connection的值是否为close。
hdr(Connection) -i close
4) method
测试HTTP请求报文中使用的方法。
5) path_beg
用于测试请求的URL是否以
acl url_static path_beg -i /static /iilannis /javascript /stylesheets
#url 目录
6) path_end
用于测试请求的URL是否以
acl url_static path_end -i .jpg .gif .png .css .js
#url 结尾文件
7) hdr_beg
用于测试请求报文的指定首部的开头部分是否符合
acl host_static hdr_beg(host) -i img. video. download. ftp.
8) hdr_end
用于测试请求报文的指定首部的结尾部分是否符合
9) hdr_reg
正则匹配
acl bbs hdr_reg(host) -i ^(bbs.test.com|shequ.test.com|forum)
use_backend bbs_pool if bbs or bbs_path #注意 "or"
Haproxy 会话保持 (三种方式)
Haproxy保持客户端session会话同步的三种方式梳理如下:
============第一种方式: 源地址hash(用户IP识别)==========
haroxy 将用户IP经过hash计算后 指定到固定的真实服务器上(类似于nginx 的IP hash 指令)。
缺陷: 当后端一台服务器挂了以后会造成部分session丢失。
配置示例:
1 2 3 4 5 6 |
|
===========第二种方式: cookie 识别 ===========
haproxy 将WEB服务端返回给客户端的cookie中插入haproxy中特定的字符串(或添加前缀)在后端的服务器cookie id。
配置指令例举: cookie SESSION_COOKIE insert indirect nocache
用firebug可以观察到用户的请求头的cookie里 有类似" Cookie jsessionid=0bc588656ca05ecf7588c65f9be214f5;SESSION_COOKIE=app1"
其中SESSION_COOKIE=app1就是haproxy添加的内容。
配置示例:
1 2 3 4 5 6 |
|
cookie参数说明:
cookie
特别注意: rewrite | insert | prefix 这三个参数相互排斥,只能选一!
rewrite: 表示cookie由服务器生成并且haproxy会在其值中注入该服务器的标识符;此关键字不能在HTTP隧道模式下工作。
insert: 表示如果客户端没有cookie信息且有权限访问服务器时,持久性cookie必须通过haproxy穿插在服务器的响应报文中。当服务器收到相同名称的cookie并且没有“preserve(保存)”选项时,将会移除之前已存的cookie信息。因此,insert可视作"rewrite"的升级版。cookie信息仅仅作为会话cookie且不会存到客户端的磁盘上。默认除非加了“indirect(间接)”选项,否则服务器端会看到客户端端发送的cookie信息。由于缓存的影响,最好加上“nocache”或“postonly”选项。
prefix: 表示不依赖专用的cookie做持久性,而是依赖现成的。用在某些特殊的场景,如客户端不支持一个以上的cookie和应用程序需求它。每当服务器建立一个名为
indirect: 指定此选项时,将不会向客户端发送服务器已经处理过请求的且可用的cookie信息。如果服务器设置这样一个cookie本身,它将被删除,除非“保存”选项也设置。在“插入”模式下,将从发送给服务器的请求中删除cookie,使持久机制从应用程序的角度完全透明。
nocache: 当客户端和haproxy间存在缓存时,使用此选项和insert搭配最好,以便确保如果一个cookie需要被插入时,可被缓存的响应会被标记成不可缓存。这很重要,举个例子:如果所有的持久cookie被添加到一个可缓存的主页上,之后所有的客户将从外部高速缓存读取页面并将共享相同的持久性cookie,会造成服务器阻塞。
在LB服务器上配置好HAProxy后,LB服务器将接受用户的所有请求。如果一个用户请求不包含任何cookie,那这个请求将被HAProxy转发到一台可用的WEB服务器。可能是webA,webB,webC或webD。然后HAProxy将把处理这个请求的WEB服务器的cookie值插入到请求响应中。如SERVERID=A。当这个客户端再次访问并在HTTP请求头中带有SERVERID=A,HAProxy将会把它的请求直接转发给webA处理。在请求到达webA之前,cookie将被移除,webA将不会看到这个cookie。如果webA不可用,对应的请求将被转发到其他可用的WEB服务器,相应的cookie值也将被重新设置。
==============第三种方式: 基于session识别 ============
haproxy 将后端服务器产生的session和后端服务器标识存在haproxy中的一张表里。客户端请求时先查询这张表。
配置参数:appsession JSESSIONID len 64 timeout 5h request-learn
配置示例:
1 2 3 4 5 |
|
注意使用事项
1) 如果客户端使用HTTP1.1(keep-alive),只有第一个响应才会被插入cookie,并且HAProxy只会分析每个session的第一个请求。在使用cookie的插入模式下,可能不会造成什么问题,因为HAProxy会立即在第一个响应中插入cookie,同一个session中的所有请求将被转发到同一台服务器上。但是,到达服务器端的请求中的cookie不会被删除,所以这要求后端服务器对来历不明的cookie不作敏感处理。如果不想引起其他的问题,可以使用"option httpclose"参数关掉keep-alive
2) 由于一些原因,一些客户端不能识别多个cookie,并且后端应用已经设置了cookie,如果HAProxy再对响应插入cookie后,这些客户端可能不能识别cookie。这种情况下,可以使用cookie的prefix模式。
3) LB服务器成为整个架构中的瓶颈,如果LB不可用,那么客户端的所有请求都得不到响应。可以使用Keepalived配置HAProxy解决LB单点故障的问题。
4) 在以上配置中后端服务器是看不到客户端的真实IP地址的; 可以使用 forwardfor 参数,它能够在客户端的请求头中增加 X-Forwarded-For 字段; 同时需要配置使用 httpclose 参数,确保每个请求都被重写,而不只是第一个请求被重写。即使用配置下面两个参数来实现.
1 2 |
|
后端Realserver的WEB服务器上的Nginx的日志格式需要增加$http_x_forwarded_for 变量
1 2 3 |
|
5) 在有些情况下,一些用户会将他们的浏览器的cookie功能关闭。这时候可能没法访问WEB服务器的内容。这种情况下,可以使用HAProxy的 source 负载均衡算法替代 roundroubin算法。source 算法可以确保来自同一个IP的所有请求都到达同一台WEB服务器,但是前提是,可用的服务器的数量保持不变。
6) 不要在一个小型网络和代理服务器后面使用source 算法,因为请求分发会不太公平,但是在大型内部网络或互联网上使用source算法,转发效率很好。对于那些具有动态IP地址的客户端,只要它们能够接收cookie,那么请求转发就不会受到影响,因为HAProxy对cookie的处理具有较高优先级。
===========================================================================================
以上总结的指令和参数都是为了设置或定义ACL匹配条件的,即ACL仅仅只是将匹配条件进行分类归纳而不进行处理。若要将定义好的ACL规则做处理,需下面参数来设置:
1) 当符合指定的条件时使用特定的backend,
1 |
|
2) 阻塞一个七层请求满足/不满足某一ACL匹配条件。格式如下
1 |
|
例如
1 2 3 |
|
3) 配置七层的请求访问控制,与block阻塞不同,http-request更灵活,可做黑白名单控制。只能用在mode http中.
1 |
|
4) 配置四层的请求访问控制
1 |
|
例如:
1 2 3 4 5 6 7 8 |
|
=======ACL示例======
要注意到的是acl关键字可用在frontend、listen、backend中,不能用在default中。
例1:设置HAProxy状态页,只允许指定IP访问,设置如下
1 2 3 4 5 6 7 8 |
|
说明只有来源为192.168.29.1的机器才能访问这个haproxy的stats状态, 访问地址假设为http://192.168.29.101:9099/myhaproxy?admin
例2:不适用block,使用http-request来达到例1的效果。
在没有设置访问规则限制时,用IP为192.168.29.104的主机访问stats主页
提示错误401,只需输入账号密码即可访问,方法为
1 |
|
说明IP为29.104的主机可以访问,并无限制。
添加限制后
1 2 3 4 5 6 7 8 |
|
再用IP为29.104的主机访问效果如下
此时错误为403,而29.1的主机是可以访问的(图太大了就省略了),说明ACL控制生效了。
例3: 七层规则匹配
七层ACL规则匹配中,常用的参数是path,它用来做URL规则匹配,path包括以下参数:
path : 精确匹配
path_beg : 匹配字符串开头的所有内容
path_dir : 子路径匹配
path_dom : 域名匹配
path_end : 匹配字符串结尾的所有内容
path_len : 字符串长度匹配
path_reg : 正则表达式匹配
path_sub : 域名子串匹配
下面来举一个使用path的具体例子,选两台主机,安装Nginx并用Nginx虚拟为4台主机,两台用来处理图片请求,两台用来处理文本请求,利用HAProxy负载均衡的ACL控制机制实现,结构图如下:
1) 在192.168.29.102上添加监听8080端口的虚拟主机(安装的是Nginx),修改Nginx配置,在主配置中添加如下信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
2) 在80端口的主机root目录下创建文件static.txt,内容为static 1;在8080端口主机root目录下创建文件static.txt,内容为static 2。重启Nginx服务,并确保能正常访问,如下图
3) 用同样的方法在192.168.29.103上创建分别监听在80和8080端口的虚拟主机,并在根目录下创建图片文件,确保能正常访问,如下图:
4) 在主机192.168.29.101上配置HAProxy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
配置完成后重启HAProxy,分别访问192.168.29.101/image.png和192.168.29.101/static.txt,并刷新,会发现内容会不停变化,如下图
这说明ACL规则培植成功,HAProxy会根据请求的结尾来判断负载均衡规则。
简单总结: 上面举了3个很简单的HAProxy ACL访问控制的例子,虽然例子中的配置很粗糙,但也可以初步领略到HAProxy有着比较智能的负载均衡功能,在后面的博客中我会更深入的介绍HAProxy的细节配置与调优
================Haproxy ACL规则小例==============
1) 按请求的主机头(名)负载
[root@localhost ~]# cat haproxy.cfg
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
|
2) 其它ACL规则
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
use_backend 参数
or 用于匹配多个acl 名称
default_backend 没有满足条件的时候使用默认的后端服务器
========HAProxy 七层层模型下强大的ACL规则配置示例========
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
|
以上haproxy.cfg配置文件的acl控制主要是在frontend里设置:
acl host_a hdr_reg(host) -i ^(www.a.cn|a.cn)
acl host_b hdr_dom(host) -i www.b.cn
acl url_policy url_sub -i buy_sid
use_backend test-proxy-srv-a if host_a
use_backend test-proxy-srv-b if host_b
use_backend test-proxy-srv-c if url_policy
default_backend test-proxy-srv-default
第一个acl控制,当主机为www.a.cn或者a.cn时,规则返回TRUE,对应第一个use_backend 请求访问后端服务器池test-proxy-srv-a
第二个acl控制,当主机为www.b.cn时,规则返回TRUE,对应第二个use_backend请求访问后端服务器池test-proxy-srv-b
第三个acl控制,当请求url路径出现buy_sid 字符串时,规则返回TRUE,对应第三个use_backend请求访问后端服务器池test-proxy-srv-c
当所有规则均不为TRUE时,请求访问默认后端服务器池test-proxy-srv-default
当然acl还有更多的用法,如下:
acl url_static path_end .gif .png .jpg .css .js
acl host_www hdr_beg(host) -i www
acl host_static hdr_beg(host) -i img. video. download. ftp.
use_backend static if host_static || host_www url_static
use_backend www if host_www
default_backend server_cache
第一个acl,通过path_end参数定义请求的url以.gif,.png,.jpg,.css,.js结尾时返回TRUE
第二个acl,通过hdr_beg(host)参数定义如果客户端以www开头的域名发送请求时返回TRUE
第三个acl,也是通过hdr_beg(host)参数定义以img.,video.,download.,ftp.开头域名发送请求返回TRUE
第四行backend,定义了当请求需同时满足host_static与url_static时,或者满足host_www与url_static时请求将发往名为static 的backend
第五行backend,定义了当请求满足host_www规则时,请求发往名为www的backend
第六行backend,定义将用户请求默认调度到名为server-cache的backend
以上就是Haproxy的ACL常用控制用法,基本上可以满足日常负载需求。
========================设置haproxy负载均衡的最大并发连接数=======================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
===========================下面分析一个haproxy的负载均衡配置=============================
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
|
==========================整体总结下Haproxy的参数说明============================
一. Haproxy 配置说明
haproxy的配置段有"global","defaults","listen","frontend"和"backend"等:
global: 配置中的参数为进程级别的参数,且通常与其运行的操作系统有关
defaults: 用于为所有其他配置段提供默认参数,这配置默认配置参数可由下一个"defaults"所重新设定
forntend: 用于定义一系列监听的套接字,这些套接字可以接受客户端请求并与子建立连接
backend: 用于定义一系列"后端"服务器,代理将会将对应客户端的请求转发至这些服务器
listen: 用于定义通过关联"前段"和"后端"一个完整的代理,通常只对TCP流量有用
所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、_(下划线)、.(点号)和:(冒号)。此外,ACL名称会区分大小写.
时间格式一些包含了值得参数表示时间,如超时时长。
这些值一般都以毫秒为单位,但也可以使用其他的时间单位做后缀,如us(微妙,1/10000000秒),ms(毫秒,1/1000秒),s(秒),m(分钟),h(小时),d(天)
二. global 全局配置
chroot: 修改haproxy的工作目录至指定的目录,并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不过需要注意的是确保指定的目录为空目录且任何用户均不能有写权限;
daemon: 让haproxy以守护进程的方式工作于后台,其等同于"-D"选项的功能,当然,也可以在命令行中以"-db"选项将其禁用;
gid: 以指定的GID运行haproxy,建议使用专用于运行haproxy的GID,以避免因权限带来的风险;
group: 同gid,不过这里为指定的组名;
uid: 已指定的UID身份运行haproxy进程;
user: 同uid,但这里使用的为用户名;
log: 定义全局的syslog服务器,最多可以定义两个;
nbproc: 指定启动的haproxy进程个数,只能用于守护进程模式的haproxy;默认为止启动一个进程,鉴于调试困难等多方面的原因,一般只在但进程仅能打开少数文件描述符的场中才使用多进程模式;
pidfile: pid文件的存放位置;
ulimit-n:设定每个进程所能够打开的最大文件描述符,默认情况下其会自动进行计算,因此不建议修改此选项;
node: 定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时;
description: 当前实例的描述信息;
maxconn: 设定每个haproxy进程所接受的最大并发连接数,其等同于命令行选项"-n","ulimit-n"自动计算的结果正式参照从参数设定的;
maxpipes: haproxy使用pipe完成基于内核的tcp报文重组,此选项用于设定每进程所允许使用的最大pipe个数,每个pipe会打开两个文件描述符,因此,"ulimit -n"自动计算的结果会根据需要调大此值,默认为maxcoon/4;
noepoll: 在linux系统上禁用epoll机制;
nokqueue: 在BSE系统上禁用kqueue机制;
nopoll: 禁用poll机制;
nosepoll: 在linux系统上禁用启发式epoll机制;
nosplice: 禁止在linux套接字上使用tcp重组,这会导致更多的recv/send调用,不过,在linux2.6.25-28系列的内核上,tcp重组功能有bug存在;
spread-checks<0..50,in percent>: 在haprorxy后端有着众多服务器的场景中,在紧缺是时间间隔后统一对中服务器进行健康状况检查可能会带来意外问题,此选项用于将检查的时间间隔长度上增加或减少一定的随机时长,为当前检查检测时间的%;
tune.bufsize: 设定buffer的大小,同样的内存条件下,较小的值可以让haproxy有能力接受更多的并发连接,较大的值了可以让某些应用程序使用较大的cookie信息,默认为16384,其可以在编译时修改,不过强烈建议使用默认值;
tune.chksize: 设定检查缓冲区的大小,单位为字节,更大的值有助于在较大的页面中完成基于字符串或模式的文本查找,但也会占用更多的系统资源,不建议修改;
tune.maxaccept: 设定haproxy进程内核调度运行时一次性可以接受的连接的个数,较大的值可以带来较大的吞吐量,默认为单进程模式下为100,多进程模式下为8,设定为-1可以禁止此限制,一般不建议修改;
tune.maxpollevents: 设定一次系统调用可以处理的事件最大数,默认值取决于OS,其至小于200时可介于带宽,但会略微增大网络延迟,但大于200时会降低延迟,但会稍稍增加网络带宽的占用;
tune.maxrewrite: 设定在首部重写或追加而预留的缓存空间,建议使用1024左右的大小,在需要更大的空间时,haproxy会自动增加其值;
tune.rcvbuf.client: 设定内核套接字中客户端接收缓存区的大小,单位为字节,强烈推荐使用默认值;
tune.rcvbuf.server: 设定内核套接字中服务器接收缓存区的大小,单位为字节,强烈推荐使用默认值;
tune.sndbuf.client: 设定内核套接字中客户端发送缓存区的大小,单位为字节,强烈推荐使用默认值;
tune.sndbuf.server: 设定内核套接字中服务器端发送缓存区的大小,单位为字节,强烈推荐使用默认值;
debug: 调试模式,输出启动信息到标准输出;
quiet: 安装模式,启动时无输出;
三. defaults 默认配置
defaults:用于为所有其他配置段提供默认参数,这配置默认配置参数可由下一个"defaults"所重新设定
1) balance
balance
balance url_param [check_post [
定义负载均衡算法,可用于"defaults"、"listen"和"backend"中。
roundrobin:基于权重进行轮询,在服务器的处理时间保持均匀分布时 ,这是最平衡、最公平的算法。此算法是动态的,这表示某权重可以在运行时进行调整,不过,在设计上,每个后端服务器仅能最多支持4128个连接; 即客户端请求每次都转发到不同的节点服务器上;
static-rr:基于权重进行轮询,与roundrobin类似,但是为静态方法,在运行时调整期后端权重不会生效,不过,其在后端服务器连接数上没有限制;
leastconn:新的连接强求笨哦派发至具有最少连接数目的后端服务器,在有这较长会话的场景中推荐使用此算法,如LDAP、SQL等。其并不太适合用于较短会话的应用层协议,如HTTP,此算法是动态的,可以在运行时调整其权重;
source:将请求的源地址进行hash运算,并有后端的服务器的权重总数相处后派发至某匹配的服务器,这可以使得同一个客户端IP的请求始终被派发至某特定的服务器,不过,当服务器权重总数发生变化时,如某服务器宕机或者添加新服务器,许多的请求可能会被派发至与此前请求不同的服务器,常用于负载均衡无cooki功能的基于TCP的协议,默认为动态,不过可以使用hash-type修改此特性;
uri:对URI的左半部分(“问号”标记之前的部分)或整个URI进行hash运算,并由服务器的总权重相除后派发至某匹配的服务器;这可以使得对同一个URI的请求总是派发至某匹配的服务器,除法服务器的权重总数发生了变化,此算法常用于代理缓存或反病毒代理以提高缓存的命中率,需要注意的是,此算法仅应用于HTTP后端服务器场景,其默认为静态算法,不过可以使用hash-type修改此特性;
url_param:通过
har(
2) bind
bind [
3) mode
mode{ tcp|http|health }
设定实例的运行模式或协议,当实现内容交换时,前段和后端必须工作与统一中模式(一般说来时tcp模式),否则将无法启动实例;
tcp: 实例运行于纯tcp模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查,此为默认模式,通常用于SSL、SSH、SMTP等应用;
http:实例运行于http模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC模式兼容的请求都会被拒绝;
health:实例运行于health模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息 ,此模式将用于相应外部组件的监控状态检测请求;目前来讲,此模式已经废弃,因为tcp或http模式中的monitor关键字可完成此类功能;
4) log
log global
log
5) maxconn
maxconn
设定一个前段的最大并发连接数,因此,其不能用于backend区段,对于大型站点来说,可以尽可能提高此值以便让haproxy管理连接队列,从而便面无法应答用户请求。当然,此最大值不能超过“global”段中的定义。此外,需要留心的是,haproxy会为每个连接维持两个缓冲,每个缓存的大小为8KB,在加上其他的数据,每个连接将大约占用17KB的RAM空间,这意味着经过适当优化后 ,有着1GB的可用RAM空间时将维护40000-50000并发连接;
如果为
6) default_backend
default_backend
在没有匹配的“use_backend”规则时为实例指定使用的默认后端,因此,其不可应用于backend区段,在“frontend”和“backend”之间进行内容交换时,通常使用“use-backend”定义其匹配规则,而没有被匹配到的请求将有此参数指定的后端接收;
7) server
server
在后端声明一个server,因此,不能用于defaults和frontend区段。
<:port>:指定将连接请求所发往此服务器时的目标端口,其为可选项,为设定是,将使用客户端请求时的同一相同端口;
[param*]:为此服务器设定的一系列参数:其可以得参数非常多,下面仅说明几个常用的服务器或默认服务器参数:
backup:设定为备用服务器,仅在负载均衡场景中的其他server均不可以启用此server;
check:启动对此server执行监控状态检查,其可以借助于额外的其他参数完成更精细的设定,如:
inter
rise
fall
cookie
maxconn
maxqueue
redir
1 |
|
weight
检查方法:
option httpchk
option httpchk
option httpchk
option httpchk
1 2 3 4 |
|
8) capture request header
capture request header
捕获并记录指定的请求首部最近一次出现时的第一个值,仅能用于“frontend”和“listen”区段,捕获的首部值使用花括号{}括起来后添加进日志中,如果需要捕获多个首部值,他们将以指定的次序出现在日志文件中,并以竖线“|”作为分隔符,不存在的首部记录为空字符串,最长需要捕获的首部包括在虚拟主机环境中使用的“host”、上传请求首部的“Content-length”、快速区别现实用户和网络机器人“User-agent”,已经代理环境中距离请求来源的“X-Forword-For”;
可以捕获的请求首部的个数没有限制,但每个捕获最多能记录64个字符,为了保证同一个frontend中日志格式的统一性,首部捕获仅能在frontend中定义;
9) capture response header
capture response header
捕获并记录响应首部。其格式和要点同捕获的请求首部响应.
10) stats enable
启用基于程序编译时默认设置的统计报告,不能用于"frontend"区段,只要没有额外的其他设定,他们就会使用如下的配置:
- stats uri : /haproxy?stats
- stats realm : "HAProxy Statistics"
- stats auth : no authentication
- stats scope : no restriction
尽管"stats enable"一条就能够启用统计报告,但还是建议设定其他所有的参数,以避免其依赖默认设定而带来非预期后果,下面是一个配置示例:
1 2 3 4 5 6 7 8 9 |
|
11) stats hide-version
启用统计报告并隐藏HAProxy版本报告,不能用于"frontend"区域,默认情况下,统计页面会显示一些有用信息,包括HAProxy的版本号,然后,向所有人公开HAproxy的准确版本号是非常有危险的,因为他能够版主恶意用户快速定位版本的缺陷和漏洞,尽管"stats hide-version"一条就能够启用统计报告,但还是建议设定其他所有的参数,以避免其依赖默认设定而带来非预期后果.
12) stats realm
stats realm
启用统计报告并高精认证领域,不能用于"frontend"区域,haproxy在读取realm是会讲是做一个单词,因此,中间的空白字符都必须使用反斜线进行转移。此参数仅在与"stats auth"配置使用时有意义;
尽管"stats realm"一条就能够启用统计报告,但还是建议设定其他所有的参数,以避免其依赖默认设定而带来非预期.
13) stats scope
stats scope {
启用统计报告并限定报告的区段,不能用于“frontend”区域,当指定此语句时,统计报告将仅显示其列举出区段的报告信息,所有其他区段的信息将被隐藏,如果需要显示多个区段的统计报告,此语句可以定义多次,需要注意的是,区段名称进程仅仅是以字符串比较的方式进行,他不会真检查指定的区段是否真正存在;
尽管“stats scope”一条就能够启用统计报告,但还是建议设定其他所有的参数,以避免其依赖默认设定而带来非预期后果.
14) stats auth
stats auth
启用带认证的统计报告功能并授权一个用户账号,不能用于"frontend"区域;
此语句将给予默认设定启用统计功能报告,并仅允许其定义的用户访问,其也可以定义多次以手段多个用户账号,可以结合"stats realm"参数在提示用户认证是给出一个领域说明信息,在使用非法用户访问统计功能时,其将会响应一个"401 Forbidden"页面,其认证方式为HTTP Basic认证,密码传输会以明文方式进行,因此,配置文件中也使用存储明文方式存储以说明其非保密信息故此不能想用与其他关键性账号的密码。
尽管"stats auth"一条就能够启用统计报告,但还是建议设定其他所有的参数,以避免其依赖默认设定而带来非预期后果.
15) stats admin
atsts admin {if|unless}
在指定的条件满足时启用统计报告页面的管理级别功能,它允许通过web接口启用或禁用服务器,不过,基于安全的角度考虑,统计报告页面应该尽可能为只读的,此外,如果启用了HAproxy的多进程模式,启用此管理级别将会可能导致异常行为;
目前来说,POST请求方法被限制于仅能使用缓冲区减去保留之外的空间,因此,服务器列表不能过长,否则,此请求将无法正常工作,因此,建议一次仅调整少数几个服务器.
16) option httplog
option httplog [clf]
启用记录HTTP请求、会话状态和计时器的功能;
clf:使用CLF格式来代替HAproxy默认的HTTP格式,通常在使用仅支持CLF格式的特定日志分析器时才需要使用此格式;
默认情况下,日志输入格式非常简陋。因为其仅包括源地址、目标地址和实例名称、而"option httplog"参数将会使得日志变得丰富许多,其通常包括但不局限于HTTP请求、连接计时器、会话状态、连接数、捕获的首部及cookie、"frontend"、"backend"及服务器名称。当然也包括源地址和端口号等。
17) option logasap
no option logasap
启用或禁用提前将HTTP请求记入日志,不能用于“frontend”区段。
默认情况下,HTTP请求是在请求结束时进行记录以便能够将其整体输入时长和字节数记入日志,由此,传较大的对象时,其记入日志的市场可能会略有延迟,“option logasap”参数能够在服务器发送complete首部时及时记录日志,只不过,此时将不记录整体传输时长和字节数。此情形下,捕获“Content-Length”响应报文来记录的字节数是以一个较好的选择;
18) option forwardfor
option forwardfor[ except
允许在发往服务器的请求首部中插入"X-Forwarded-For"首部;
if-none: 仅在此首部不存在时才会将其添加至请求报文中;
HAproxy工作与反向代理模式,其发往服务器的请求中的客户端IP均为HAproxy主机的地址而非真正的客户端地址,这会使得服务器的日志记录不了真正的请求来源,"X-Forwarded-For"首部则可用于解决此问题,HAproxy可以向每个房网服务器的请求上添加此首部,并以客户端IP为其value;
需要注意的是: HAproxy工作与隧道模式,其仅检查每一个连接的第一个请求,仅第一个请求报文中被附加此首部,请确保同时使用"option httpclose"、"option forceclose"和"option http-server-close"几个option.
19) errorfile
errorfile
在用户请求不存在的页面时,返回一个页面给客户端而非有haproxy生成的错误代码,可用于所有段中;
: 指定对HTTP的那些状态码发回指定的页面,这里可用的状态码有200、400、403、408、500、502、503和504;
例如:
1 2 3 |
|
20) errorloc和errorloc302
errorloc
errorloc302
请求错误时,返回一个HTTP重定向至某URL的信息,可以用于所有端中;
: 指定对HTTP的那些状态码发回指定的页面,这里可用的状态码有200、400、403、408、500、502、503和504;
需要留意的是: 这两个关键字都会返回302状态码,浙江使得客户端使用同样的HTTP方法获取指定的URL。对于非GET方法获取指定的URL,对于非GET方法的场景(如POST)来说会产生问题,因为返回客户端的URL是不允许使用GET意外的其他方法的,如果的确有这种问题,可以使用errorloc303来返回303状态码给客户端;
21) errorloc303
errorloc303
: 指定对HTTP的那些状态码发回指定的页面,这里可用的状态码有400、403、408、500、502、503和504;
需要注意的是,如果URI之神错误时禅师某特定状态码信息的话,有可能会导致循环定向.
*************** 当你发现自己的才华撑不起野心时,就请安静下来学习吧!***************