HAProxy
HAProxy
官网
http://www.haproxy.org
http://www.haproxy.com
HAProxy介绍
HAProxy: 是法国人Willy Tarreau开发的一个开源软件,是一款应对客户端10000以上的同时连接的高性能的TCP和 HTTP负载均衡器。其功能是用来提供基于cookie的持久性, 基于内容的交换,过载保护的高级流量管制,自动故障切换 ,以正则表达式为基础的标题控制运行时间,基于Web的报表,高级日志记录以帮助排除故障的应用或网络及其他功能。
相关概念
代理的作用
- 正向代理,反向代理
- 代理服务器,可以提供缓存功能加速客户端访问,同时可以对缓存数据进行有效性检查
- 内容路由:根据流量以及内容类型将请求转发至特定的服务器
- 转码器:支持压缩功能,将数据以压缩形式发送给客户端
缓存的作用
- 减少访冗余内容传输
- 节省带宽,缓解网络瓶颈
- 降低了对原始服务器的请求压力
- 降低了传输延迟
负载均衡集群:
四层:
lvs, nginx(stream),haproxy(mode tcp)
七层:
http: nginx(http, ngx_http_upstream_module), haproxy(mode http), httpd, ats, perlbal, pound...
HAProxy功能
HAProxy是TCP / HTTP反向代理服务器,尤其适合于高可用性环境
可以针对HTTP请求添加cookie,进行路由后端服务器
可平衡负载至后端服务器,并支持持久连接
支持基于cookie进行调度
支持所有主服务器故障切换至备用服务器
支持专用端口实现监控服务
支持不影响现有连接情况下停止接受新连接请求
可以在双向添加,修改或删除HTTP报文首部
支持基于pattern实现连接请求的访问控制
通过特定的URI为授权用户提供详细的状态信息
版本:1.4 1.5 1.6 1.7 1.8
支持http反向代理
支持动态程序的反向代理
支持基于数据库的反向代理
HAproxy组成
包名:haproxy
程序环境
主程序:/usr/sbin/haproxy
配置文件:/etc/haproxy/haproxy.cfg
Unit file:/usr/lib/systemd/system/haproxy.service
配置文件
haproxy.cfg主要有两部分组成:global,和proxies配置段
global:全局配置段
进程及安全配置相关的参数
性能调整相关参数
Debug参数
proxies:代理配置段
defaults:为frontend, backend, listen提供默认配置
fronted:前端,相当于nginx, server {}
backend:后端,相当于nginx, upstream {}
listen:同时拥有前端和后端,适用于一对一环境
实现简单的HAProxy的代理服务
1)在后端web服务器上
RS1
# yum install httpd # echo RS1 > /var/www/html/index.html # cat /var/www/html/index.html RS1 # systemctl start httpd # ss -ntl
RS2
# yum install httpd # echo RS2 > /var/www/html/index.html # cat /var/www/html/index.html RS2 # systemctl start httpd # ss -ntl
2)在HAPproxy代理服务器上
#yum install haproxy #安装包 修改配置文件 #vim /etc/haproxy/haproxy.cfg #添加内容 frontend main *:80 #设置监听IP端口 default_backend websrvs #代理的后端服务器组名 backend websrvs #定义后端的代理服务器 balance roundrobin #轮询算法 server web1 192.168.130.11:80 check #被代理的后端服务器的IP地址及代理服务的端口号 server web2 192.168.130.8:80 check #systemctl start haproxy
3)在客户端
# curl 172.20.81.10 | http://172.20.81.10
配置文件配置
global配置参数:
#vim /etc/haproxy/haproxy.cfg
global # 全局参数的设置 log 127.0.0.1 local2 # log语法:log <address_1>[max_level_1] # 全局的日志配置,使用log关键字,指定使用127.0.0.1上的syslog服务中的local0日志设备,记录日志等级为info的日志 chroot /var/lib/haproxy #改变当前工作目录 pidfile /var/run/haproxy.pid #当前进程id文件 maxconn 4000 #最大连接数 user haproxy #所属用户 group haproxy #所属组 daemon #以守护进程方式运行haproxy stats socket /var/lib/haproxy/stats #基于本地的文件传输
log (日志)
log:定义全局的syslog服务器;最多可以定义两个;
格式:log <address> [len <length>] <facility> [max level [min level]]
实现日志记录
haproxy配置文件中默认定义了log 127.0.0.1 local2 说明日志将被记录在本机的local2设施中。
#vim /etc/rsyslog.conf # Provides UDP syslog reception $ModLoad imudp #取消注释 $UDPServerRun 514 #取消注释 #Save haproxy log to haproxy.log #添加的内容 local2.* /var/log/haproxy.log #指定设备local2日志存放位置 # systemctl restart rsyslog #重启日志服务 #ss -nul #查看514端口 #curl 172.20.81.10 #访问以下 #tail tail /var/log/haproxy.log #再次查看日志已经有记录了 Jul 10 07:16:36 localhost haproxy[1873]: 172.20.81.11:38770 [10/Jul/2018:07:16:36.126] main websrvs/web1 0/0/0/0/0 200 262 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"
proxies配置参数:
代理配置段:
- defaults <name>
- frontend <name>
- backend <name>
- listen <name>
Frontend段:指定接收客户端连接侦听套接字设置
Backend段:指定将连接请求转发至后端服务器的相关设置
Listen段:指定完整的前后端设置,只对 TCP 有效
proxy 名称:使用字母 数字 - _ . : 并区分字符大小写
#vim /etc/haproxy/haproxy.cfg
defaults mode http #默认的模式mode { tcp|http|health },tcp是4层,http是7层,health只会返回OK log global #应用全局的日志配置 option httplog # 启用日志记录HTTP请求,默认haproxy日志记录是不记录HTTP请求日志 option dontlognull # 启用该项,日志中将不会记录空连接。所谓空连接就是在上游的负载均衡器或者监控系统为了探测该服务是否存活可用时,需要定期的连接或者获取某一固定的组件或页面,或者探测扫描端口是否在监听或开放等动作被称为空连接;官方文档中标注,如果该服务上游没有其他的负载均衡器的话,建议不要使用该参数,因为互联网上的恶意扫描或其他动作就不会被记录下来 option http-server-close #每次请求完毕后主动关闭http通道 option forwardfor except 127.0.0.0/8 #如果服务器上的应用程序想记录发起请求的客户端的IP地址,需要在HAProxy上配置此选项, 这样 HAProxy会把客户端的IP信息发送给服务器,在HTTP请求中添加"X-Forwarded-For"字段。启用X-Forwarded-For,在requests头部插入客户端IP发送给后端的server,使后端server获取到客户端的真实IP。 option redispatch #当使用了cookie时,haproxy将会将其请求的后端服务器的serverID插入到cookie中,以保证会话的SESSION持久性;而此时,如果后端的服务器宕掉了, 但是客户端的cookie是不会刷新的,如果设置此参数,将会将客户的请求强制定向到另外一个后端server上,以保证服务的正常。 retries 3 # 定义连接后端服务器的失败重连次数,连接失败次数超过此值后将会将对应后端服务器标记为不可用 timeout http-request 10s #http请求超时时间 timeout queue 1m #一个请求在队列里的超时时间 timeout connect 10s #连接超时 timeout client 1m #客户端超时 timeout server 1m #服务器端超时 timeout http-keep-alive 10s #设置http-keep-alive的超时时间 timeout check 10s #检测超时 maxconn 3000 #每个进程可用的最大连接数 frontend main *:80 #监听地址为80 acl url_static path_beg -i /static /images /javascript /stylesheets acl url_static path_end -i .jpg .gif .png .css .js use_backend static if url_static default_backend my_webserver #定义一个名为my_app前端部分。此处将对应的请求转发给后端 backend static #使用了静态动态分离(如果url_path匹配 .jpg .gif .png .css .js静态文件则访问此后端) balance roundrobin #负载均衡算法(#banlance roundrobin 轮询,balance source 保存session值,支持static-rr,leastconn,first,uri等参数) server static 127.0.0.1:80 check #静态文件部署在本机(也可以部署在其他机器或者squid缓存服务器) backend my_webserver #定义一个名为my_webserver后端部分。PS:此处my_webserver只是一个自定义名字而已,但是需要与frontend里面配置项default_backend 值相一致 balance roundrobin #负载均衡算法 server web01 172.20.81.10:80 check inter 2000 fall 3 weight 30 #定义的多个后端 server web02 172.20.81.11:80 check inter 2000 fall 3 weight 30 #定义的多个后端 server web03 172.20.81.81:80 check inter 2000 fall 3 weight 30 #定义的多个后端
Balance配置
balance:后端服务器组内的服务器调度算法
balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post]
haproxy中调度算法同样分为动态调度算法和静态调度算法,与nginx调度算法中区分动静态调度算法的概念不同,nginx用能不能根据后端服务器的负载状况进行调度来区分动静态调度算法的差别,而haproxy中则根据该算法支不支持运行时即时生效来区分动静态算法。
调度算法:
roundrobin:基于权重轮询,动态算法,支持权重的运行时调整,支持慢启动;每个后端backend中最多支持4095个
server server options: weight #
static-rr:基于权重轮询,静态算法,不支持权重的运行时调整及慢启动;后端主机数量无上限
leastconn:加权最少连接,动态算法,最少连接的后端服务器优先分配接收新连接,相同连接时轮询,适用于长连接场景,例如 MySQL、LDAP等,不适合http
first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务
source:源地址hash,新连接先按权重分配,后续连接按source分配请求
源地址hash算法: a .将来自同一个的地址请求发往同一个的后端服务器。(静态) 存在的缺点:当后台服务器有一台宕机了,源地址绑定就会无法访问后台的web服务了。无法实现高可用的效果。 b .还有一致性的哈希算法:同nginx的一致性哈希算法相同。(动态) 具体使用那种算法取决于第二个参数:hash-type source map-based:除权取余法,哈希数据结构是静态的数组; source consistent:一致性哈希,哈希数据结构是一个环。
uri:对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,以后派发至某挑出的服务器,适用于后端缓存服务器
动静态取决于hash type
hash-type map-based #静态 consistent #动态
url_param:对用户请求的uri听<params>部分中的参数的值作hash计算, 并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server
动静态取决于hash type
hash-type map-based consistent
hdr(<name>):对于每个http请求,此处由<name>指定的http首部将会被取出做hash计算; 并由服务器总权重相除以后派发至某挑出的服务器;没有有效值的会被轮询调度; 例如对浏览器进行区分,将PC端和移动端进行区分,代理到后台指定的服务器上去。
动静态取决于hash type
hash-type map-based consistent
hdr(Cookie)
rdp-cookie 远程桌面相关
rdp-cookie(<name>)
default_backend <backend>
无use_backend 匹配时,使用默认的backend,用于 frontend中
server
server <name> <address>[:[port]] [param*]
定义后端主机的各服务器及其选项 server <name> <address>[:port] [settings ...] default-server [settings ...]
<name>:服务器在haproxy上的内部名称;出现在日志及警告信息
<address>:服务器地址,支持使用主机名
[:[port]]:端口映射;省略时,表示同bind中绑定的端口
[param*]:参数
check:对当前server做健康状态检测,只用于四层检测
注意:httpchk,“smtpchk”, “mysql-check”, “pgsql-check” and “sslhello-chk” 用于定义应用层检测方法
addr :检测时使用的IP地址
port :针对此端口进行检测
inter <delay>:连续两次检测之间的时间间隔,默认为2000ms
rise <count>:连续多少次检测结果为“成功”才标记服务器为可用 ;默认为2
fall <count>:连续多少次检测结果为“失败”才标记服务器为不可 用;默认为3
cookie <value>:为当前server指定cookie值,实现基于cookie的会话黏性
disabled:标记为不可用,标记到disabled的服务器将下线
redir <prefix>:将发往此server的所有GET和HEAD类的请求重定向至指 定的URL
例:server webser1 172.20.81.10(haproxy的外网) redir http://www.baidu.com
weight <weight>:权重,默认为1
maxconn <maxconn>:当前server的最大并发连接数
backlog <backlog>:当server的连接数达到上限后的后援队列长度
backup:设定当前server为备用服务器
default-server [param*] 为backend中的各server设定默认选项
bind配置
bind:指定一个或多个前端侦听地址和端口
只用于frountend配置段和listen配置段
bind [<address>]:<port_range> [, ...] [param*]
示例:配置监听端口
# vim /etc/haproxy/haproxy.cfg frontend main bind :80,:8080 #使用bind监听多个端口 default_backend websrvs backend websrvs balance roundrobin server web1 192.168.130.11:80 server web2 192.168.130.8:80 weight 3 # systemctl restart haproxy # ss -ntl
maxconn
maxconn <conns>:为指定的frontend定义其最大并发连接数;默认为2000
mode { tcp|http|health }
定义haproxy的工作模式
tcp:基于layer4实现代理;可代理mysql, pgsql, ssh, ssl等协议,https时使用此模式,默认模式
http:仅当代理协议为http时使用,centos实际默认模式
health:工作为健康状态检查的响应模式,当连接请求到达时回应“OK”后即断开连接,较少使用
基于cookie的会话绑定
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
<name>:cookie名称,用于实现持久连接
rewrite:重写
insert:插入
prefix:前缀
基于cookie的session粘滞
# vim /etc/haproxy/haproxy.cfg frontend web *:80 mode http default_backend appsrvs backend appsrvs balance roundrobin option forwardfor cookie WEBSRV insert nocache indirect server app1 192.168.130.10:80 check inter 1000 rise 1 fall 2 maxconn 2000 cookie websrv1 server app2 192.168.130.11:80 check maxconn 1500 cookie websrv2 # curl -b "WEBSRV=websrv1" http://192.168.130.8/ web1 # curl -b "WEBSRV=websrv2" http://192.168.130.8/ web2
统计接口启用相关的参数
stats enable
启用统计页;基于默认的参数启用stats page
- stats uri : /haproxy?stats uri默认值
- stats realm : HAProxy Statistics
- stats auth : no authentication
stats uri <prefix> 自定义stats page uri
stats auth <user>:<passwd> 认证时的账号和密码,可使用多次
stats realm <realm> 认证时的realm
stats hide-version 隐藏版本
stats refresh <delay> 设定自动刷新时间间隔
stats admin { if | unless } <cond> 启用stats page中的管理功能
直接使用此状态页面包括信息较多,为了防止其他人看到可以采取以下方式来避免
a . 通过设定特别的端口号:(不使用默认的端口号)
# vim /etc/haproxy/haproxy.cfg frontend main bind :80,:8080 default_backend websers listen stats *:9527 #定义的特定端口 stats enable backend websers balance roundrobin server web1 192.168.130.11 server web2 192.168.130.8 # systemctl restart haproxy #重启服务 浏览器:http://172.20.81.10:9527/haproxy?stats
b . 通过设定用户登陆的密码和账号来限制其他人的查看
# vim /etc/haproxy/haproxy.cfg frontend main bind :80,:8080 default_backend websers stats enable #stats realm haproxy #此条为描述信息 stats auth admin:centos #用户名admin,密码centos backend websers balance roundrobin server web1 192.168.130.11 server web2 192.168.130.8 # systemctl restart haproxy #重启服务 浏览器:http://172.20.81.10/haproxy?stats
c . 通过自定义的uri路径别名来控制其他人的登陆
# vim /etc/haproxy/haproxy.cfg frontend main bind :80,:8080 default_backend websers stats enable stats uri /var/www/a #自定义的uri的路径名 backend websers balance roundrobin server web1 192.168.130.11 server web2 192.168.130.8 # systemctl restart haproxy #重启服务 浏览器:http://172.20.81.10/haproxy?stats/var/www/a
d.开启状态页面的修改参数的端口
# vim /etc/haproxy/haproxy.cfg frontend main bind :80,:8080 default_backend websers listen stats *:9527 #定义的特定端口 stats enable stats admin if TRUE #打开操作端口 backend websers balance roundrobin server web1 192.168.130.11 server web2 192.168.130.8 # systemctl restart haproxy #重启服务 浏览器:http://172.20.81.10:9527/haproxy?stats
浏览器上进行下面操作
set stats to DRAIN (排干模式):新的用户请求不在接收,老的用户请求继续等待执行完毕。
health: disable checks :禁止做健康状态检测
forwardfor配置
option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
在由haproxy发往后端主机的请求报文中添加“X-ForwardedFor”首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP
[ except <network> ]:请求报请来自此处指定的网络时不予添加此首部,如haproxy自身所在网络
[ header <name> ]:使用自定义的首部名称,而非“XForwarded-For”
[ if-none ] 如果没有首部才添加首部,如果有使用默认值
为指定的MIME类型启用压缩传输功能
compression algo <algorithm> ...:启用http协议的压缩机制,指明压缩算法gzip, deflate
compression type <mime type> ...:指明压缩的MIMI类型
错误页配置
errorfile <code> <file> 自定义错误页
<code>:HTTP status code.
支持200, 400, 403, 408, 500, 502, 503, 504.
<file>:错误页文件路径
示例:
使用haproxy主机本地的文件进行响应
errorfile 400 /etc/haproxy/errorfiles/400badreq.http errorfile 408 /dev/null # workaround Chrome preconnect bug errorfile 403 /etc/haproxy/errorfiles/403forbid.http errorfile 503 /etc/haproxy/errorfiles/503sorry.http
使用url进行响应,响应状态码为302,不适用于GET以外的其他请求方法:
errorloc <code> <url> 相当于errorloc302 <code> <url>,利用302重定向至指URL
errorloc 503 http://www.a.com/error_pages/503.html
修改报文首部
reqadd <string> [{if | unless} <cond>]
在请求报文尾部添加指定首部
rspadd <string> [{if | unless} <cond>]
在响应报文尾部添加指定首部
示例:
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.*
连接超时
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> 后端服务器半连接的空闲时长
ACL
访问控制列表的使用提供了一种灵活的解决方案来执行内容切换,并且通常基于从请求,响应或任何环境状态中提取的内容来做出决策
acl <aclname> <criterion> [flags] [operator] [<value>] ...
aclname:ACL名称必须由大写和小写字母,数字,' - '(短划线),'_'(下划线),'.' 组成。ACL名称区分大小写
value:值
boolean 布尔型 integer or integer range 整数或整数范围 IP address / network IP或网络地址 string (exact精确匹配, substring子串匹配, suffix前缀匹配, prefix后缀匹配,
subdir子路径匹配, domain子域名匹配) 字符串匹配 regular expression 正则表示式匹配 hex block 16进制的块匹配
flags:标志
-i : 忽略字符大小写 -m : 特定的模式 -n : 禁止DNS解析 -u : 要求acl使用唯一的名称
operator:操作符
匹配整数值:eq、ge、gt、le、lt
匹配字符串:
exact match 精确匹配
substring match 子串匹配
prefix match 前缀匹配
suffix match 后缀匹配
subdir match 子路径匹配
domain match 子域名匹配
acl作为条件时的逻辑关系:
if invalid_src invalid_port 或关系 if invalid_src || invalid_port 与关系 if ! invalid_src invalid_port 非invalid_src
criterion:判断标准
dst : 目标ip
dst_port : 目标端口
src : 源ip
src_port : 源端口
检查url的路径
path : 精确匹配
path_beg : 前缀匹配
path_dir : 子串匹配
path_dom : 子域名匹配
path_end : 路径后缀匹配
path_len : 路径长度匹配
path_reg : 路径的正则表达式模式匹配
path_sub : 路径的子字串匹配
检查整个url
url : 精确匹配
url_beg : 前缀匹配
url_dir : 子串匹配
url_dom : 子域名匹配
url_end : 后缀匹配
url_len : 长度匹配
url_reg : 正则表达式匹配
url_sub : 子字串匹配
请求报文的指定头部检查 req.hdr([<name>[,<occ>]]) : string 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
示例:阻止curl访问
frontend web *:80 acl bad_curl hdr_sub(User-Agent) -i curl block if bad_curl default_backend appsrvs
配置HAProxy支持https协议
1)准备ca证书
[root@haproxy ~]# cd /etc/pki/tls/certs/ [root@haproxy certs]# vim Makefile %.key: umask 77 ; \ /usr/bin/openssl genrsa $(KEYLEN) > $@ #将-aes128删除,避免私钥加密 [root@haproxy certs]# make haproxy.crt Country Name (2 letter code) [XX]:CN State or Province Name (full name) []:bj Locality Name (eg, city) [Default City]:bj Organization Name (eg, company) [Default Company Ltd]:magedu Organizational Unit Name (eg, section) []:opt Common Name (eg, your name or your server's hostname) []:www.magedyu.com [root@haproxy certs]# cp haproxy.* /etc/haproxy/ [root@haproxy ~]# cd /etc/haproxy/ [root@haproxy haproxy]# cat haproxy.crt haproxy.key > haproxy.pem
2)配置HAProxy
frontend web *:80 bind *:443 ssl crt /etc/haproxy/haproxy.pem redirect scheme https if !{ ssl_fc } #将80端口跳转到443 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 192.168.130.7:80 check backend appsrvs balance roundrobin server app1 192.168.130.10:80 check server app2 192.168.130.11:80 check