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 匹配条件<criterion>进阶
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 <number>:设定每个haproxy进程所能接受的最大并发连接数
maxconnrate <number>:设置每个进程每秒种所能建立的最大连接数量
maxsessrate <number>:设置每个进程每秒种所能建立的最大会话数量
maxsslconn <number>: 每进程支持SSL的最大连接数量
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 [<address>]:<port_range> [, ...] [param*]
示例:
listen http_proxy
bind :80,:443
bind 10.0.0.1:10080,10.0.0.1:10443
4.代理配置段常见配置参数
4.1Balance相关
balance:后端服务器组内的服务器调度算法
语法: balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post]
调度算法:
① roundrobin:基于权重轮询,动态算法, 支持权重的运行时调整,支持慢启动;每个后端backend中最多支持4095个server
server options: weight #
② static-rr:基于权重轮询,静态算法,不支持权重的运行时调整及慢启动;后端主机数量无上限
③ leastconn:加权最少连接,动态算法,最少连接的后端服务器优先分配接收新连接,相同连接时轮询,推荐在较长会话的场景使用,例如MySQL、 LDAP等,不适合http。
④ first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务器。
⑤ hdr(<name>):对于每个http请求,此处由<name>指定的http首部将会被取出做hash计算; 并由服务器总权重相除以后派发至某挑出的服务器; 无有效值的会被轮询调度
例:hdr(host) hdr(Cookie)
⑤ rdp-cookie 远程桌面相关
hash类算法:
需配合参数:hash-type <method> <function> <modifier>
method:
map-based:除权取余法,哈希数据结构是静态数组
consistent:一致性哈希,哈希数据结构是一棵树
⑥ source:源地址hash,新连接先按权重分配,后续连接按source分配请求
⑦ uri:对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,以后派发至某挑出的服务器,适用于后端缓存服务器
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分: /<path>;<params>
整个uri: /<path>;<params>?<query>#<frag>
⑧ url_param:对用户请求的uri听<params>部分中的参数的值(通常为用户ID)作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server。
4.2 server:定义后端主机相关选项
语法:
server <name> <address>[:[port]] [param*]
<name>:服务器在haproxy上的自定义名称;出现在日志及警告信息
<address>:服务器地址,支持使用主机名
[:[port]]:端口映射;省略时,表示同bind中绑定的端口
[param*]:server后可加的参数
weight <weight>:权重,默认为1
maxconn <maxconn>:当前server的最大并发连接数
backlog <backlog>:当server的连接数达到上限后的后援队列长度
backup:设定当前server为备用服务器
check:对当前server做健康状态检测,只用于四层检测
注意: httpchk, “smtpchk”, “mysql-check”, “pgsql-check” and “sslhello-chk” 用于定义应用层检测方法
addr :检测时使用的IP地址(检测的不一定是vip)
port :针对此端口进行检测
inter <delay>:连续两次检测之间的时间间隔,默认单位为毫秒,默认为2000ms
rise <count>:连续多少次检测结果为“成功”才标记服务器为可用;默认为2
fall <count>:连续多少次检测结果为“失败”才标记服务器为不可用;默认为3
disabled:标记为不可用
redir <prefix>:将发往此server的所有GET和HEAD类的请求重定向至指定的URL
cookie <value>:为当前server指定cookie值,实现基于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 <delay>设定自动刷新时间间隔
若服务器出现故障,默认手动刷新才能才能看到状态的变化,可设置自动刷新
例:添加stats refresh 2s
② stats uri <prefix> 自定义stats page uri
默认为/haproxy?stats 可自定义uri
例:stats uri /hastas
重启后访问http://172.18.43.62/hastas即可
③ stats hide-version
如上图所示界面会显示haproxy版本信息,若想隐藏版本加上此参数即可
④ stats auth <user>:<passwd> 认证时的账号和密码,可使用多次。如多个用户定义多行即可,例:
stats auth ha1:centos1
stats auth ha2:centos2
⑤ stats realm <realm> 认证时浏览器弹出对话框的提示信息
例:stats realm "haproxy info"
⑥ stats admin { if | unless } <cond> 启用stats page中的管理功能
例: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 <conns>:为指定的frontend定义其最大并发连接数;默认为3000
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 <network> ] [ header <name> ] [ if-none ]
在由haproxy发往后端主机的请求报文中添加“X-ForwardedFor”首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP
[ except <network> ]:请求报请来自此处指定的网络时不予添加此首部,如haproxy自身所在网络
[ header <name> ]:使用自定义的首部名称,而非“XForwarded-For”
[ 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 <code> <file> 自定义错误页
<code>: HTTP status code. 支持200, 400, 403, 408, 500, 502, 503, 504.
<file>:错误页文件路径
例:errorfile 400 /etc/haproxy/errorfiles/400badreq.http
② rrorloc <code> <url> 相当于errorloc302 <code> <url>,利用302重定向至指URL
例:errorloc 503 http://www.magedu.com/error_pages/503.html
4.7修改报文首部
① reqadd <string> [{if | unless} <cond>] 在请求报文尾部添加指定首部(用于web端区分从哪个调度器发来请求)
例:在frontend中添加 reqadd X-via:\ haproxy1
后端修改httpd.conf中logformat添加%{X-via}i
再次访问日志就会看到是通过哪个调度器调度到本机
② rspadd <string> [{if | unless} <cond>] 在响应报文尾部添加指定首部 (用于haproxy之前的调度器查看用于排错)
示例: rspadd X-Via:\ HAPorxy
③ reqdel <search> [{if | unless} <cond>]
reqidel <search> [{if | unless} <cond>] (ignore case) 不分大小写
从请求报文中删除匹配正则表达式的首部
④ rspdel <search> [{if | unless} <cond>]
rspidel <search> [{if | unless} <cond>] (ignore case) 不分大小写
从响应报文中删除匹配正则表达式的首部
示例: rspidel Server.* 用于隐藏web服务器版本信息
rspadd Server:\ Apache 15.1 结合上例可伪造server信息
4.8 定义连接超时
① timeout client <timeout> 客户端最长空闲连接超时时长 默认单位是毫秒
② timeout server <timeout> 后端服务器最长空闲连接超时时长
③ timeout http-keep-alive <timeout> 持久连接的持久时长
④ timeout http-request <timeout> 一次完整的HTTP请求的最大等待时长
⑤ timeout connect <timeout> 成功连接后端服务器的最大等待时长
⑥ timeout client-fin <timeout> 客户端半连接的空闲时长
⑦ timeout server-fin <timeout> 后端服务器半连接的空闲时长
5. ACL灵活转发详解
acl:访问控制列表(ACL)的使用提供了一个灵活的解决方案来执行内容交换,并且通常基于从请求中提取的内容、响应或任何环境状态进行决策,是haproxy的重要特色。
5.1 语法
acl <aclname> <criterion> [flags] [operator] [<value>]...
<aclname>: ACL名称,可使用字母 数字 : . - _区分字符大小写
<criterion>: 比较的标准和条件
dst 目标IP
dst_port 目标PORT
src 源IP
src_port 源PORT
示例: acl invalid_src src 172.16.100.200
<flags>
-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进行匹配
<value>的类型:
- boolean
- integer or integer range
- IP address / network
- string (exact, substring, suffix, prefix, subdir,domain)
- regular expression
- hex block
5.2 匹配条件<criterion>进阶:
(1)base : string
返回第一个主机头和请求的路径部分的连接,该请求从第一个斜杠开始,并在问号之前结束,对虚拟主机有用
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
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路径,该路径从第一个斜杠开始,并在问号之前结束(无主机部分)
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
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([<name>[,<occ>]]) : string
提取在一个HTTP请求报文的首部
hdr([<name>[,<occ>]]) : exact string match
hdr_beg([<name>[,<occ>]]) : prefix match
hdr_dir([<name>[,<occ>]]) : subdir match
hdr_dom([<name>[,<occ>]]) : domain match
hdr_end([<name>[,<occ>]]) : suffix match
hdr_len([<name>[,<occ>]]) : length match
hdr_reg([<name>[,<occ>]]) : regex match
hdr_sub([<name>[,<occ>]]) : substring match
(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 } <condition> 阻止7层请求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 <backend> [{if | unless} <condition>]
当if/unless一个基于ACL的条件匹配时切换指定backend(可实现动静分离)
例1:
acl imagefile path_end .jpg .png .bmp acl appfile path_end .php use_backend websrvs1 if imagefile 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 <name> <fmt>|set-header <name> <fmt> } [ { if | unless }<condition> ]
对7层请求的访问控制
5.8 tcp4层连接控制
语法:tcp-request connection {accept|reject} [{if | unless} <condition>]
根据第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 /images /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 |
本文出自 “linux运维” 博客,请务必保留此出处http://arm2012.blog.51cto.com/2418467/1978842
原文地址:http://arm2012.blog.51cto.com/2418467/1978842