一、haproxy的功能:
HAProxy vs LVS
HAProxy支持tcp和http两种代理模式,而lvs仅支持tcp代理模式
HAProxy相比LVS的使用要简单很多,功能方面也很丰富。当前HAProxy支持两种主要的代理模式;
tcp:仅在客户端和服务器之间转发双向流量。
http:分析协议,并且能通过允许,拒绝,交换,增加,修改或删除请求或者回应里指定内容来控制协议,这种协议要基于特定的规则。
HAProxy vs Nginx
1. HAProxy可以代理任何基于tcp的协议,而不仅仅是http协议,nginx仅支持http、https、mail等协议。
2. HAProxy对于后端服务器的检查可以基于端口也可以基于url,nginx仅对后端服务器的检查仅通过端口。
3. HAProxy对session的保持强与nignx,nginx通过ip_hash来定向客户端ip来访问的后端主机,达到session保持的目的。而haproxy有多种算法来达到session保持的目的:source、uri、url_param、hdr
二、haproxy的安装
yum install haproxy -y
主配置文件:/etc/haproxy/haproxy.cfg
主配置文件详解:
haproxy配置中分成五大部分:
global: 全局配置参数,参数是进程级别的,通常这些参数是与操作系统有关。
defaults: 配置默认参数,这里的默认参数是相对于后面的frontend 、backend、listen组件而言。
frontend: 相当于nginx中的server段定义,是接收客户端发起请求,建立socket监听。可根据规则直接指定具体的后端服务器。
backend: 后端服务器集群配置,相当于nginx的upstream配置段,一个backend对应一个或者多个后端服务器。
listen: 用于建立虚拟主机,是frontend和backend的结合体,可直接取代frontend和backend
1. global 段具体参数说明:
global # 对全局参数的说明
log 127.0.0.1 local2 # 全局的日志配置,使用log关键字,此日志需要借助rsyslog来进行配置,默认等级为info
chroot /var/lib/haproxy # 改变当前工作目录,基于安全性的考虑
pidfile /var/run/haproxy.pid # 当前进程pid文件
maxconn 4000 # 当前进程最大的连接数,很重要的一个参数,后面有详细的讲解。
user haproxy # 启动服务所属用户
group haproxy # 启动服务所属组
daemon # 开启守护进程运行模式
# turn on stats unix socket
stats socket /var/lib/haproxy/stats # haproxy socket文件
注意:在全局参数中,要注意的参数:
maxconn: 启动服务后,haproxy进程的最大连接数,也就是该服务器haproxy支持的最大并发数。
nbproc: 开启进程数,默认配置是开启1个进程,建议开启一个进程。如开启2个进程定义: nbproc 2
2. defaults 段具体参数说明:
defaults # 开始定义 defaults段
mode http # haproxy支持两种工作模式tcp、http,默认配置为http
log global # 应用全局配置的日志
option httplog # 启用日志记录HTTP请求
option dontlognull # 启用该项,日志中将不会记录关于对后端服务器的检测情况。
option http-server-close # 每次请求完毕后主动关闭http通道
option forwardfor except 127.0.0.0/8 # 这里是转发客户端ip地址至后端服务器上。根据测试,无需修改此项,在后端服务器上设置{X-Forwarded-For}i就能实现。
option redispatch # 此项是对backend server内容中的serverID作用的,当backend中定义的server启用了cookie时,haproxy会将请求到的后端服务器的serverID插入到cookie中,以保证session持久性,如果此时后端服务器宕机,但是客户端的cookie是不会刷新的,如果开启了cookie,将会使客户端请求强制定向到另一台后端server上,保证了服务的正常运行。
retries 3 # 定义尝试连接后端服务器的失败次数,尝试3次失败后,后端该服务器将标记为不可用状态
timeout http-request 10s # http请求超时时间
timeout queue 1m # 一个请求在队列里的超时时间
timeout connect 10s # 连接超时时间
timeout client 1m # 客户端超时时间
timeout server 1m # 服务端超时时间
timeout http-keep-alive 10s # http keepalived保持时间
timeout check 10s # 检测超时时间
maxconn 3000 # 每个frontend定义的最大连接数
注意:在defaults中需要注意的参数:
mode: 工作模式
timeout http-keep-alive: http keepalived 超时时间,具体需要测试,一般保持默认
maxconn:defaults中出现的maxconn值是为frontend做限制的。后面有详细的讲解
3. listen、frontend、backend定义段
以下是我自行定义的代码段:
listen stats # 申明定义一个listen段,命名为stats
bind *:1080 # bind设置socket 格式:ip:port
mode http # 指定工作模式
stats refresh 30 # 刷新时间,这里30秒刷新一次
stats enable # 启用haproxy监控状态
stats hide-version # 隐藏haproxy的版本号
stats uri /haproxy?wsd # 设置haproxy监控页的uri,可任意设置
stats auth admin:admin # 验证用户名密码
stats admin if TRUE # 此项是实现haproxy监控页的管理功能的。
注意:此段配置中 stats admin if TRUE 是很重要的。
4. 定义一个frontend 和 backend段
注意:
haproxy 的 backend 同等于 nginx 的 upstream
haproxy 的 frontend 同等于 nginx 的 server
这样说虽然有些牵强,但是对于会使用nginx的童鞋来说,更容易理解
frontend www.test.com # 定一个frontend 段,命名为www.test.com 命名随意。
mode http # 定义工作模式
bind *:8000 # 定义监听地址和端口 格式:ip:port
option forwardfor # 将客户端ip转发到后端真实服务器
use_backend web check # 使用web后端服务器群组,并进行健康检查
backend web # 定义一个backend 段,命名为web,该命名在frontend中 use_backend使用
balance roundrobin # 主机集群的调度算法,此参数很重要,下面详细解释。
# server 定义中可以使用的参数:
# weight -- 调整服务器权重
# check -- 允许对该服务器进行健康检查
# inter -- 设置连续两次健康检查之间的时间,单位为毫秒(ms),默认是2000(ms) = 2秒
# rise -- 指定多少次连续成功的健康检查后,即可认定该服务器处于可操作状态,默认为2次
# fall -- 地址多少次失败的检查后,即认为服务宕机,并标识为不可用状态,默认为3次
# maxconn -- 指定可被送到后端服务器的最大连接并发数
server web1 127.0.0.1:8080 check # 具体定义的后端主机 格式:server 主机名 ip:port check
server web2 127.0.0.1:80 check
[root@localhost haproxy]# service haproxy restart # 重启服务
Stopping haproxy: [ OK ]
Starting haproxy: [ OK ]
[root@localhost haproxy]# curl http://localhost:8000
80
[root@localhost haproxy]# curl http://localhost:8000
8080
通过上面的测试,我们发现成功的代理至后端的服务器上了,并且是通过轮询调度的方式。
在上面的配置中我们也定义了haproxy的状态监控页。通过浏览器尝试访问:
5. 配置文件中的关键字及性能调整相关参数
maxconn 在 global、defaults、frontend、listen、server中都有运用到,在不同的代码段代表的意义也是不同的:
(1) global代码段中maxconn:设置进程的最大连接数,也就是该haproxy总的并发连接数,可进行修改。但是该并发连接受限与系统具体的文件描述符
例:设置global maxconn=123456
修改后可打开haproxy监控页查看到:
(2) defaults段中maxconn:设置默认代理段的最大连接数,该defaluts是设置frontend的连接数,如果frontend中设置了就以frontend中设置的为主,调整后,在监控页中提现:
例:设置defaults maxconn = 1111 frontend 不设置maxconn
(3) listen段中的maxconn:设置该代理的最大连接数,该设置是定义该listen的socket所能接收的最大并发数,如果没有在listen中定义,则以defaults中为准。
例:设置listen maxconn = 2222
(4) server中的maxconn:设置该后台服务的最大连接数
例:设置server中的主机maxconn = 3333
注:对于后端主机的性能,可以分别设置不同的maxconn
总结:listen maxconn + frontend maxconn + server maxconn =< global maxconn
优先级:listen maxconn > defaults maxconn frontend maxconn > defaults maxconn
balance
定义负载均衡算法,可用于 defaults、listen、backend,其作用是将一个连接通过对应的规则重新派发至后端服务器。支持的算法:
(1) roundrobin: 基于权重进行轮叫,在服务器处理时间保持平均分配,这是最常见的负载均衡算法,但是在haproxy中此算法是动态的,这表示其权重可动态调整,每个后端服务器仅能最多并发4128个连接,切记!
(2) static-rr: 基于权重进行轮叫,与roundrobin类似,但是static-rr为静态方法,在运行时,调整权重是不会生效的,不过后端服务器并发数是没有限制的,因此如果要使用haproxy做轮叫一定要修改 balance 为 static-rr 算法
(3) leastconn: 新的连接请求被派发至具有最少连接数目的后端主机,在有较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如http,此算法是动态的,可以运行时调整权重;
(4) source: 将请求的源地址进行hash运算,并由后端服务器的权重总和相除后派发至某匹配的服务器,这可以使得同一个客户端ip的请求始终被派发至特定主机,不过当某台服务器权重发生变化时,如某台后端服务器宕机或新添加了新的机器,许多客户端的请求可能会被派发至与此前请求不同的主机,因此这种算法常用与负载均衡无cookie功能的基于TCP的协议,其默认为静态,但是可以通过hash-type 来修改此特性
(5) uri: 对uri左半部分或整个URI进行hash运算,并由服务器的总权重相除后派发至某匹配的服务器,这可以使得对同一个uri的访问并定向至后端同一台主机,除非服务器的权重总数发生了变化,次算法常用与代理缓存或反病毒代理以提高缓存命中率,需要注意的是,此算法仅应用与HTTP后端服务器场景,其默认为静态算法,不过可以使用hash-type 来修改此特性。
(6) url_param: 通过<argument>为URL指定的参数在每个HTTP GET请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值,通过<argument>为URL指定的参数在每个HTTP GET请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值,此算法可以通过追踪请求中的用户标识进而确保同一个用户ID的请求将被送往同一个特定的服务器,除非服务器的总权重发生了变化;如果某请求中没有出现指定的参数或其没有有效值,则使用轮叫算法对相应请求进行调度;此算法默认为静态的,不过其也可以使用hash-type修改此特性
(7) hdr: 对于每个HTTP请求,通过<name>指定的HTTP首部将会被检索;如果响应的首部没有出现或者没有有效值,则使用轮叫算法对响应的请求进行调度;此算法为静态,可以通过hash-type修改。
(8) rdp-cookie: 远程桌面协议,该算法几乎没有被使用到。
hash-type类型有两种:
hash-type map-based 静态hash 取模法
hash-type consistent 动态hash 一致性hash算法
这里演示两种最长用的算法:static-rr 和 source 算法:
static-rr算法:
frontend http-in
mode http
bind *:8000
#maxconn 678
use_backend web check
backend web
maxconn 777
balance static-rr
server web1 127.0.0.1:80 maxconn 3333 check
server web2 127.0.0.1:8080 maxconn 3333 check
访问结果:
[root@node1 haproxy]# curl http://localhost:8000
<h1>80</h1>
[root@node1 haproxy]# curl http://localhost:8000
<h1>8080</h1>
frontend http-in
mode http
bind *:8000
#maxconn 678
use_backend web check
backend web
maxconn 777
balance static-rr
server web1 127.0.0.1:80 maxconn 3333 check
server web2 127.0.0.1:8080 maxconn 3333 check
访问结果:
[root@node1 haproxy]# curl http://localhost:8000
<h1>80</h1>
[root@node1 haproxy]# curl http://localhost:8000
<h1>8080</h1>
bind 此指令仅能用于frontend和listen区段,用于定义一个或几个监听套接字
格式:ip:port
mode {tcp|http|health}
设定实例的运行模式或协议,当实现内容交换时,前端和后端必须工作在同一种模式(一般来说是http模式),否则无法开启实例。
tcp:实例运行于纯tcp模式,在客户端和服务器端建立一个tcp通道,且不会对7层报文做任何的操作,通常用于ssh、smtp等
http:实例运行于http模式,客户端在转发至后端服务器之前将被深度分析,所有与规则不符合的格式都将被拒绝。
health:实例运行于health模式,其对入站请求仅响应ok信息并关闭连接,且不会记录任何日志,此模式将用于响应外部组件的健康状态检查请求,目前该模式已经被废弃。
hash-type:定义将请求hash映射到后端服务器的方法,其不能在frontend区段,可用方法有:
map-based:静态方法,除模取余法。一旦任何一台主机发生变化将影响到全局session
consistent:一致性hash算法,动态算法。后端服务器主机的变动只能影响到该服务器session区域的变动。
注:虽然consistent很好用,但派发至后端服务器未必达到理想的负载均衡,需要测试对权重进行调整,
因此大多数场景还是推荐使用map-based
三、高阶配置及acl
1. 在haproxy内定义监控backend server 失效了多少台
listen site-stats
bind *:1081
mode http
monitor-uri /site_status # 定义网站检查的uri,用来检查后端主机的socket。正常返回200,不正常返回503
acl site_dead nbsrv(web) lt 2 # 定义网站down时的策略当挂载负载均衡上的指定backend中,有效机器小于2台时,
返回503
monitor fail if site_dead # 当满足策略时返回503
2. acl配置部分
acl server_web hdr_reg(host) -i ^(www.test.com|host.test.com)$
#如果请求的域名满足正则表达式则返回true -i是忽视大小写。
acl server_blog hdr_dom(host) -i blog.test.com
#如果请求的域名满足 blog.test.com返回true -i是忽视大小写。
acl test hdr(host) -i test.com
#如果请求的域名满足test.com返回true -i是忽视大小写。
acl file_req_url_sub -i abc=
#在请求的url中包含abc= ,则此控制策略返回true,否则为false
acl dir_req rul_dir -i allow
#在请求url中存在allow作为部分地址路径,则此控制策略返回true,否则返回false
acl missing_cl hdr_cnt(Content-length) eq 0
#当请求的header中Content-length 等于0时返回true
---acl策略匹配响应---
block if missing_cl
# 当请求header中Content-length等于0阻止请求返回403
block if !file_req || dir_req
#block 表示阻止请求,返回403错误,这里表示如果不满足file_req或者dir_req,则阻止请求 常用acl
use_backend test_web if server_web
# 当满足server_web的策略时使用test_web的backend
use_backend test_blog if server_blog
# 当满足server_blog的策略时使用test_blog的backend
redirect prefix http://a.test.com code 301 if test
# 当访问a.test.com时,用http301跳转到http://127.0.0.1:8888
defalt_backend server_bbs
#以上都不满足的时候使用默认server_bbs的backend
完整的范例配置:
#---------------------------------------------------------------------
# Example configuration for a possible web application. See the
# full configuration options online.
#
# http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
# to have these messages end up in /var/log/haproxy.log you will
# need to:
#
# 1) configure syslog to accept network log events. This is done
# by adding the '-r' option to the SYSLOGD_OPTIONS in
# /etc/sysconfig/syslog
#
# 2) configure local2 events to go to the /var/log/haproxy.log
# file. A line like the following can be added to
# /etc/sysconfig/syslog
#
# local2.* /var/log/haproxy.log
#
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 3000
listen stats
bind *:1080
mode http
stats refresh 30
stats enable
stats hide-version
stats uri /haproxy?wsd
stats auth admin:admin
stats admin if TRUE
listen site-stats
bind *:1081
mode http
monitor-uri /site_status
acl site_dead nbsrv(test_web) lt 1
acl site_dead nbsrv(server_blog) lt 1
acl site_dead nbsrv(test_bbs) lt 1
monitor fail if site_dead
frontend http_80_in
mode http
bind *:8000
option forwardfor
# acl
acl server_web hdr_reg(host) -i ^(www.test.cn|host.test.cn)
acl server_blog hdr_dom(host) -i blog.test.cn
acl test hdr(host) -i test.cn
acl file_req url_sub -i abc=
acl dir_req url_dir -i allow
acl missing_cl hdr_cnt(Content-length) eq 0
# acl 匹配
#block if missing_cl
#block if !file_req || dir_req
use_backend test_web if server_web
use_backend server_blog if server_blog
#redirect prefix http://a.test.cn code 301 if test_web
default_backend test_bbs
backend test_web
mode http
balance static-rr
#cookie SERVERID
option httpchk GET /index.html
server web1 127.0.0.1:80 check inter 1500 rise 3 fall 3 weight 1
server web2 127.0.0.1:81 check inter 1500 rise 3 fall 3 weight 1
backend server_blog
mode http
balance static-rr
cookie SERVERID
option httpchk GET /index.html
server blog1 127.0.0.1:90 cookie blog1 check inter 1500 rise 3 fall 3 weight 1
server blog2 127.0.0.1:91 cookie blog2 check inter 1500 rise 3 fall 3 weight 2
backend test_bbs
mode http
balance static-rr
cookie SERVERID
option httpchk GET /index.html
server bbs1 127.0.0.1:100 cookie bbs1 check inter 1500 rise 3 fall 3 weight 1
server bbs2 127.0.0.1:101 cookie bbs2 check inter 1500 rise 3 fall 3 weight 2
测试结果:
[root@localhost haproxy]# echo "127.0.0.1 www.test.cn host.test.cn" >> /etc/hosts
[root@localhost haproxy]# curl http://www.test.cn:8000
test_web1:80
[root@localhost haproxy]# curl http://www.test.cn:8000
test_web2:81
[root@localhost haproxy]# curl http://host.test.cn:8000
test_web1:80
[root@localhost haproxy]# curl http://host.test.cn:8000
test_web2:81