HAProxy简介
HAProxy是免费、极速且可靠的用于为TCP和基于HTTP应用程序提供高可用、负载均衡和代理服务的解决方案,尤其适用于高负载且需要持久连接或7层处理机制的web站点。HAProxy还可以将后端的服务器与网络隔离,起到保护后端服务器的作用。HAProxy的负载均衡能力虽不如LVS,但也是相当不错,而且由于其工作在7层,可以对http请求报文做深入分析,按照自己的需要将报文转发至后端不同的服务器(例如动静分离),这一点工作在4层的LVS无法完成。
安装配置HAproxy
HAProxy已经集成在base源中,可直接通过yum下载。
[root@node1 ~]# yum install haproxy
当然也可以去官网直接下载源码编译安装。
/etc/haproxy/haproxy.cfg为haproxy的主配置文件,里面包括全局配置段(global settings)和代理配置段(proxies)。
global settings:主要用于定义haproxy进程管理安全及性能相关的参数
proxies:代理相关的配置可以有如下几个配置端组成。
- defaults
- frontend
- backend
- listen
HAproxy的工作模式:
HAProxy的工作模式一般有两种:tcp模式和http模式。
tcp模式:实例运行于TCP模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查,只能以简单模式工作。此为默认模式,通常用于SSL、SSH、SMTP等应用。
http模式:实例运行于HTTP模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC格式兼容的请求都会被拒绝。
当实现内容交换时,前端和后端必须工作于同一种模式(一般都是HTTP模式),否则将无法启动实例。工作模式可通过mode参数在default,frontend,listen,backend中实现定义。
mode {tcp|http}
下面介绍一些HAproxy的常见用法。
应用实例
基于HAProxy实现负载均衡
在backend段或listen段中通过server定义后端节点。
格式:server
[param*]:为此服务器设定的一系参数。其可用的参数很多,以下为常用参数。
服务器参数:
backup:设定为备用服务器,仅在负载均衡场景中的其它server均不可用于启用此server;
maxconn
maxqueue
observe
redir
weight
定义负载均衡的算法,算法的定义除了listen段和backend段中也可以放在defaults段中,定义格式如下:
balance
balance url_param [check_post [
常见的调度算法有:
roundrobin:基于权重进行轮询,此算法是动态的,其权重可以在运行时进行调整。
static-rr:基于权重进行轮询,与roundrobin类似,但是为静态方法,在运行时调整其服务器权重不会生效。
leastconn:新的连接请求被派发至具有最少连接数目的后端服务器,动态算法,适用于较长时间会话的场景。
source:将请求的源地址进行hash运算,并与后端服务器的总权重作取模运算后调度至某台服务器;同一IP地址的请求将始终被调度至某特定的服务器,静态算法,可以使用hash-type修改此特性;
uri:对URI的左半部分(“?”之前的部分)或整个URI进行hash运算,并与后端服务器的总权重作取模运算后调度至某台服务器;同一URI的请求将始终被调度至某特定的服务器,静态算法,可以使用hash-type修改此特性;
hdr(
前端代理服务器上配置示例(其余为默认配置):
#--------------------------------------------------------------------- # main frontend which proxys to the backends #--------------------------------------------------------------------- frontend service *:80 default_backend app #--------------------------------------------------------------------- # static backend for serving up p_w_picpaths, stylesheets and such #--------------------------------------------------------------------- backend app balance roundrobin server app1 192.168.2.7:80 maxconn 3000 weight 2 server app2 192.168.2.18:80 maxconn 3000 weight 1 server app3 127.0.0.1:8080 backup
在app1(192.168.2.7)上配置测试页面:
[root@node1 ~]# vim /web/index.htmlserver node1
在app1(192.168.2.18)上:
[root@node2 ~]# vim /web/index.htmlserver node2
在代理服务器上有两个接口:192.168.1.116(面向客户端),192.168.2.11。配置完成后启动haproxy服务。后端节点上启动nginx服务。
已实现轮询访问。
在上述的算法中涉及到hash运算,hash-type参数可定义hash的运算方式。格式如下:
格式:hash-type
map-based:静态方法,在线调整服务器权重不能立即生效。hash表是一个包含了所有在线服务器的静态数组。简而言之,通过这种运算方式将请求调度至后端的某台服务器,当后端的服务器放生变动时(如某台服务器宕机或新添加了一台服务器),大部分的连接将会被重新调度至一个与之前不同的服务器上。
consistent:动态发放,支持在线调整服务器权重。hash表是一个由各服务器填充而成的树状结构,使用此算法调度,当后端的服务器发生变动时,大分布的连接将依旧被调度至原本的服务器上。
默认方式为map-based,可应用于大部分场景。但是若后端的服务器为缓存服务器,使用默认方式,当后端的服务器调整时,将导致缓存无法命中,从而影响系统的性能。推荐的配置方式:
backendbalance uri hash-type consistent server .... server ...
对后端服务器健康状况的检测
check为server的参数,可启动对此server执行健康状态的检测。check借助其额外的参数可实现更精细的监测机制。
inter
rise
fall
配置示例:
backend app balance roundrobin server app1 192.168.2.7:80 maxconn 3000 weight 2 check inter 1 rise 1 fall 2 server app2 192.168.2.18:80 maxconn 3000 weight 1 check inter 1 rise 1 fall 2 server app3 127.0.0.1:8080 backup
state页面
启用统计报告,通过state页面可查看到各服务器的状态及其相关信息。关于state的配置建议单独定义一个listen。
listen stats mode http bind 192.168.1.116:1080 #监听端口 stats enable #启用state功能 stats scope app #统计报告的报告区段,不启动这项则报告所有区段 stats hide-version #隐藏HAProxy版本号 stats uri /haproxyadmin?stats #state页面的访问路径 stats realm Haproxy\ Statistics #认证时提示信息 stats auth baby:baby #认证的账号密码 stats admin if TRUE #启用管理功能
配置完成后重启haproxy服务。然后访问定义的路径:http://192.168.1.116:1080/haproxyadmin?stats。首先完成认证。
基于前面配置完成的健康状态检测,现在停止其中一台后端服务器的nginx服务。
[root@node1 web]# service nginx stop Stopping nginx: [ OK ]
红色表示服务不在线,若停止所有后端服务器的服务,则会访问定义为backup的server(127.0.0.1上的sorry页面)。
基于cookie的session绑定
在响应报文中添加cookie信息,下一次的客户请求会带上这个cookie信息,服务器端根据cookie将请求始终定向至后端的某一台服务器。可用于保持session会话。
cookie配置格式:
cookie
配置示例:
backend app balance roundrobin cookie babyserver insert nocache indirect server app1 192.168.2.17:80 check port 80 cookie app1 server app2 192.168.2.16:80 check port 80 cookie app2
重启服务,客户端进行访问。
客户端查看响应报文:
Set-Cookie首部已经添加信息,接下来该客户端的访问(只要cookie信息还在)将始终被定向至app2。
option forwardfor
客户端的请求经前端的代理服务器转发至后端的web服务器,代理服务器在转发时将目标地址改为后端的某台web服务器地址,将源地址由client ip(客户端地址)改为自己面向后端服务器的地址。后端的web服务器若使用默认格式记录日志,则记录的客户端IP地址都为前端的代理服务器地址。这时需要在发往后端的请求报文中添加内容为客户端IP地址的首部,以便后端的web服务器能够正确获取客户端地址。
使用option forwardfor 在发往服务器的请求首部中插入“X-Forwarded-For”首部。
格式:option forwardfor [ except
if-none:仅在此首部不存在时才允许添加至请求报文中。
backend app ....... option forwardfor header X-Client
在后端的web服务器上修改日志格式。
这里后端的web服务器为nginx,若为httpd,%{headname}i获取指定首部信息。重新加载配置文件后,即可获取客户端IP。需要注意的是,HAProxy工作于隧道模式,其仅检查每一个连接的第一个请求,因此,仅第一个请求报文被附加此首部。如果想为每一个请求都附加此首部,需要确保同时使用了“option httpclose”、“option forceclose”和“option http-server-close”几个option。
ACL简介
haproxy的ACL能够通过检测请求报文的首部、响应报文的内容或其他的环境状态信息作出转发决策,增强了其配置弹性。配置分两步骤:首先定义ACL,即定义一个测试条件,再定义动作,即满足测试条件的情况下执行的某特定动作。
定义格式:acl
[flags]:目前haproxy的acl支持的标志位有3个:
-i:不区分
-f:从指定的文件中加载模式;
--:标志符的强制结束标记;
常见的测试标准(criterion)有be_sess_rate,fe_sess_rate,hdr
基于ACL实现动静分离
实验环境:
haproxy2作为高可用集群的备用节点。
前端代理服务器收到的请求通过分析其uri,将静态内容调度至static server1和2,将动态内容调度至dynamic server1和2。
1)首先haproxy1和haproxy2实现时间同步
2)在haproxy1和haproxy2安装keepalived和haproxy。
3)编辑配置文件
配置haproxy,配置完成后将配置文件同步至haproxy2节点(关于每个参数的解释,可参考http://cbonte.github.io/haproxy-dconv/):
[root@node1 haproxy]# vim haproxy.cfg #--------------------------------------------------------------------- # Global settings #--------------------------------------------------------------------- global log 127.0.0.1 local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 4000 #最大并发连接数 user haproxy #运行haproxy的用户 group haproxy #运行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 #某上游服务器故障,重新将发往该服务器的请求发往其他的server。 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 ?#--------------------------------------------------------------------- # main frontend which proxys to the backends #--------------------------------------------------------------------- frontend service 192.168.1.200:80 option httpclose #允许服务器端被动关闭连接 option logasap capture request header Host len 20 capture request header Referer len 60 #定义ACL,以下两个ACL是获取静态请求 acl url_static path_beg -i /static /p_w_picpaths /javascript /stylesheets acl url_static path_end -i .jpg .gif .png .css .js use_backend static if url_static #将静态请求定向至static default_backend app #非静态请求定向至app option forwardfor header X-Client #添加内容为客户端IP的首部 #--------------------------------------------------------------------- # static backend for serving up p_w_picpaths, stylesheets and such #--------------------------------------------------------------------- backend static balance roundrobin server first 192.168.2.7:80 check port 80 maxconn 3000 server second 192.168.2.18:80 check port 80 maxconn 3000 #--------------------------------------------------------------------- # round robin balancing between the various backends #--------------------------------------------------------------------- backend app balance roundrobin option forwardfor header X-Client server app1 192.168.2.17:80 check port 80 maxconn 3000 server app2 192.168.2.16:80 check port 80 maxconn 3000 server app3 127.0.0.1:8080 backup
配置keepalived:
haproxy1上:
[root@node1 ~]# vim /etc/keepalived/keepalived.conf vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1234 } virtual_ipaddress { 192.168.1.200 } notify_master "/etc/init.d/haproxy start" #提升为主节点时,启动haproxy服务 notify_backup "/etc/init.d/haproxy stop" #降级为备节点时,关闭haproxy服务 notify_fault "/etc/init.d/haproxy stop" #运行出错时,关闭haproxy服务 }
haproxy2上(省略部分与haproxy1上一致):
vrrp_instance VI_1 { state BACKUP #备用节点 ...... priority 99 #服务器优先级 ....... }
配置完成后在启动各节点上的服务:
[root@www ~]# ansible haproxy -m shell -a 'service haproxy start' [root@www ~]# ansible haproxy -m shell -a 'service keepalived start' [root@www ~]# ansible webstatic -m shell -a 'service nginx start' [root@www ~]# ansible webdynamic -m shell -a 'service httpd start'
可以看到主节点上的虚拟IP已启用。在各个web节点上准备测试页面。
dynamic server1和server2上:
####server1##### [root@node1 ~]# vim /var/www/html/index.phpdynamic server1
####server2##### [root@node2 ~]# vim /var/www/html/index.phpdynamic server2
static server1和server2上:
####server1##### [root@node1 web]# vim p_w_picpaths/abc.htmlstatic node1
####server2##### [root@node2 web]# vim p_w_picpaths/abc.htmlstatic node2
进行访问测试:
访问静态内容:
访问动态内容:
这里已经对单节点haproxy做了高可用,当主节点故障时,服务能够自动切换至备节点而不中断访问。完成部署!.................^_^