构建HAProxy高性能反向代理架构
1.HAProxy基础
HAProxy基础概念和原理
四层代理: 通过分析IP层及TCP/UDP层的流量实现的基于“IP+端口”的负载均衡。
七层: 可以根据内容,再配合负载均衡算法来选择后端服务器,不但可以根据 “ip+端口”方式进行负载分流,还可以根据网站的URL,访问域名,浏览 器类别,语言等决定负载均衡的策略。
七层负载均衡模式下,负载均衡与客户端及后端的服务器会分别建立一次 TCP连接,而在四层负载均衡模式下(DR),仅建立一次TCP连接;七层负载均衡对负载均衡设备的要求更高,处理能力也低于四层负载均衡。
haproxy与lvs的负载均衡很大一点不同的是,lvs仅仅是基于内核的简单调度,而haproxy则是当请求到达反向代理端时,代理端帮前端去请求相应内容
Haproxy的特性:
- 1、可靠性与稳定性都非常出色,可与硬件级设备媲美。
- 2、支持连接拒绝,可以用于防止DDoS攻击
- 3、支持长连接、短连接和日志功能,可根据需要灵活配置
- 4、路由HTTP请求到后端服务器,基于cookie作会话绑定;同时支持通过获取指定 的url来检测后端服务器的状态
- 5、HAProxy还拥有功能强大的ACL支持,可灵活配置路由功能,实现动静分离,在架构设计与实现上带来很大方便
- 6、可支持四层和七层负载均衡,几乎能为所有服务常见的提供负载均衡功能
- 7、拥有功能强大的后端服务器的状态监控web页面,可以实时了解设备的运行状态 ,还可实现设备上下线等简单操作。
- 8、支持多种负载均衡调度算法,并且也支持session保持。
HAProxy的软件架构和配置文件
Haproxy程序路径:
- 主程序:/usr/sbin/haproxy
- 主配置文件:/etc/haproxy/haproxy.cfg
- Unit file:/usr/lib/systemd/system/haproxy.service(centos7)
- Init.file :/etc/init.d/haproxy (centos6)
Haproxy配置文件结构:
Haproxy的主配置文件路径一般在/etc/haproxy/haproxy.cfg下(yum安装)
haproxy 的配置文件由两部分组成:全局设定(global settings)和对代理的设定(proxies)
global settings:主要用于定义haproxy进程管理安全及性能相关的参数
proxies共分为4段:defaults,frontend,backend,listen
proxies:代理相关的配置可以有如下几个配置端组成
- – defaults:为其它配置段提供默认参数,默认配置参数可由下一个“defaults”重新设定。
- – frontend:定义一系列监听的套接字,这些套接字可接受客户端请求并与之建立连接。
- – backend:定义“后端”服务器,前端代理服务器将会把客户端的请求调度至这些服务器。
- – listen:定义监听的套接字和后端的服务器。类似于将frontend和backend段放在一起
所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、_(下划线)、.(点号)和:(冒号)。此 外,ACL名称会区分字母大小写。
global #全局配置 (进程管理及安全相关的参数)
- - chroot:修改haproxy的工作目录至指定的目录并在放弃权限之前执行 chroot()操作,可以提升haproxy的安全级别,
- - daemon:让haproxy以守护进程的方式工作于后台,其等同于“-D”选项的功能, 当然,也可以在命令行中以“-db”选项将其禁用;
- - gid:以指定的GID运行haproxy,建议使用专用于运行haproxy的GID, 以免因权限问题带来风险;
- - group:同gid,不过指定的组名;
- - log: [max level [min level]]:定义全局的syslog服务器,最多可以定义两个;
- - nbproc :指定启动的haproxy进程个数,只能用于守护进程模式的 haproxy;默认只启动一个进程,
- - uid:以指定的UID身份运行haproxy进程;
- - user:同uid,但使用的是用户名;
- - ulimit-n:设定每进程所能够打开的最大文件描述符数目,默认情况下其会自动进行计 算,因此不推荐修改此选项;
- - stats:可开启一个unix socket管理接口
defaults相关的配置可以如下:
defaults
mode http #实现http的7层规则
log global #日志定义
option httplog#启用日志记录HTTP请求,默认haproxy日志是不记HTTP请求
option dontlognull #日志中将不会记录空连接。
option httpclose # 强制短连接,每次收发完包后都把连接关闭
option forwardfor #添加xforward日志标记
retries 3 # 定义连接后端服务器的失败重连次数
timeout http-request 10s # 请求超时
timeout queue 1m #队列超时
timeout connect 10s #连接超时
timeout client 1m #客户端超时
frontend 相关的配置可以如下:
frontend段用于定义一系列监听套接字,可接受客户端请求并与之建立连接
frontend main *:5000
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 app
backend 相关的配置可以如下:
backend段用于定义一系列“后端”服务器,代理将会将对应客户端的请求转发至这些服务器。
backend app
balance roundrobin
server app1 127.0.0.1:5001 check
server app2 127.0.0.1:5002 check
server app3 127.0.0.1:5003 check
server app4 127.0.0.1:5004 check
listen 相关的配置可以如下:
listen段通过关联“前端”和“后端”定义了一个完整的代理,frontend和backend 块的结合体
listen stats #定义一个统计报告服务
mode http #基于http协议
bind 0.0.0.0:1080 #监听1080端口
stats enable #开启统计报告服务
stats hide-version #隐藏统计报告版本信息
stats uri /haproxyadmin?stats #统计报告访问url
stats realm Haproxy\ Statistics #页面登陆信息
stats auth admin:admin #验证账号信息
stats admin if TRUE #验证模式
mode { tcp|http|health } #实例运行模式
设定实例的运行模式或协议。当实现内容交换时,前端和后端必须工作于同一种模式(一般 说来都是HTTP模式),否则将无法启动实例。
tcp:实例运行于纯TCP模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查;此为默认模式,通常用于SSL、SSH、SMTP等应用;
http:实例运行于HTTP模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC格式兼容的请求都会被拒绝;
health:实例工作于health模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息;此模式将用于响应外部组件的健康状态检查请求;目前来讲,此模式已经废弃,因为tcp或http模式中的monitor关键字可完成类似功能
balance 分配算法策略
balance 定义负载均衡算法,可用于“defaults”、“listen”和“backend”。用于在负载均衡场景中挑选一个server,其仅应用于用户新请求或需要将一个连接重新派发至另一个服务器时。支持的算法有:
roundrobin:基于权重进行轮叫,在服务器的处理时间保持均匀分布时,这是最平衡、 最公平的算法。此算法是动态的,这表示其权重可以在运行时进行调整,不过,在设计上 ,每个后端服务器仅能最多接受4128个连接;
static-rr:基于权重进行轮叫,与roundrobin类似,但是为静态方法,在运行时调整其服务器权重不会生效;不过,其在后端服务器连接数上没有限制;
leastconn:新的连接请求被派发至具有最少连接数目的后端服务器;在有着较长时间会 话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议
first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限, 新请求才会分配给下一台服务;
source:将请求的源地址进行hash运算,并由后端服务器的权重总数相除后派发至某匹 配的服务器;这可以使得同一个客户端IP的请求始终被派发至某特定的服务器;不过,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可 能会被派发至与此前请求不同的服务器;常用于负载均衡无cookie功能的基于TCP的协议 ;其默认为静态,不过也可以使用hash-type修改此特性;
uri:对URI的左半部分(“问题”标记之前的部分)或整个URI进行hash运算,并由服务 器的总权重相除后派发至某匹配的服务器;这可以使得对同一个URI的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存或反病毒代 理以提高缓存的命中率;需要注意的是,此算法仅应用于HTTP后端服务器场景;其默认为静态算法
default_backend #默认backend配置
default_backend 在没有匹配的"use_backend"规则时为实例指定使用的默认后端,因此,其不可应用于 backend区段。在"frontend"和"backend"之间进行内容交换时,通常使用"use- backend"定义其匹配规则;而没有被规则匹配到的请求将由此参数指定的后端接收。
使用案例:
use_backend dynamic if url_dyn
use_backend static if url_css url_img extension_img
default_backend dynamic
httpchk #健康状态检查
listen http_proxy 0.0.0.0:80
mode http
balance roundrobin
option httpchk GET /index.html
server web1 192.168.1.1:80 cookie server01 check
server web2 192.168.1.2:80 cookie server02 check
errorfile #错误页面配置
errorfile 在用户请求不存在的页面时,返回一个页面文件给客户端而非由haproxy生成的错误代码;可用于所有段中。
例如:
errorfile 400 /etc/haproxy/errorpages/400badreq.http
errorfile 403 /etc/haproxy/errorpages/403forbid.http
errorfile 503 /etc/haproxy/errorpages/503sorry.http
一份完整的haproxy配置文件实例:
2.HAProxy企业级实战
haproxy的ACL用于实现基于请求报文的首部、响应报文的内容或 其它的环境状态信息来做出转发决策,这大大增强了其配置弹性。 其配置法则通常分为两步,首先去定义ACL,即定义一个测试条件 ,而后在条件得到满足时执行某特定的动作,如阻止请求或转发至 某特定的后端。
Haproxy进行安全加固
用于测试指定的backend上会话创建的速率(即每秒创建的会话数)是否满足指定的条件;常用于在指定 backend上的会话速率过高时将用户请求转发至另外的backend,或用于阻止攻击行为。例如
backend dynamic
mode http
acl being_scanned be_sess_rate gt 100
redirect location /denied.html if being_scanned
通过ACL指定可访问的用户:
#阻断来自非指定IP的访问80端口的请求
acl myhost src 172.16.100.1
acl myport dst_port 80
tcp-request connection reject if !myhost myport
#还可以用block
block if ! myhost myport
根据用户访问内容实现动静分离:
frontend http-in
bind *:80
mode http
log global
option httpclose
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .jpeg .gif .png .css .js
use_backend static_servers if url_static
default_backend dynamic_servers
backend static_servers
balance roundrobin
server imgsrv1 172.18.64.7:80 check maxconn 6000
server imgsrv2 172.18.64.107:80 check maxconn 6000
backend dynamic_servers
balance source
server websrv1 172.18.64.17:80 check maxconn 1000
server websrv2 172.18.64.106:80 check maxconn 1000
Haproxy实现浏览器控制:
#阻断火狐浏览器发送的请求
acl firefox hdr_reg(User-Agent) -i .*firefox.*
block if firefox
#将IE用户请求分配到静态服务器
acl ie_useragent hdr_reg(User-Agent) -i .*ie.*
use_backend static_servers if ie_useragent
Haproxy实现真实日志记录 :
option forwardfor
option forwardfor [ except ] [ header ] [ if-none ] 允许在发往服务器的请求首部中插入“X-Forwarded-For”首部。
HAProxy工作于反向代理模式,其发往服务器的请求中的客户端IP均为HAProxy主机的地址而非真正客户端的地址,这会使得服务器端的日志信息记录不了真正的请求来源,“X-Forwarded-For”首部则可用于解决此问题。HAProxy可以 向每个发往服务器的请求上添加此首部,并以客户端IP为其value。 需要注意的是,HAProxy工作于隧道模式,其仅检查每一个连接的第一个请求,因此,仅第一个请求报文被附加此首部。 下面是一个例子。
frontend www
mode http
option forwardfor except 127.0.0.1
Haproxy实现会话保持:
一、源地址hash(用户IP识别)Haroxy 将用户IP经过hash计算后 指定到固定的真实服务器上(类似于nginx的IP hash 指令)。
缺点:当后端一台服务器挂了以后会造成部分session丢失
backend SOURCE_srv
mode http
balance source
server app-node1 10.31.1.179:80 check port 80 inter 3000 rise 3 fall 3
server app-node2 10.31.1.191:80 check port 80 inter 3000 rise 3 fall 3
server app-node3 10.31.0.35:80 check port 80 inter 3000 rise 3 fall 3
二、cookie 识别 haproxy 将WEB服务端返回给客户端的cookie中插入haproxy中特定的字符串(或添加前缀)在后端的服务器COOKIE ID。
backend COOKIE_srv
mode http
cookie SERVERID insert indirect nocache
server app-node1 10.31.1.179:80 check port 80 cookie a inter 3000 rise 3 fall 3
server app-node2 10.31.1.191:80 check port 80 cookie b inter 3000 rise 3 fall 3
server app-node3 10.31.0.251:80 check port 80 cookie c inter 3000 rise 3 fall 3
在LB1上配置好HAProxy后,LB1将接受用户的所有请求。如果一个用户请求不包含任何cookie,那这个请求将被HAProxy转发到一台可用的WEB服务器。可能是webA,webB,webC。然后HAProxy将把处理这个请求的WEB服务器的cookie值插入到请求响应中。如SERVERID=A。当这个客户端再次访问 并在HTTP请求头中带有SERVERID=A,HAProxy将会把它的请求直接转发给webA处理。在请求到达 webA之前,cookie将被移除,webA将不会看到这个cookie。如果webA不可用,对应的请求将被转发到其他可用的WEB服务器,相应的cookie值也将被重新设置。
Haproxy性能优化参数:
option redispatch:当server对应的服务器挂掉后,强制定向到其他健康的服务器
option dontlognull :保证HAProxy不记录上级负载均衡发送过来 的用于检测状态没有数据的心跳包
retries 3 : //3次连接失败就认为服务器不可用,主要通过后面的check检查
maxconn 30000 : //代理时所能接受的最大并发连接数, 应该要比后端主机的并发总和要小
深化理解思考:
1、haproxy的特点是什么?
2、如何优化haproxy参数?
3、haproxy中hdr_reg是匹配什么的?
4、haproxy的acl怎么配置的?
5、haproxy怎么实现会话保持的?
6、haproxy如何和keepalived结合实现高可用和负载均衡的?
7、haproxy对后端服务如何配置健康监测的?
8、haproxy如何实现动静分离的?
9、Haproxy、Nginx和LVS都能实现负载均衡功能,区别是什么?