HAProxy是法国人Willy Tarreau开发的一款可应对客户端10000以上的同时连接的高性能的TCP和
HTTP负载均衡器。由于其丰富强大的功能在国内备受推崇,是目前主流的负载均衡器。本文介绍其功能特性并结合配置实例演示,如有错误敬请赐教。
Haproxy主要工作位置:
1. 支持http反向代理
2. 支持动态程序的反向代理
3. 支持基于数据库的反向代理
Haproxy 程序组成:
程序环境:
安装:yum install haproxy -y
主程序: /usr/sbin/haproxy
配置文件: /etc/haproxy/haproxy.cfg
主配置文件主要结构:1. global 全局配置段 2. proxies代理配置段
索引
1. global:全局配置段配置
1.1 全局日志配置
1.2 性能调整常见参数
2.proxies:代理配置段结构
3.实现简单proxy配置实验
3.1 方法1
3.2 方法2
4.代理配置段常见配置参数
4.1 Balance调度算法相关
4.2 server:定义后端主机相关选项
4.3 实现图形化配置页
4.4 default默认配置中定义的内容
4.5 forwardfor后端记录真实请求配置
4.6 自定义错误页面
4.7 自定义修改报文首部
4.8 自定义连接超时相关配置
5. ACL灵活转发详解
5.1 acl语法
5.2 匹配条件
5.3 acl作为条件时的逻辑关系
5.4 系统预定义ACL(部分)
5.5 配置block拒绝访问
5.6 指定backend组
5.7 http 7层访问控制
5.8 tcp 4层连接控制
5.9 配置HAProxy支持https协议
6. 附实现动静分离实验示例
1. global:全局配置段
1.1 log:全局日志配置
默认发往本机的日志服务器;
(1) 系统默认:log 127.0.0.1 local2
发往远端可添加:log 远端IP local2
(2) 修改本机日志配置文件:
vim /etc/rsyslog.conf $ModLoad imudp #取消注释 $UDPServerRun 514 #取消注释 local2.* /var/log/haproxy.log #新增 |
(3) 远端日志配置(配合前端log配置)
vim /etc/rsyslog.conf local2.* /var/log/haproxy.log #新增 |
1.2 性能调整(依据生产环境适当调整):
maxconn
maxconnrate
maxse***ate
maxsslconn
spread-checks <0..50, in percent> 健康检测延迟时长比建议2-5之间
2.proxies:代理配置段结构
(1). defaults:为frontend, backend, listen提供默认配置
(2). fronted:前端,指定接收客户端连接侦听套接字设置
(3). backend:后端,指定将连接请求转发至后端服务器的相关设置
(4). listen:同时拥有前端和后端,适用于一对一环境
3.实现简单proxy配置:
实验拓扑:
3.1 方法一:
配置 /etc/haproxy/haproxy.cfg :
将frontend段、backend段注释,新建如下配置
frontend http *:80 #均衡器端采用http 协议,监听80端口 default_backend websrvs #引用后端自定义服务器组名websrvs backend websrvs #设定默认后端,自定义名字为websrvs balance roundrobin #轮询方式为加权轮询 server web1 192.168.43.61:80 check #设定后端服务器IP ,并引入健康检查 server web2 192.168.43.63:80 check #设定后端服务器IP ,并引入健康检查 service haproxy start |
在浏览器访问http://172.18.43.62 刷新即可看到轮询效果
3.2 方法2:
上面两段配置也可以配置在一段实现相同功能,配置如下:
listen http bind :80 balance roundrobin server web1 192.168.43.61:80 check server web2 192.168.43.63:80 check |
配置参数 bind:指定一个或多个前端侦听地址和端口
语法: bind []:
示例:
listen http_proxy
bind :80,:443
bind 10.0.0.1:10080,10.0.0.1:10443
4.代理配置段常见配置参数
4.1Balance相关
balance:后端服务器组内的服务器调度算法
语法: balance
balance url_param [check_post]
调度算法:
① roundrobin:基于权重轮询,动态算法, 支持权重的运行时调整,支持慢启动;每个后端backend中最多支持4095个server
server options: weight #
② static-rr:基于权重轮询,静态算法,不支持权重的运行时调整及慢启动;后端主机数量无上限
③ leastconn:加权最少连接,动态算法,最少连接的后端服务器优先分配接收新连接,相同连接时轮询,推荐在较长会话的场景使用,例如MySQL、 LDAP等,不适合http。
④ first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务器。
⑤ hdr(
例:hdr(host) hdr(Cookie)
⑤ rdp-cookie 远程桌面相关
hash类算法:
需配合参数:hash-type
method:
map-based:除权取余法,哈希数据结构是静态数组
consistent:一致性哈希,哈希数据结构是一棵树
⑥ source:源地址hash,新连接先按权重分配,后续连接按source分配请求
⑦ uri:对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,以后派发至某挑出的服务器,适用于后端缓存服务器
左半部分: /
整个uri: /
⑧ url_param:对用户请求的uri听
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的实现:
frontend http bind 172.18.43.62:80 default_backend websrvs backend websrvs balance roundrobin cookie SRV insert nocache #自定义会话添加cookie信息SRV,insert:插入 nocache:不缓存增加保密性 server web1 192.168.43.61:80 check weight 2 cookie srv1 #自定义该server添加cookie信息为srv1 server web2 192.168.43.63:80 check maxconn 5000 cookie srv2 #自定义该server添加cookie信息为srv2 server sorroyserver 192.168.43.62:80 backup |
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端口提高访问安全性示例:
listen admin bind 192.168.43.62:6666 stats enable stats uri /status stats realm "haproxy info" stats auth ha1:centos stats hide-version stats refresh 5s stats admin if TRUE |
从内网访问界面:
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模式的健康状态检测示例:
listen ssh bind :22022 balance leastconn mode tcp server sshsrv1 172.16.100.6:22 check server sshsrv2 172.16.100.7:22 check |
4.5 forwardfor配置
语法 :option forwardfor [ except
在由haproxy发往后端主机的请求报文中添加“X-ForwardedFor”首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP
[ except
[ header
[ if-none ] 如果没有首部才添加首部,如果有使用默认值
默认defaults中有一条配置option forwardfor except 127.0.0.0/8
若想后端日志记录真实请求客户端IP,需更改后端两台服务器配置文件:
vim /etc/httpd/conf/httpd.conf LogFormat "%{x-forwarded-for}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" haformat #添加日志格式 CustomLog logs/access_log haformat #修改记录日志 |
重载客户端httpd服务,浏览器刷新请求。在客户端观看日志即可看到真实请求服务器
tail -f /var/log/httpd/access_log |
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
5. 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 p_w_picpathfile 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(部分)
ACL名称
|
等价于
|
说明
|
TRUE |
always_true |
总是匹配 |
FALSE |
always_false |
从不匹配 |
HTTP_1.1 |
req_ver 1.1 |
匹配HTTP协议1.1 |
HTTP |
req_proto_http |
匹配HTTP协议 |
LOCALHOST
|
src 127.0.0.1/8
|
匹配从localhost来的连接
|
METH_CONNECT
|
method CONNECT
|
匹配HTTP CONNECT方法
|
5.5 配置block拒绝访问
语法:block { if | unless }
例1:
frontend http acl deny_src src 172.18.0.108 #自定义源地址为172.18.0.108的acl组deny_src acl deny_port dst_port 80:100 #自定义目标端口为80到100的acl组deny_port block if deny_src || deny_port #如果属于deny_src组或deny_port组则拒绝访问 block unless deny_src #如果不属于acl组deny_src则拒绝访问 |
例2(阻止curl访问):
acl bad_curl hdr_sub(User-Agent) -i curl block if bad_curl |
5.6 指定backend组
语法:use_backend
当if/unless一个基于ACL的条件匹配时切换指定backend(可实现动静分离)
例1:
acl p_w_picpathfile path_end .jpg .png .bmp acl appfile path_end .php use_backend websrvs1 if p_w_picpathfile use_backend websrvs2 if appfile |
例2:
例3:
acl webhost hdr(host) web.51cto.com acl apphost hdr(host) app.51cto.com use_backend websrvs if webhost use_backend appsrvs if apphost |
5.7 http 7层访问控制
语法:http-request { allow | deny |add-header
对7层请求的访问控制
5.8 tcp4层连接控制
语法:tcp-request connection {accept|reject} [{if | unless}
根据第4层条件对传入连接执行操作
例:
listen ssh bind :22022 balance leastconn acl invalid_src src 172.16.200.2 tcp-request connection reject if invalid_src mode tcp server sshsrv1 172.16.100.6:22 check server sshsrv2 172.16.100.7:22 check backup |
5.9 配置HAProxy支持https协议:
① 支持ssl会话;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
crt 后证书文件为PEM格式,且同时包含证书和所有私钥
为实验方便自签证书方法:
在etc/pki/tls/certs/目录下执行make命令可获得同时包含证书和所有私钥的证书
cd /etc/pki/tls/certs/ make /etc/haproxy/haproxy.pem |
证书和私钥分离的情况可通过重定向获得: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中日志格式即可
6. 附基于ACL的动静分离示例
frontend web *:80 acl url_static path_beg -i /static /p_w_picpaths /javascript /stylesheets acl url_static path_end -i .jpg .gif .png .css .js .html .txt .htm use_backend staticsrvs if url_static default_backend appsrvs backend staticsrvs balance roundrobin server stcsrv1 172.16.100.6:80 check backend appsrvs balance roundrobin server app1 172.16.100.7:80 check server app1 172.16.100.7:8080 check listen stats bind :9091 stats enable stats auth admin:admin stats admin if TRUE |