HAProxy是法国人Willy Tarreau开发的一个开源软件,是一款应对客户端10000以上的同时连接的高性能的TCP和HTTP负载均衡器,可以实现基于TCP协议的四层代理及基于HTTP协议的七层代理。
HAProxy是TCP / HTTP反向代理服务器,尤其适合于高可用性环境:
可以针对HTTP请求添加cookie,进行路由后端服务器
可平衡负载至后端服务器,并支持持久连接
支持基于cookie进行调度
支持所有主服务器故障切换至备用服务器
支持专用端口实现监控服务
支持不影响现有连接情况下停止接受新连接请求
可以在双向添加,修改或删除HTTP报文首部
支持基于pattern实现连接请求的访问控制
通过特定的URI为授权用户提供详细的状态信息
1 程序环境:
主程序:/usr/sbin/haproxy
配置文件:/etc/haproxy/haproxy.cfg
Unit file:/usr/lib/systemd/system/haproxy.service
2 配置段:
global:全局配置段
进程及安全配置相关的参数
性能调整相关参数
Debug参数
proxies:代理配置段
defaults:为frontend, backend, listen提供默认配置
fronted:前端,相当于nginx, server {}
backend:后端,相当于nginx, upstream {}
listen:同时拥有前端和后端,适用于一对一环境
balance 关键字定义后端服务器组内的服务器调度算法,调度算法有以下几种:
roundrobin:基于权重轮询,动态算法,支持权重的运行时调整,支持慢启动;每个后端backend中最多支持4095个server
server options:weight #
static-rr:基于权重轮询,静态算法,不支持权重的运行时调整及慢启动;后端主机数量无上限
leastconn:加权最少连接,动态算法,最少连接的后端服务器优先分配接收新连接,相同连接时轮询,推荐在较长会话的场景使用,例如MySQL、LDAP等,不适合http
first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务
source:源地址hash,新连接先按权重分配,后续连接按source分配请求
uri:
对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,以后派发至某挑出的服务器,适用于后端缓存服务器
://:@:/;?#
左半部分:
/;
整个uri:
/;?#
url_param:
对用户请求的uri去params部分中的参数的值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server
hdr(name):对于每个http请求,此处由name指定的http首部将会被取出做hash计算;并由服务器总权重相除以后派发至某挑出的服务器;无有效值的会被轮询调度
hash-type:哈希算法
hash-type [method] [function] [modifier]
method包括:
map-based:除权取余法,哈希数据结构是静态数组
consistent:一致性哈希,哈希数据结构是一棵树
[function] : 哈希函数
基于uri的调度算法:
将服务器按权重映射,假设A、B、C的权重分别为1、2、3,则A、B、C分别映射为1、2、3台服务器,对应0-5的编号,当客户端请求到达时,对uri做哈希计算,将得到的哈希值对服务器总权重之和6取模,并调度至编号与结果相同的服务器,所以当客户端访问相同uri时总能被调度至同一台后端服务器。相同uri意味着相同的资源,所以一般适用于后端为缓存服务器的情形。第一次访问时就基于uri进行调度
基于url_param的调度算法:
将服务器按权重映射,假设A、B、C的权重分别为1、2、3,则A、B、C分别映射为1、2、3台服务器,对应0-5的编号,当客户端请求到达时,对uri中的参数(参数值一般为用户ID)做哈希计算,将得到的哈希值对服务器总权重之和6取模,并调度至编号与结果相同的服务器,所以来自同一客户端的请求总能被调度至同一台后端服务器。第一次访问时就基于uri_param进行调度
基于source的调度对源地址做哈希计算,但得到的哈希值不对权重取模,所以第一次按权重调度至某台服务器,当该源地址的客户端再次访问时,调度至第一次调度的服务器
基于hdr([name])的调度算法:
当客户端的http请求到达时取出http报文首部的相应字段进行哈希运算,将得到的哈希值对服务器总权重之和6取模,并调度至编号与结果相同的服务器,所以http报文首部的相应字段相同时总能被调度至同一台后端服务器。第一次访问时就基于hdr([name])进行调度
但当服务器数量变动即服务器权重变化时,这种映射服务器权重的方法会导致之前所有的调度策略全部失效。一致性哈希将服务器按权重映射到哈希环,且uri的哈希值对固定值2^32取模,就解决了服务器权重变化时调度策略失效的问题,为避免出现哈希环偏斜的问题,可以按权重比扩大。
基于cookie的调度
当客户端访问http://172.18.0.107即haproxy时,haproxy将请求数据包根据调度策略发送到后端某台服务器,haproxy收到后端服务器的响应报文后修改相应首部,在响应报文中添加cookie字段,指明本次请求被调用到的后端服务器,然后发送给客户端。当客户端再次访问时会携带cookie信息,haproxy根据cookie值将请求调度至cookie值指定的后端服务器。第一次访问时基于某种调度策略进行调度,之后的访问基于cookie值调度
HAProxy通过ACL实现访问控制:
acl [aclname] [criterion] [flags] [operator] [value] …
[aclname]:ACL名称,可使用字母数字: . -_区分字符大小写
[flags]
-i不区分大小写
-m 使用指定的pattern匹配方法
-n 不做DNS解析
-u 强制每个ACL必须唯一ID,否则多个同名ACL或关系
–强制flag结束. 当字符串和某个flag相似时使用
[operator]
匹配整数值:eq、ge、gt、le、lt
匹配字符串:
-exact match (-m str) :字符串必须完全匹配模式
-substring match (-m sub) :在提取的字符串中查找模式,如果其中任何一个被发现,ACL将匹配
-prefix match (-m beg) :在提取的字符串首部中查找模式,如果其中任何一个被发现,ACL将匹配
-suffix match (-m end) :将模式与提取字符串的尾部进行比较,如果其中任何一个匹配,则ACL进行匹配
-subdir match (-m dir) :查看提取出来的用斜线分隔(“/”)的字符串,如果其中任何一个匹配,则ACL进行匹配
-domain match (-m dom) :查找提取的用点(“.”)分隔字符串,如果其中任何一个匹配,则ACL进行匹配
[value]的类型:
-boolean
-integer or integer range
-IP address / network
-string (exact, substring, suffix, prefix, subdir, domain)
-regular expression
-hex bloc
[criterion] :比较的标准和条件
dst目标IP
dst_port目标PORT
src源IP
src_port源PORT
base : string
返回第一个主机头和请求的路径部分的连接,该请求开始,并在问号之前结束,对虚拟主机有用
://:@:/;?#
base : exact string match
base_beg : prefix match
base_dir : subdir match
base_dom : domain match
base_end : suffix match
base_len : length match
base_reg : regex match
base_sub : substring match
path : string
提取请求的URL路径,该路径从第一个斜杠开始,并在问号之前结束(无主机部分)
://:@:/;?#
path : exact string match
path_beg : prefix match
path_dir : subdir match
path_dom : domain match
path_end : suffix match
path_len : length match
path_reg : regex match
path_sub : substring match
url: string
提取请求中的URL。一个典型的应用是具有预取能力的缓存,以及需要从数据库聚合多个信息并将它们保存在缓存中的网页门户入口
url: exact string match
url_beg: prefix match
url_dir: subdir match
url_dom: domain match
url_end: suffix match
url_len: length match
url_reg: regex match
url_sub: substring match
req.hdr([[name][,]]) : string
提取在一个HTTP请求报文的首部
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
示例1:acl invalid_src src 172.16.100.200
当源地址为172.16.100.200时满足这个acl的定义
示例2:acl bad_curl hdr_sub(User-Agent) -i curl
block if bad_curl
在http请求报文中提取User-Agent字段(浏览器类型),不区分大小写,若该字段包含curl子串,则禁止访问
基于ACL的动静分离示例
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 172.16.100.6:80 check
backend appsrvs
balance roundrobin
server app1 172.16.100.7:80 check
server app1 172.16.100.7:8080 check
listen stats
bind :9091
stats enable
stats auth admin:admin
stats admin if TRUE
其中,
acl url_static path_beg -i /static /images /javascript /stylesheets
当url以/static /images /javascript /stylesheets开始时,满足url_static这个acl的定义
acl url_static path_end -i .jpg .gif .png .css .js .html .txt .htm
当url以.jpg .gif .png .css .js .html .txt .htm结尾时,满足url_static这个acl的定义
use_backend staticsrvs if url_static
use_backend 当if/unless一个基于ACL的条件匹配时切换指定backend
当满足url_static这个acl的定义时,调度到后端服务器组staticsrvs
default_backend appsrvs
default_backend 无use_backend匹配时,使用默认的backend
即当不满足url_static这个acl的定义时,调度到后端服务器组appsrvs
backend staticsrvs
balance roundrobin
server stcsrv1 172.16.100.6:80 check
backend 定义后端服务器组
server 定义后端主机
check 对后端主机进行健康状态检查
该示例实现了动静分离:当客户端访问.jpg .gif .png .css .js .html .txt .htm等静态资源时,调度到静态资源服务器;当客户端访问动态资源时,调度至动态资源服务器。
待续。。。