一、HAProxy概述
1.haproxy简介
HAProxy主要提供两个功能:http协议反向代理(不提供缓存功能)、基于tcp层的负载均衡(如https、mysql协议)。适用于需要会话保持或七层处理的且负载特别大的站点。可支持数以万计的并发连接。
代理作用:web缓存(加速)、反向代理、内容路由(根据流量及内容类型等将请求转发至特定服务器)、转码器;
HAProxy基于一种事件驱动(event-driven)、单一进程模型和ebtree弹性二叉树机制。
多进程或多线程模型受内存限制、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型有更好的资源和时间管理的用户端(User-Space) 实现所有这些任务,所以并发响应能特别大。但在多核系统上此模型通常扩展性较差
2.性能优势
HAProxy借助于OS上几种常见的技术来实现性能的最大化。
单进程、事件驱动模型显著降低了上下文切换的开销及内存占用。
O(1)事件检查器(eventchecker)允许其在高并发连接中对任何连接的任何事件实现即时探测。
在任何可用的情况下,单缓冲(singlebuffering)机制能以不复制任何数据的方式完成读写操作,这会节约大量的CPU时钟周期及内存带宽;
借助于Linux 2.6 (>=2.6.27.19)上的splice()系统调用,HAProxy可以实现零复制转发(Zero-copy forwarding),在Linux3.5及以上的OS中还可以实现零复制启动(zero-starting);
内存分配器在固定大小的内存池中可实现即时内存分配,这能够显著减少创建一个会话的时长;
树型存储:侧重于使用作者多年前开发的弹性二叉树,实现了以O(log(N))的低开销来保持计时器命令、保持运行队列命令及管理轮询及最少连接队列;
优化的HTTP首部分析:优化的首部分析功能避免了在HTTP首部分析过程中重读任何内存区域;
精心地降低了昂贵的系统调用,大部分工作都在用户空间完成,如时间读取、缓冲聚合及文件描述符的启用和禁用等;
3.HAProxy目前主要版本
1.4版本——提供较好的弹性:衍生于1.2版本,并提供了额外的新特性,其中大多数是期待已久的。
客户端侧的长连接(client-side keep-alive)
TCP加速(TCP speedups)
响应池(response buffering)
RDP协议
基于源的粘性(source-based stickiness)
更好的统计数据接口(a much better stats interfaces)
更详细的健康状态检测机制(more verbose health checks)
基于流量的健康评估机制(traffic-based health)
支持HTTP认证
服务器管理命令行接口(server management from the CLI)
基于ACL的持久性(ACL-based persistence)
日志分析器
1.3版本——内容交换和超强负载:衍生于1.2版本,并提供了额外的新特性。
内容交换(content switching):基于任何请求标准挑选服务器池;
ACL:编写内容交换规则;
负载均衡算法(load-balancing algorithms):更多的算法支持;
内容探测(content inspection):阻止非授权协议;
透明代理(transparentproxy):在Linux系统上允许使用客户端IP直接连入服务器;
内核TCP拼接(kernel TCPsplicing):无copy方式在客户端和服务端之间转发数据以实现数G级别的数据速率;
分层设计(layereddesign):分别实现套接字、TCP、HTTP处理以提供更好的健壮性、更快的处理机制及便捷的演进能力;
快速、公平调度器(fast and fairscheduler):为某些任务指定优先级可实现理好的QoS;
会话速率限制(session rate limiting):适用于托管环境;
注意:
1)1.1、1.2、1.3的poll和epoll机制对性能影响
1.1l版本默认使用的polling系统为select(),其处理的文件数达数千个时性能便会急剧下降。
1.2和1.3版本默认的为poll(),在有些操作系统上可会也会有性能方面的问题,但在Solaris上表现相当不错。
HAProxy1.3在Linux 2.6及打了epoll补丁的Linux2.4上默认使用epoll,在FreeBSD上使用kqueue,这两种机制在任何负载上都能提供恒定的性能表现。
2) 高性能选型方案
Linux 2.6.32及之后版本上运行HAProxy 1.4;
打了epoll补丁的Linux2.4上运行HAProxy 1.4;
FreeBSD上运行HAProxy1.4;
Solaris10上运行HAProxy 1.4;
3)splice()调用机制
在较新版本的Linux2.6(>=2.6.27.19)上,HAProxy还能够使用splice()系统调用在接口间无复制地转发任何数据,甚至可以达到10Gbps的性能。
二、HAProxy安装配置
1.程序包安装
[[email protected]~]# yum install -y haproxy
主配置文件:/etc/haproxy/haproxy.cfg
主程序:/usr/sbin/haproxy
2.配置文件格式
(1) "global”配置段,用于设定全局配置参数
该配置段中的参数为进程级别的参数,且通常与其运行的OS相关。
chroot /var/lib/haproxy |
指定haproxy工作目录,修改可以提高安全性;指定目录为空且任何用户不能有写权限 |
pidfile /var/run/haproxy.pid |
指定程序进程运行文件 |
maxconn 4000 |
设定每个haproxy进程所接受的最大并发连接数 |
user haproxy |
指明程序运行的属主 |
group haproxy |
指明程序运行的属组 |
daemon |
指明haproxy以守护进程的形式运行 |
… ... |
(2) proxy相关配置段,如 "defaults"、" listen"、"frontend" 和 "backend"
defaults段 |
为所有其它配置段提供默认参数,这配置默认配置参数可由下一个“defaults”所重新设定 |
frontend段 |
定义监听的套接字(可接受客户端请求并与之建立连接) |
backend段 |
定义“后端”服务器,代理将会将对应客户端的请求转发至这些服务器。 |
listen段 |
通过关联“前端”和“后端”定义了一个完整的代理,通常只对TCP流量有用。 |
说明:defaults段相关参数
mode http |
设定实例的运行模式或协议,tcp|http|health |
log global |
启用事件和流量日志,因此可用于所有区段。每个实例最多可以指定两个log参数 |
option httplog |
启用记录HTTP请求、会话状态和计时器的功能 |
option dontlognull
optionhttp-server-close
option forwardfor except 127.0.0.0/8 允许在发往服务器的请求首部中插入“X-Forwarded-For”首部,除了本机
option redispatch
retries 3
timeouthttp-request 10s
timeoutqueue 1m
timeoutconnect 10s
timeoutclient 1m
timeoutserver 1m
timeouthttp-keep-alive 10s
timeoutcheck 10s
maxconn 3000 设定一个前端的最大并发连接数,一般1GB内存空间能维护40000-50000并发连接
实例一:
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
backendstatic
balance roundrobin
server static 127.0.0.1:4331 check
backendapp
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
实例二:
frontendmain
bind *:80
default_backendwebsrvs
backendwebsrvs
balanceroundrobin
server web1 172.16.49.102:80 check
server web2 172.16.49.103:80 check
三、HAProxy代理相关参数
1.balance
定义负载均衡算法,可用于"defaults"、"listen"和"backend"配置段
可用算法:
static-rr |
轮询、静态算法,每个后端主机支持的数量无上限 |
roundrobin: |
基于权重轮询算法,每个后端主机最多支持4128个连接 |
leastconn: |
根据后端主机的负载数量进行调度;仅适用长连接的会话(LDAP、SQL...),动态、可在运行时调整权重 |
source |
将请求的源地址进行hash运算,并由后端服务器的权重总数相除后派发至某匹配的服务器,使得同一个客户端IP的请求始终被派发至某特定的服务器,可指明hash-type(map-based、consistent) map-based:取模法;静态;默认 consistent:一致性哈希法;动态;支持权重的调整,影响是局部的 |
uri |
对URI的左半部分(?<QUERY>之前)或整个URI进行hash运算,对同一个URI的请求总是被派发至某特定的服务器,可以指明hash-type(map-based、consistent)。 即第一次请求一个URL分发到一个主机,则之后再次请求相同URL则使用一台主机响应 |
url_param |
根据url中的指定的参数的值进行调度;把值做hash计算,并除以总权重; 可以指明hash-type(map-based、consistent) |
hdr(<name>) |
根据请求报文中指定的header(如use_agent, referer, hostname)进行调度;把指定的header的值做hash计算;可以指明hash-type(map-based、consistent) |
注意:
(1)当使用uri算法时,第一次请求一个URL分发到一个主机,则之后再次请求相同URL则使用一台主机响应。当第一次请求之后,若响应该请求的主机服务出现故障,则haproxy或将其调度到其他主机,此主机修复后再次调度回来
(2)URI:统一资源标识符;格式如下:
<SCHEME>://<USER>:<PASSWORD>@<HOST>:<PORT>/<PATH>;<PARAMS>?<QUERY>#<FRAG>
方案://用户:密码@主机:端口/路径;参数(键值数据、可以多个参数字段)?查询语句#片段显示
2.hash-type
格式:hash-type <method>
定义用于将hash码映射至后端服务器的方法;不能用于frontend区段;可用方法有map-based和consistent
说明:
(1) map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。
(2) consistent:hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,尤其适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。
3.bind
定义一个或者几个监听的套接字、只能用于frontend, listen;
bind[<address>]:<port_range> [, ...]
bind[<address>]:<port_range> [, ...] interface <interface>
<address> |
可以为主机名、IPv4地址、IPv6地址或*;省略、*或0.0.0.0时,表示监听所有IPv4地址 |
<port_range> |
特定的TCP端口,或者端口范围;小于1024需要特定用户才能使用 |
<interface> |
指定物理接口的名称,不能使用接口别名 |
4.default_backend
为frontend指明使用的默认后端;default_backend<backend>
实例:
use_backend dynamic if url_dyn
use_backend static if url_css url_img extension_img
default_backend dynamic
注意:use_backend: 条件式后端调用;
5.server
server <name> <addr>[:port][param*];用于为后端声明一个server
<name>:名称,标识符
<addr>[:port]:设定后端真实服务器监听的端口和地址
[param*]:参数
backup: 设定为备用服务器,仅在负载均衡场景中的其它server均不可用于启用此server;
check:健康状态检测;
inter<delay>:检测时间间隔;单位为ms, 默认为2000;
rise<count>:设定健康状态检查中,某离线的server从离线状态转换至正常状态需要成功检查的次数;
fall<count>:确认server从正常状态转换为不可用状态需要检查的次数;
cookie <value>:为指定server设定cookie值,用于实现持久连接的功能;
maxconn:此服务接受的并发连接的最大数量;
maxqueue:请求队列的最大长度;
observe:根据流量判断后端server的健康状态;
weight #: 指定权重,#默认为1,最大为256;0表示不被调度;
redir<prefix>: 重定向;所有发往此服务器的请求均以302响应;
注意:
健康监测的方式有多种,具体服务可能检测方法的配置指令不同;此处为后端http服务时的健康状态的检测方法,在defaults配置段定义了" option httpchk "。
"httpchk"、"smtpchk"、"mysql-check"、"pgsql-check"、"ssl-hello-chk"
实例:基于浏览器cookie实现sessionsticky(会话绑定)
backendwebsrvs
balance roundrobin
cookie SERVERID insert # 报文首部插入标识
server web1 172.16.49.102:80 check weight 1 cookie websrv1 # cookie绑定名称参数标识
server web2 172.16.49.103:80 check weight 3 cookie websrv2
注释:每个server有自己惟一的cookie标识、在backend中定义为用户请求调度完成后操纵其cookie
6.向日志中记录额外信息:
(1) capture requestheader
格式:capture request header <name> len <length>
捕获并记录指定的请求首部最近一次出现时的第一个值,仅能用于“frontend”和“listen”区段
<name>:要捕获的首部的名称,此名称不区分字符大小写,但建议与它们出现在首部中的格式相同,比如大写首字母。需要注意的是,记录在日志中的是首部对应的值,而非首部名称。
<length>:指定记录首部值时所记录的精确长度,超出的部分将会被忽略。
注意:
可以捕获的请求首部的个数没有限制,但每个捕获最多只能记录64个字符。为了保证同一个frontend中日志格式的统一性,首部捕获仅能在frontend中定义。
(2)captureresponse header;捕获并记录响应首部,其格式和要点同请求首部。
格式:capture response header <name> len <length>
四、HAProxy状态监控页配置
1.配置监控页信息
(1)stats enable
启用基于程序编译时默认设置的统计报告,不能用于“frontend”区段。
(2)stats hide-version
启用统计报告并隐藏HAProxy版本报告,不能用于“frontend”区段。
(3)stats realm
格式:stats realm <realm>
<realm>:实现HTTP基本认证时显示在浏览器中的领域名称,用于提示用户输入一个用户名和密码。
启用统计报告并高精认证领域,不能用于“frontend”区段。haproxy在读取realm时会将其视作一个单词,因此,中间的任何空白字符都必须使用反斜线进行转义。此参数仅在与“statsauth”配置使用时有意义。
(4)stats scope
stats scope {<name> | "." }
<name>:可以是“listen”、“frontend”或“backend”区段的名称,而“.”则表示statsscope语句所定义的当前区段。
启用统计报告并限定报告的区段,不能用于“frontend”区段。当指定此语句时,统计报告将仅显示其列举出区段的报告信息,所有其它区段的信息将被隐藏。如果需要显示多个区段的统计报告,此语句可以定义多次。需要注意的是,区段名称检测仅仅是以字符串比较的方式进行,它不会真检测指定的区段是否真正存在。
(5)stats auth
格式:stats auth <user>:<passwd>
<user>:授权进行访问的用户名;
<passwd>:此用户的访问密码,明文格式;
启用带认证的统计报告功能并授权一个用户帐号,其不能用于“frontend”区段。
(6)stats admin
格式:stats admin {if | unless } <cond>
在指定的条件满足时启用统计报告页面的管理级别功能,它允许通过web接口启用或禁用服务器。
2.配置案例:stats状态监控页
(1)在配置文件/etc/haproxy/haproxy.cfg中配置代理和监控配置信息
listenstatistics
bind *:9090
stats enable
stats hide-version
stats uri /haproxyadmin?stats
stats realm "HAPorxy\Statistics"
stats auth admin:xuding
stats admin if TRUE
(2)访问URL:http://172.16.49.101:9090/haproxyadmin?stats
(3)此时即可进入管理页面进行对后端服务器的管理和页面监控数据监控
说明:
此时可以管控后端主机的启停操作,所以演注意安全性
五、错误页面重定向
errorfile:使用haproxy主机本地文件进行响应;
errorloc,errorloc302: 使用指定的url进行响应,响应状态码为302;不适用于GET以外的其它请求方法;
errorloc303:返回303状态码;
1.errorfile
格式:errorfile <code> <file>
<code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;
<file>:指定用于响应的页面文件
在用户请求不存在的页面时,返回一个页面文件给客户端而非由haproxy生成的错误代码;可用于所有段中。
实例:
errorfile400 /etc/haproxy/errorpages/400badreq.http
errorfile403 /etc/haproxy/errorpages/403forbid.http
errorfile503 /etc/haproxy/errorpages/503sorry.http
2.errorloc 和 errorloc302
请求错误时,返回一个HTTP重定向至某URL的信息;可用于所有配置段中。
errorloc<code> <url>
errorloc302<code> <url>
<code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;
<url>:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需要注意的是,如果URI自身错误时产生某特定状态码信息的话,有可能会导致循环定向;
注意:
这两个关键字都会返回302状态吗,这将使得客户端使用同样的HTTP方法获取指定的URL,对于非GET广场法的场景(如POST)来说会产生问题,因为返回客户的URL是不允许使用GET以外的其它方法的。如果的确有这种问题,可以使用errorloc303来返回303状态码给客户端。
3. errorloc303
errorloc303 <code> <url>;请求错误时,返回一个HTTP重定向至某URL的信息给客户端;可用于所有配置段中。
<code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有400、403、408、500、502、503和504;
<url>:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需要注意的是,如果URI自身错误时产生某特定状态码信息的话,有可能会导致循环定向;
实例:
backendwebserver
server 172.16.100.6 172.16.100.6:80 checkmaxconn 3000 cookie srv01
server 172.16.100.7 172.16.100.7:80 checkmaxconn 3000 cookie srv02
errorfile 403/etc/haproxy/errorpages/sorry.htm
errorfile 503/etc/haproxy/errorpages/sorry.htm