HAProxy实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(user-space)实现所有这些任务,所有没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以使每个cpu时间片(cycle)做更多的工作。
LB Cluster工作协议层分类:
1) 传输层(四层)
Lvs,nginx,haproxy(mode tcp)
2) 应用层(七层)
http:nginx(http模块),haproxy(mode http),httpd,…
Note:haproxy和nginx一样,是工作在用户空间的应用程序,负载均衡能力同样受限于套接字的数量限制;Lvs是工作在内核空间的,只是作为了一个报文转发的角色,不受限于端口的数量,所以有人说lvs优化可以承载四百万个并发。
HAProxy安装及参数配置:
配置文件:/etc/haproxy/haproxy.cfg
程序:/usr/sbin/haproxy
Unit file:
Centos6:/etc/rc.d/init.d/haproxy
Centos7:haproxy.service
配置可分为两段:
Global
配置参数:log,maxconn,…
Proxies(代理)
Defaults,frontend,backend,listen
示例:
frontend main *:80
default_backend websrvs
backend websrvs
balance roundrobin
server web1 172.16.100.68 check
server web2 172.16.100.69 check
演示1:配置haproxy负载均衡web服务;
1. 试验环境
代理服务器(haproxy):192.168.19.203
upserver1:192.168.19.143
upserver2:192.168.19.134
2. 编辑haproxy配置文件/etc/haproxy/haproxy.cfg,使其反向代理后端web服务器,
3. 启动haproxy服务,查看端口是否开启;
4. 为后端两台upserver提供网页测试页面;
Upserver1:
Upserver2:
5. 测试代理服务器访问;
HAProxy具体参数配置(全局配置GLOBAL):
进程管理及安全相关的参数
1. chroot <jail dir>
修改haproxy的工作目录至指定的目录并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不顾需要注意的是要确保指定的目录为空目录且任何用户均不能有写权限;
2. daemon
让haproxy以守护进程方式工作于后台,其等同于“-D”选项的功能,当然,也可以在命令行中以“-db”选项将其禁用;
3. gid <number>
以指定的GID运行haproxy,建议使用专用于运行haproxy的GID,以免因权限问题带来风险;
4. group
同gid,不过指定的组名;
5. uid
以指定的UID身份运行haproxy进程;
6. user
同uid,但使用的是用户名;
7. nbproc <number>
指定启动的haproxy进程的个数,只能用于守护进程模式的haproxy;默认只启动一个进程,鉴于调试困难等多方面的原因,一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;
8. pidfile
pid文件;
9. ulimit-n
设定每进程所能够打开的最大文件描述符数目,默认情况下其会自动进行计算,因此不推荐修改此选项;
10. description
当前实例的描述信息
11. node
定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时;
12. log <address> <facility> [max level [min level]]
定义全局的syslog服务器,最多可以定义两个;
13. log-send-hostname [<string>]:在syslog信息的首部添加当前主机名,可以为“string”指定的名称,也可以缺省使用当前的主机名;
演示:启用haproxy的记录日志功能:
1) 编辑haproxy的配置文件,启用记录日志功能;
2) 编辑/etc/rsyslog.conf配置文件,记录一个记录远程日志的tcp或udp服务;
3) 重启rsyslog服务,并查看端口是否开启;
4) 浏览器访问测试,查看日志;
性能调整相关的参数:
1. maxconn <number>
设定每个haproxy进程所接受的最大并发连接数,其等同于命令行选项“-n”;“ulimit -n”自动计算的结果正是参照此参数设定的;
2. maxpipes <number>
haproxy使用pipe完成基于内核的tcp报文重组,此选项则用于设定每进程所允许使用的最大pipe个数;每个pipe会打开两个文件描述符,因此,“ulimit -n”自动计算时会根据需要调大此值;默认为maxconn/4,其通常会显得过大。
3. noepoll
在linux系统上禁用epoll机制;
4. nokqueue
在BSD系统上禁用epoll机制
5. nopoll
禁用poll机制;
6. nosepoll
在linux禁用启发式epoll机制;
7. nosplice
禁止在linux套接字上使用内核tcp重组,这会导致更多的recv/send系统调用;不过,在Linux 2.6.25-28系列的内核上,tcp重组功能有bug存在;
8. spread-checks <0..50,in percent>
在haproxy后端有着众多服务器的场景中,在精确的时间间隔后统一对众服务器进行健康状况检查可能会带来意外问题;此选项用于将其检查的时间间隔长度上增加或减小到一定的随机时长;
9. tune.bufsize <number>
设定buffer的大小,同样的内存条件下,较小的值可以让haproxy有能力接受更多的并发连接,较大的值可以让某些应用程序使用较大的cookie信息;默认为16384,其可以在编译时修改,不过强烈建议使用默认值;
10. tune.chksize <number>
设定检查缓冲区的大小,单位为字节;更大的值有助于在较大的页面中完成基于字符串或模式的文本查找,但也会占用更多的系统资源;不建议修改;
11. tune.maxaccept <number>
设定haproxy进程内核调度运行时一次性可以接受的连接的个数,较大的值可以带来较大的吞吐率,默认在单进程模式下为100,多进程模式下为8,设定为-1可以禁止此限制;一般不建议修改;
12. tune.maxpollevents <number>
设定一次系统调用可以处理的事件最大数,默认值取决于OS;其值小于200时可节约带宽,但会略微增大网络延迟,而大于200时会降低延迟,但会稍稍增加网络带宽的占用量;
13. tune.maxrewrite <number>
设定为首部重写或追加而预留的缓冲空间,建议使用1024左右的大小;在需要使用更大的空间时,haproxy会自动增加其值;
14. tune.rcvbuf.server <number>
设定内核套接字中服务端或客户端接收缓冲的大小,单位为字节;强烈推荐使用默认值;
Debugging、userlists、peers参数
1. Debugging 调试相关的参数;
debug :尽量详细的输出信息;
quiet:尽量不输出信息
2. Userlists:定义用户、组及用户列表
userlist <listname>
group <groupname> [users <user>,<user>,(...)]
user <username> [password|insecure-password <password>] [groups <group>,<group>,(...)]
3. Peers:定义haproxy同步集群
peer
peers
HAProxy参数配置(代理配置段):
代理相关的配置可以如下配置段中。
- defaults <name>
- frontend <name>
- backend <name>
- listen <name>
“defaults”段用于为所有其它配置段提供默认参数,这配置默认配置参数可由下一个“defaults”所重新设定。
“frontend”段用于定义一系列监听的套接字,这些套接字可接受客户端请求并与之建立连接。
“backend”段用于定义一系列“后端”服务器,代理将会将对应客户端的请求转发至这些服务器。
“listen”段通过关联“前端”和“后端”定义了一个完整的代理,通常只对TCP流量有用。
所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、_(下划线)、.(点号)和:(冒号)。此外,ACL名称会区分字母大小写。
1. balance:指明调度算法
balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post [<max_wait>]]
动态:权重可动态调整
静态:调整权重不会实时生效
roundrobin:轮询,动态算法,每个后端主机最多支持4128个连接;
static-rr:轮询,静态算法,每个后端主机支持的数量无上限
leastconn:最少连接算法,根据后端主机的负载数量进行调度;仅适用长连接的会话;动态;
source:源地址哈希算法,将来自同一个ip地址的请求发往同一个real server
将请求的源地址进行hash运算,并由后端服务器的权重总数相除后派发至某匹配的服务器;这可以使得同一个客户端IP的请求始终被派发至某特定的服务器;不过,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;常用于负载均衡无cookie功能的基于TCP的协议;其默认为静态,不过也可以使用hash-type修改此特性;
hash-type:
map-based:取模法,静态;
consistent:一致性哈希算法;动态;
uri:对URI的左半部分(“问题”标记之前的部分)或整个URI进行hash运算,并由服务器的总权重相除后派发至某匹配的服务器;这可以使得对同一个URI的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存或反病毒代理以提高缓存的命中率;需要注意的是,此算法仅应用于HTTP后端服务器场景;其默认为静态算法,不过也可以使用hash-type修改此特性;
hash-type
map-based:
consistent:
url_param: 根据url中的指定的参数的值进行调度;把值做hash计算,并除以总权重;
hash-type
map-based:
consistent:
hdr(<name>) :根据请求报文中指定的header(如use_agent, referer, hostname)进行调度;把指定的header的值做hash计算;
hash-type
map-based:
consistent:
rdp-cookie
rdp-cookie(<name>)
2. bind:设定监听的地址和端口,适用于frontend,listen段
bind [<address>]:<port_range> [, ...]
bind [<address>]:<port_range> [, ...] interface <interface>
<address>:可选选项,其可以为主机名、IPv4地址、IPv6地址或*;省略此选项、将其指定为*或0.0.0.0时,将监听当前系统的所有IPv4地址;
<port_range>:可以是一个特定的TCP端口,也可是一个端口范围(如5005-5010),代理服务器将通过指定的端口来接收客户端请求;需要注意的是,每组监听的套接字<address:port>在同一个实例上只能使用一次,而且小于1024的端口需要有特定权限的用户才能使用,这可能需要通过uid参数来定义;
<interface>:指定物理接口的名称,仅能在Linux系统上使用;其不能使用接口别名,而仅能使用物理接口名称,而且只有管理有权限指定绑定的物理接口;
示例:
1) 编辑配置文件,适用bind监听多个地址;
2) 重启haproxy,查看端口;
3. mode {tcp|http|health}:设定haproxy工作模式
设定实例的运行模式或协议。当实现内容交换时,前端和后端必须工作于同一种模式(一般说来都是HTTP模式),否则将无法启动实例。
tcp:实例运行于纯TCP模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查;此为默认模式,通常用于SSL、SSH、SMTP等应用;
http:实例运行于HTTP模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC格式兼容的请求都会被拒绝;
health:实例工作于health模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息;此模式将用于响应外部组件的健康状态检查请求;目前业讲,此模式已经废弃,因为tcp或http模式中的monitor关键字可完成类似功能;
4. log
log global
log <address> <facility> [<level> [<minlevel>]]
为每个实例启用事件和流量日志,因此可用于所有区段。每个实例最多可以指定两个log参数,不过,如果使用了“log global”且"global"段已经定了两个log参数时,多余了log参数将被忽略。
global:当前实例的日志系统参数同"global"段中的定义时,将使用此格式;每个实例仅能定义一次“log global”语句,且其没有任何额外参数;
<address>:定义日志发往的位置,其格式之一可以为<IPv4_address:PORT>,其中的port为UDP协议端口,默认为514;格式之二为Unix套接字文件路径,但需要留心chroot应用及用户的读写权限;
<facility>:可以为syslog系统的标准facility之一;
<level>:定义日志级别,即输出信息过滤器,默认为所有信息;指定级别时,所有等于或高于此级别的日志信息将会被发送;
5. maxconn
maxconn <conns>
设定一个前端的最大并发连接数,因此,其不能用于backend区段。对于大型站点来说,可以尽可能提高此值以便让haproxy管理连接队列,从而避免无法应答用户请求。当然,此最大值不能超出“global”段中的定义。此外,需要留心的是,haproxy会为每个连接维持两个缓冲,每个缓冲的大小为8KB,再加上其它的数据,每个连接将大约占用17KB的RAM空间。这意味着经过适当优化后,有着1GB的可用RAM空间时将能维护40000-50000并发连接。
如果为<conns>指定了一个过大值,极端场景下,其最终占据的空间可能会超出当前主机的可用内存,这可能会带来意想不到的结果;因此,将其设定了一个可接受值方为明智决定。其默认为2000。
6. default_backend:为frontend指明使用的默认后端;
default_backend <backend>
use_backend:条件式后端调用
示例:
use_backend dynamic if url_dyn
use_backend static if url_css url_img extension_img
default_backend dynamic
7. server
server <name> <addr>[:port] [param*]
backup:设定当前server为backup server
check:健康状态检测
inter <delay>:检测时间间隔,单位为ms,默认为2000;
fall:up --> down,soft state,soft state,hard state;
rise:down --> up,
cookie <value>:
maxconn:此服务接受的并发连接的最大数量;
maxqueue:请求队列的最大长度;
observe:根据流量判断后端server的健康状态;
weight:指定权重,默认为1,最大为256;0表示不被调度;
redir <prefix>:重定向,所有发往此服务器的请求均已302响应;
8. 后端http服务时的健康状态的检测方法:
option httpchk
option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>:不能用于frontend段,例如:
backend https_relay
mode tcp
option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www.magedu.com
server apache1 192.168.1.1:443 check port 80
9. 基于浏览器cookie实现session sticky
backend webserver
balance roundrobin
cookie SERVERID insert nocache indirect
server web1 192.168.19.143:80 check weight 1 cookie webserver1
server web2 192.168.19.134:80 check weight 3 cookie webserver2
要点:
1) 每个server有自己唯一的cookie标识;
2) 在backend中定义为用户请求调度完成后操纵器cookie
演示:
1) 编辑配置文件;
2) 重启服务后浏览器测试;
10. 启用stats
listen statistics
bind *:9090
stats enable
stats hide-version 隐藏版本信息;
#stats scope . no restriction
stats uri /haproxyadmin?stats //自定义stats页面的uri,默认为/haproxy?stats
stats realm "HAPorxy\ Statistics" //启用统计信息并设置身份认证域;
stats auth admin:mageedu //定义认证使用的账号和密码;
stats admin if TRUE //条件满足启用stats內建的管理功能接口;不建议启用,有安全隐患;
stats refresh <delay> //自动刷新相关页面的时间间隔;
演示:定义统计页,并配置相关统计页参数
1) 编辑配置文件,开启统计页;
重启haproxy服务,并用浏览器访问测试;
2) 编辑/etc/haproxy/haproxy.cfg配置文件,自定义统计页的uri;
重启服务并测试,输入原来的uri将找不到页面;
输入自定义的uri:
3) 为统计页面添加账号和密码;
重启服务后测试,输入账号密码才能进入统计页面;
4) 隐藏stats统计页面的版本号,定义3s自动刷新一次页面,启动stats管理功能接口;
重启服务并测试;
11. 向日志中记录额外信息:
capture request header
capture request header <name> len <length>
捕获并记录指定的请求首部最近一次出现时的第一个值,仅能用于“frontend”和“listen”区段。捕获的首部值使用花括号{}括起来后添加进日志中。如果需要捕获多个首部值,它们将以指定的次序出现在日志文件中,并以竖线“|”作为分隔符。不存在的首部记录为空字符串,最常需要捕获的首部包括在虚拟主机环境中使用的“Host”、上传请求首部中的“Content-length”、快速区别真实用户和网络机器人的“User-agent”,以及代理环境中记录真实请求来源的“X-Forward-For”。
<name>:要捕获的首部的名称,此名称不区分字符大小写,但建议与它们出现在首部中的格式相同,比如大写首字母。需要注意的是,记录在日志中的是首部对应的值,而非首部名称。
<length>:指定记录首部值时所记录的精确长度,超出的部分将会被忽略。
可以捕获的请求首部的个数没有限制,但每个捕获最多只能记录64个字符。为了保证同一个frontend中日志格式的统一性,首部捕获仅能在frontend中定义。
演示:向日志添加额外信息;
1) 编辑配置文件;
2) 修改后端服务器httpd的配置文件,修改日志格式;
3) 在代理服务器上重启服务,并用浏览器测试访问,查看后端服务器的日志;
capture response header
capture response header <name> len <length>
捕获并记录响应首部,其格式和要点同请求首部。
12. 当mode为httpd时,记录丰富的日志信息;
option httplog
13. 错误页面重定向:
errorfile <code> <file>
在用户请求不存在的页面时,返回一个页面文件给客户端而非由haproxy生成的错误代码;可用于所有段中。
<code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;
<file>:指定用于响应的页面文件;
errorfile:使用haproxy主机本地文件进行响应;
errorloc,errorloc302:使用指定的url进行响应,响应状态码为302;不适用于GET以外的其它请求方法;
errorloc 303:返回303状态码;
14. 添加请求或响应报文首部;(适用范围:frontend,backend,listen)
reqadd <string> [{if | unless} <cond>]:在请求报文添加一个首部信息;
rspadd <string> [{if | unless} <cond>]:在响应报文添加一个首部信息;
reqdel <search> [{if | unless} <cond>]:删除请求报文首部
reqidel <search> [{if | unless} <cond>]:删除请求报文首部(忽略大小写)
rspdel <search> [{if | unless} <cond>]:删除响应报文首部;
rspdel <search> [{if | unless} <cond>]:删除响应报文首部(忽略大小写);
15. 访问控制ACL
haproxy的ACL用于实现基于请求报文的首部、响应报文的内容或其它的环境状态信息来做出转发决策,这大大增强了其配置弹性。其配置法则通常分为两步,首先去定义ACL,即定义一个测试条件,而后在条件得到满足时执行某特定的动作,如阻止请求或转发至某特定的后端。定义ACL的语法格式如下。
acl <aclname> <criterion> [flags] [operator] <value> ...
<aclname>:ACL名称,区分字符大小写,且其只能包含大小写字母、数字、-(连接线)、_(下划线)、.(点号)和:(冒号);haproxy中,acl可以重名,这可以把多个测试条件定义为一个共同的acl;
<criterion>:测试标准,即对什么信息发起测试;测试方式可以由[flags]指定的标志进行调整;而有些测试标准也可以需要为其在<value>之前指定一个操作符[operator];
[flags]:目前haproxy的acl支持的标志位有3个:
-i:不区分<value>中模式字符的大小写;
-f:从指定的文件中加载模式;
--:标志符的强制结束标记,在模式中的字符串像标记符时使用;
<value>:acl测试条件支持的值有以下四类:
整数或整数范围:如1024:65535表示从1024至65535;仅支持使用正整数(如果出现类似小数的标识,其为通常为版本测试),且支持使用的操作符有5个,分别为eq、ge、gt、le和lt;
字符串:支持使用“-i”以忽略字符大小写,支持使用“\”进行转义;如果在模式首部出现了-i,可以在其之前使用“--”标志位;
正则表达式:其机制类同字符串匹配;
IP地址及网络地址;
同一个acl中可以指定多个测试条件,这些测试条件需要由逻辑操作符指定其关系。条件间的组合测试关系有三种:“与”(默认即为与操作)、“或”(使用“||”操作符)以及“非”(使用“!”操作符)。
[operator]:
数值匹配:eq,ge,gt,le,lt
字符串匹配:
- exact match (-m str) : 字符串精确匹配
- substring match (-m sub) : 子串匹配
- prefix match (-m beg) : 前缀匹配
- suffix match (-m end) : 后缀匹配
- subdir match (-m dir) : 子目录匹配
- domain match (-m dom) : 域匹配
条件逻辑连接:
AND
OR
block { if | unless } <condition>:条件匹配阻断一个7层请求
常用的测试标准:
1) src,dst,src_port,dst_port
示例:
acl invalid_src src 0.0.0.0/7 224.0.0.0/3
acl invalid_src src_port 0:1023
acl local_dst hdr(host) -i localhost
block if invalid_src || local_dst
2) be_sess_rate <integer>
be_sess_rate(backend) <integer>
用于测试指定的backend上会话创建的速率(即每秒创建的会话数)是否满足指定的条件;常用于在指定backend上的会话速率过高时将用户请求转发至另外的backend,或用于阻止攻击行为。例如:
backend dynamic
mode http
acl being_scanned be_sess_rate gt 50
redirect location /error_pages/denied.html if being_scanned
3) fe_sess_rate <integer>
fe_sess_rate(frontend) <integer>
用于测试指定的frontend(或当前frontend)上的会话创建速率是否满足指定的条件;常用于为frontend指定一个合理的会话创建速率的上限以防止服务被滥用。例如下面的例子限定入站邮件速率不能大于50封/秒,所有在此指定范围之外的请求都将被延时50毫秒。
frontend mail
bind :25
mode tcp
maxconn 500
acl too_fast fe_sess_rate ge 50
tcp-request inspect-delay 50ms
tcp-request content accept if ! too_fast
tcp-request content accept if WAIT_END
4) hdr <string>
hdr(header) <string>
用于测试请求报文中的所有首部或指定首部是否满足指定的条件;指定首部时,其名称不区分大小写,且在括号“()”中不能有任何多余的空白字符。测试服务器端的响应报文时可以使用shdr()。例如下面的例子用于测试首部Connection的值是否为close。
hdr(Connection) -i close
5) method <string>
method <string>
测试HTTP请求报文中使用的方法。
6) path_beg <string>
用于测试请求的URL是否以<string>指定的模式开头。下面的例子用于测试URL是否以/static、/images、/javascript或/stylesheets头。
acl url_static path_beg -i /static /images /javascript /stylesheets
7) path_end <string>
用于测试请求的URL是否以<string>指定的模式结尾。例如,下面的例子用户测试URL是否以jpg、gif、png、css或js结尾。
acl url_static path_end -i .jpg .gif .png .css .js
8) hdr_beg <string>
用于测试请求报文的指定首部的开头部分是否符合<string>指定的模式。例如,下面的例子用记测试请求是否为提供静态内容的主机img、video、download或ftp。
acl host_static hdr_beg(host) -i img. video. download. ftp.
9) hdr_end <string>
用于测试请求报文的指定首部的结尾部分是否符合<string>指定的模式。
动静分离示例:
global
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
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 30000
listen stats
mode http
bind 0.0.0.0:1080
stats enable
stats hide-version
stats uri /haproxyadmin?stats
stats realm Haproxy\ Statistics
stats auth admin:admin
stats admin if TRUE
frontend http-in
bind *:80
mode http
log global
option httpclose
option logasap
option dontlognull
capture request header Host len 20
capture request header Referer len 60
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.16.200.7:80 check maxconn 6000
server imgsrv2 172.16.200.8:80 check maxconn 6000
backend dynamic_servers
cookie srv insert nocache
balance roundrobin
server websrv1 172.16.200.7:80 check maxconn 1000 cookie websrv1
server websrv2 172.16.200.8:80 check maxconn 1000 cookie websrv2
server websrv3 172.16.200.9:80 check maxconn 1000 cookie websrv3
原文地址:http://blog.51cto.com/claude666/2073782