HAProxy
一、HAProxy简介
HAProxy是一个使用C语言编写的自由及开放源代码软件,其提供高可用性、负载均衡,以及基于TCP和HTTP的应用程序代理。
功能:
- 根据静态分配的cookie路由HTTP请求
- 在通过使用HTTP cookie确保服务器持久性的同时,在多个服务器之间传播负载
- 在主服务器发生故障时切换到备份服务器
- 接受专用于服务监控的特殊端口的连接
- 停止接受连接而不破坏现有连接
- 在两个方向上添加,修改和删除HTTP标头
- 阻止匹配特定模式的请求
- 从应用程序拦截的URI向已通过身份验证的用户报告详细状态
# yum install haproxy -y
主程序:/usr/sbin/haproxy
配置文件:/etc/haproxy/haproxy.cfg
启动服务:# systemctl start haproxy.service
简单配置示例:实现调度功能
frontend web #前端,相当于nginx, server {}
bind *:80 #监听于80端口
default_backend websrvs #指定后端
backend websrvs #后端,相当于nginx, upstream {}
balance roundrobin #调度算法,轮调
server srv1 192.168.0.9:80 check #后端server,并做健康检查
server srv2 192.168.0.10:80 check
二、全局(global)配置段参数
1、日志记录
定义全局的syslog服务器;最多可以定义两个
log <address> [len <length>] <facility> [max level [min level]]
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
log 127.0.0.1 local2
[root@haproxy ~]# systemctl restart haproxy
[root@haproxy ~]# vim /etc/rsyslog.conf
#### MODULES ####
$ModLoad imudp
$UDPServerRun 514
#### RULES ####
# Save haproxy log to haproxy.log
local2.* /var/log/haproxy.log
[root@haproxy ~]# systemctl restart rsyslog
2、性能调整相关参数
nbproc <number>:要启动的haproxy的进程数量
maxconn <number>:设定每个haproxy进程所能接受的最大并发连接数
总体的并发连接数:nbproc * maxconn
ulimit-n <number>:每个haproxy进程可打开的最大文件数
maxconnrate <number>:每个进程每秒种所能创建的最大连接数量
maxsessrate <number>:每个进程每秒所能创建的最大会话数量
maxsslconn <number>:设定每个haproxy进程所能接受的ssl的最大并发连接数
默认配置:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy #虚根
pidfile /var/run/haproxy.pid
maxconn 4000 #每个haproxy进程最大并发连接数,默认4000
user haproxy #以haproxy的身份运行
group haproxy
daemon
stats socket /var/lib/haproxy/stats #打开本机socket文件实现本地通信
三、代理配置段
- defaults <name> #默认配置段
- frontend <name> #前端配置段
- backend <name> #后端配置段
- listen <name>
name:所有代理名称必须由大写和小写字母,数字,'-','_','.'组成。
-
default_backend <backend> 设定默认的backend,用于frontend中;
-
default-server [param*] 为backend中的各server设定默认选项;
1、bind
在前端定义一个或多个侦听地址或端口
bind [<address>]:<port_range> [,...] [param*]
bind *:80,*:443
bind 192.168.0.8:80,192.168.0.8:8080
bind /var/run/ssl-frontend.sock user root mode 600 accept-proxy
2、balance
后端服务器组内的服务器调度算法
balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post]
-
roundrobin:轮调,动态算法:支持权重的运行时调整,支持慢启动;每个后端中最多支持4095个server
-
static-rr:静态轮调,静态算法:不支持权重的运行时调整及慢启动;后端主机数量无上限
-
leastconn:最少连接数,推荐使用在具有较长会话的场景中,例如MySQL、LDAP等
-
first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务
-
source:源地址hash
-
uri:对URI的左半部分做hash计算,并由服务器总权重相除以后派发至某挑出的服务器
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分:/<path>;<params>
整个uri:/<path>;<params>?<query>#<frag>
- url_param
对用户请求的uri的<params>部分中的参数的值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server
- hdr(<name>)
对于每个http请求,此处由<name>指定的http首部将会被取出做hash计算; 并由服务器总权重相除以后派发至某挑出的服务器;没有有效值的会被轮询调度
- rdp-cookie(<name>)
3、hash-type
hash-type <method> <function> <modifier>
- map-based:除权取余法,哈希数据结构是静态的数组
- consistent:一致性哈希,哈希数据结构是一个
4、server
定义后端主机的各服务器及其选项
server <name> <address>[:[port]] [param*]
- name:服务器在haproxy上的内部名称
- address:服务器地址,支持使用主机名
- port:端口映射;省略时,表示同bind中绑定的端口
- param*:参数
-
maxconn <maxconn>:当前server的最大并发连接数
-
backlog <backlog>:当前server的连接数达到上限后的后援队列长度
-
backup:设定当前server为备用服务器
-
disabled:标记为不可用
-
check:对当前server做健康状态检测
- addr :检测时使用的IP地址
- port :针对此端口进行检测
- inter <delay>:连续两次检测之间的时间间隔,默认为2000ms
- rise <count>:连续多少次检测结果为“成功”才标记服务器为可用;默认为2
- fall <count>:连续多少次检测结果为“失败”才标记服务器为不可用;默认为3
-
cookie <value>:为当前server指定其cookie值,用于实现基于cookie的会话黏性
-
on-error <mode>:后端服务故障时的行动策略
- fastinter:强迫快速
- fail-check:快速失败,快速测试;有故障则离线,没有问题上线,默认策略
- sudden-death:模拟一个致命的失败健康检查,另一个失败的检查将标记服务器关闭,强制fastinter
- mark-down:立即标记服务器并强制执行fastinter
-
redir <prefix>:将发往此server的所有GET和HEAD类的请求重定向至指定的URL
-
weight <weight>:权重,默认为1
-
5、option httpchk
定义基于http协议的7层健康状态检测机制
option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>
http-check expect [!] <match> <pattern>
用于定义应用层检测方法:
- httpchk:检测httpd服务的健康状态
option httpchk GET /test.html
6、maxconn
为指定的frontend定义其最大并发连接数;默认为2000
7、mode
mode { tcp|http|health } :定义haproxy的工作模式
- tcp:基于layer4实现代理;可代理mysql, pgsql, ssh, ssl等协议;
- http:仅当代理的协议为http时使用;
- health:工作为健康状态检查的响应模式,当连接请求到达时回应“OK”后即断开连接;
8、cookie
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
- name:修改或插入的cookie的名称,以便带来持久性
- rewirte:重写
- insert:插入
- prefix:前缀
基于cookie的调度配置示例:
frontend web
bind *:80
default_backend websrvs
backend websrvs
balance roundrobin
cookie WEBSRV insert nocache indirect
server srv1 192.168.0.9:80 check inter 1000 rise 1 fall 2 maxconn 2000
cookie web1
server srv2 192.168.0.10:80 check maxconn 1500 cookie web2
9、option forwardfor
option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
在由haproxy发往后端主机的请求报文中添加“X-Forwarded-For”首部,其值前端客户端的地址;用于向后端主发送真实的客户端IP
- [ except <network> ]:请求报请来自此处指定的网络时不予添加此首部
- [ header <name> ]:使用自定义的首部名称,而非“X-Forwarded-For”
10、errorfile 和 errorloc
errorfile <code> <file>
errorloc <code> <url>
errorloc302 <code> <url>
- code:HTTP状态代码。 目前HAProxy能够支持的代码:200, 400, 403, 408, 500, 502, 503, and 504
- file:指定包含完整HTTP响应的文件
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
errorfile 408 /dev/null #解决方法Chrome预连接错误
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
11、修改报文头部
reqadd <string> [{if | unless} <cond>] 在HTTP请求的末尾添加标头
rspadd <string> [{if | unless} <cond>] 在HTTP响应的末尾添加标头
reqdel <search> [{if | unless} <cond>] 删除与HTTP请求中的正则表达式匹配的所有标头
reqidel <search> [{if | unless} <cond>] (ignore case)
rspdel <search> [{if | unless} <cond>] 删除与HTTP响应中的正则表达式匹配的所有标头
rspidel <search> [{if | unless} <cond>] (ignore case)
rspidel Server.* #删除响应报文中的Server字段信息
12、连接超时时长
timeout client <timeout> 面向客户端侧的超时时间,默认单位是毫秒
timeout server <timeout> 面向服务器侧的超时时间
timeout http-keep-alive <timeout> 持久连接的持久时长
timeout http-request <timeout> 等待客户端传完的请求报文的超时时长
timeout connect <timeout> 向后端服务器发起连接请求时的超时时长
timeout client-fin <timeout> 设置客户端一侧的半关闭连接超时时长
timeout server-fin <timeout> 设置服务器一侧的半关闭连接超时时长
13、访问控制
满足条件时拒绝请求:
block { if | unless } <condition>
示例:当源地址为172.16.200.2,则拒绝请求,并返回错误页
acl invalid_src src 172.16.200.2
block if invalid_src
errorfile 403 /var/www/error.html
根据http请求包控制:
http-request { allow | deny } [ { if | unless } <condition> ]
根据tcp连接控制:
tcp-request connection {accept|reject} [{if | unless} <condition>]
示例:拒绝192.168.0.7的ssh访问
acl invalid_src src 192.168.0.7
tcp-request connection reject if invalid_src
14、use_backend
当符合指定的条件时使用特定的backend,可以实现条件式调度
use_backend <backend> [{if | unless} <condition>]
六、统计接口
- stats enable:启用统计页;基于默认的参数启用stats page
stats uri : /haproxy?stats
stats realm : "HAProxy Statistics"
stats auth : no authentication
stats scope : no restriction
- stats auth <user>:<passwd>:认证时的账号和密码,可使用多次
- stats realm <realm>:认证时的realm
- stats uri <prefix>:自定义stats page uri
- stats refresh <delay>:设定自动刷新时间间隔
- stats admin { if | unless } <cond>:启用stats page中的管理功能
配置参数示例:
listen stats
bind :8080
stats realm "HAProxy Stats Page"
stats auth admin:adminpass
stats admin if TRUE
访问:http://192.168.0.8:8080/haproxy?stats
进入管理页
七、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
示例:实现动静分离
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 192.168.0.9:80 check
backend appsrvs
balance roundrobin
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
八、配置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]:dongfei.com
Organizational Unit Name (eg, section) []:opt
Common Name (eg, your name or your server's hostname) []:www.dongfei.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.0.9:80 check
backend appsrvs
balance roundrobin
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
九、常用功能的实现
1)压缩
frontend web *:80
default_backend appsrvs
compression algo gzip
compression type text/html text/plain
backend appsrvs
balance roundrobin
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
2)stats page
listen stats
bind :8080
stats realm "HAProxy Stats Page"
stats auth admin:adminpass #认证用户:密码
stats admin if TRUE
访问:http://192.168.0.8:8080/haproxy?stats进入状态管理页
3)自定义错误页
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend web *:80
default_backend appsrvs
acl bad_guy src 192.168.0.7
block if bad_guy
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
backend appsrvs
balance roundrobin
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
[root@haproxy ~]# mkdir /etc/haproxy/errorfiles/ -p
[root@haproxy ~]# echo 'forbid' >/etc/haproxy/errorfiles/403forbid.http
[root@haproxy ~]# systemctl restart haproxy
[root@client ~]# curl http://192.168.0.8/
forbid
4)访问控制
listen stats
bind :8080
stats realm "HAProxy Stats Page"
stats auth admin:adminpass
stats admin if TRUE
acl admin_client src 192.168.0.254
block unless admin_client #只允许192.168.0.254访问状态管理页
5)日志功能
调度器中配置
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
backend appsrvs
balance roundrobin
option forwardfor
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
[root@haproxy haproxy]# systemctl restart haproxy.service
后端服务器配置(Apache)
[root@web2 ~]# vim /etc/httpd/conf/httpd.conf
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent
}i\"" combined #改变日志记录方式
[root@web2 ~]# systemctl restart httpd
[root@web2 ~]# tail -f /var/log/httpd/access_log
6)基于cookie的session粘滞
[root@haproxy ~]# 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.0.10:80 check inter 1000 rise 1 fall 2 maxconn 2000 cookie websrv1
server app2 192.168.0.11:80 check maxconn 1500 cookie websrv2
[root@client ~]# curl -b "WEBSRV=websrv1" http://192.168.0.8/
web1
[root@client ~]# curl -b "WEBSRV=websrv2" http://192.168.0.8/
web2
7)后端主机的健康状态检测
backend appsrvs
balance roundrobin
option httpchk GET /test.html
server app1 192.168.0.10:80 check
server app2 192.168.0.11:80 check
8)请求和响应报文首部的操纵:替换响应报文的Server字段信息
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend web *:80
mode http
rspidel ^Server:.*
rspadd Server:\ Apache\ or\ Nginx
default_backend appsrvs
[root@client ~]# curl -I http://192.168.0.8/
Server: Apache or Nginx #掩人耳目
感谢阅读!