骏马金龙 (新博客:www.junmajinlong.com)

网名骏马金龙,钟情于IT世界里的各种原理和实现机制,强迫症重症患者。爱研究、爱翻译、爱分享。特借此一亩三分田记录自己成长点滴!!!

haproxy配置文件详解和ACL功能

HAProxy系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html


haproxy几乎每个大版本都提供了官方手册(内容几乎都相同),手册非常详细。例如haproxy 1.7版本关于配置文件的官方手册:http://cbonte.github.io/haproxy-dconv/1.7/configuration.html

haproxy的灵魂在于配置文件,众多功能都通过配置文件来实现,配置文件中的关键词非常多,各自的概念也较复杂。但实际上真正要配置它时是相当简单的,因为除了自己的需求,很多功能官方都建议采用默认值。

配置文件的重点在于前端(frontend)和后端(backend)的定制。全局选项(global)的配置将默认提供的稍微修改下即可。

可以使用haproxy命令行检查配置文件语法是否正确。

haproxy -f /etc/haproxy/phaproxy.cfg -c

或者使用sysv脚本的check参数。

service haproxy check

1.1 配置文件说明

HAProxy在启动之前会解析配置文件,有3处配置信息来源:

  • 最优先处理来自haproxy命令行给出的参数。
  • "global"配置段的参数,设定为全局参数。
  • 代理配置段。包括defaults,listen,frontendbackend段。

另外haproxy配置文件引入了引号和转义符:反斜线表示转义符;单引号表示强引用;双引号表示弱引用。如果字符串内需要输入空格,则空格需要进行转义或者通过引号包围,不转义时在配置文件中表示分隔符。

如:

  \    标记一个空白字符以区分它的本义和用作分隔符时的空白符
  \#   to mark a hash and differentiate it from a comment
  \\   to use a backslash
  \'   to use a single quote and differentiate it from strong quoting
  \"   to use a double quote and differentiate it from weak quoting

下面几种情况是等价的:

log-format %{+Q}o\ %t\ %s\ %{-Q}r
log-format "%{+Q}o %t %s %{-Q}r"
log-format '%{+Q}o %t %s %{-Q}r'
log-format "%{+Q}o %t"' %s %{-Q}r'
log-format "%{+Q}o %t"' %s'\ %{-Q}r

在配置文件中,一些包含了数值的参数表示时间,如timeout。这些值默认以毫秒为单位,但也可以使用其它的时间单位后缀。

  • us: 微秒(microseconds),即1/1000000秒;
  • ms: 毫秒(milliseconds),即1/1000秒;
  • s: 秒(seconds);
  • m: 分钟(minutes);
  • h:小时(hours);
  • d: 天(days);

1.2 简单配置示例

以下是一个简单的配置文件,该配置文件代理模式为http,frontend定义的是监听在前端所有网卡的80端口上,此文件中只定义了一个后端服务器组backend,该backend只包含一台监听在127.0.0.1:8000的服务器。在haproxy的术语中,frontend表示的是监听套接字,用于等待客户端的连接。

    global
        daemon
        maxconn 256

    defaults
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms

    frontend http-in
        bind *:80
        default_backend web_servers

    backend web_servers
        server server1 127.0.0.1:8000 maxconn 32

如果使用listen配置方式替换backend和frontend,则更简单,以下是等价配置:

    global
        daemon
        maxconn 256

    defaults
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms

    listen http-in
        bind *:80
        server server1 127.0.0.1:8000 maxconn 32

1.3 全局配置参数

全局配置参数设定haproxy进程运行环境,一般和操作系统指定的值有关,配置正确后一般都不会去修改。全局配置参数一般都有对应的命令行选项。

1.进程管理及安全相关的参数。

haproxy是单进程、事件驱动、非阻塞模型的调度器。虽然是单进程,但官方强烈建议不要设置为多进程,因为单进程可以处理很多个代理连接请求且性能极好(官方手册说30W个代理实例都能良好运行),设置为多进程反而有一些限制。

  • chroot :修改haproxy工作目录至指定目录,可提升haproxy安全级别,但要确保必须为空且任何用户均不能有写权限;
  • daemon:让haproxy以守护进程的方式工作于后台,等同于命令行的"-D"选项,当然,也可以在命令行中以"-db"选项将其禁用;(建议设置项)
  • uid/user:以指定的UID或用户名身份运行haproxy进程;
  • gid/group:以指定的GID或组名运行haproxy,建议使用专用于运行haproxy的GID,以免因权限问题带来风险;
  • log:定义全局的syslog服务器,接收haproxy启动和停止的日志。最多可以定义两个;
  • log <address> <facility> [max level [min level]]
  • log-send-hostname [string]:在日志的最前面记录本机主机名或string。远程发送到日志服务器时可由此知道是haproxy主机发送的。
  • pidfile:等同于命令行的"-p"选项。使用服务启动脚本启动haproxy时建议不要设置该项,以保证脚本能正确获取pid文件。
  • nbproc :指定启动的haproxy进程个数,只能用于守护进程模式的haproxy;默认只启动一个进程,一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;(官方强烈建议不要设置该选项)
  • ulimit-n:设定每进程能够打开的最大文件描述符数量,默认haproxy会自动进行计算,因此不推荐修改此选项;(不建议设置项)
  • stats:和多进程haproxy有关,由于不建议使用多进程,所以也不建议设置此项。但建议设置为"stats socket"将套接字和本地文件进行绑定,如"stats socket /var/lib/haproxy/stats"。
  • node:定义当前节点的名称,用于HA场景中多haproxy进程使用相同IP地址时分辨哪个node正处于使用状态;

2.性能调整相关的参数。

  • maxconn :设定每haproxy进程所接受的最大并发连接数,当达到此限定连接数后将不再接受新的连接。该参数特指和客户端的连接数,不包括和服务端的连接。等同于命令行选项"-n";"ulimit -n"就是根据此值进行自动调整的;
  • maxpipes :haproxy在使用splice()在内核中零复制时,是使用pipe传递进行报文粘接重组的,此选项用于设定每进程所允许使用的最大pipe个数;每个pipe会打开两个文件描述符,因此"ulimit -n"自动计算时会按需调大此值;默认值为maxconn/4。调小时会影响一定的性能;
  • noepoll:在Linux系统上禁用epoll机制;(不建议设置此项)
  • nokqueue:在BSD系统上禁用kqueue机制;
  • nopoll:禁用poll机制;
  • nosplice:禁止在Linux套接字上使用内核tcp重组,这会导致更多的recv/send系统调用;(在内核版本2.6.28之后极度不建议设置此项)
  • spread-checks <0..50, in percent>:在haproxy后端有着众多服务器的场景中,在精确的时间间隔后统一对众服务器进行健康状况检查可能会带来意外问题;此选项用于将其检查的时间间隔长度上增加或减小一定的随机时长;默认为0,官方建议设置为2到5之间。(建议设置项)
  • tune.bufsize :设定buffer的大小,同样的内存条件下,较小的值可以让haproxy有能力接受更多的并发连接,较大的值可以让某些应用程序使用较大的cookie信息;默认为16384,可在编译时修改,不过强烈建议使用默认值;(不建议设置项)
  • tune.chksize :设定检查缓冲区的大小,单位为字节;更大的值有助于在较大的页面中完成基于字符串或正则pattern的文本查找,但也会占用更多的系统资源;(不建议设置项)
  • tune.maxaccept :设定haproxy进程内核调度运行时一次性可以接受的连接的个数,较大的值可以带来较大的吞吐率,默认在单进程模式下为100,多进程模式下为8,设定为-1可以禁止此限制;(不建议设置项)
  • tune.maxpollevents :设定一次io复用时系统调用可以处理的事件最大数,默认值取决于OS;其值小于200时可节约带宽,但会略微增大网络延迟,而大于200时会降低延迟,但会稍稍增加网络带宽的占用量;(不建议设置项)
  • tune.maxrewrite :设定为首部重写或追加而预留的缓冲空间,建议使用1024左右的大小;在需要使用更大的空间时,haproxy会自动增加其值;(不建议设置项)
  • tune.rcvbuf.client :设定两端的recv_buff大小(haproxy和客户端建立tcp,和后端服务器建立tcp,共两端,因此有两个recv_buff和两个send_buff)。单位为字节;(强烈推荐使用默认值)
  • tune.rcvbuf.server :(强烈推荐使用默认值)
  • tune.sndbuf.client:设定两端的send_buff大小(强烈推荐使用默认值)
  • tune.sndbuf.server:(强烈推荐使用默认值)

因此,抛去不建议设置的项后,global段的设置大致如下:这也是yum安装haproxy时默认提供的配置

global
    daemon
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    stats socket /var/lib/haproxy/stats

注意上面配置了使用local2记录log,因此还需去rsyslogd的配置文件中添加该设备以及记录的日志位置。如下:

cat <<eof>>/etc/rsyslog.conf
  local2.*     /var/log/haproxy.log
eof

1.4 proxy配置段和常用配置选项

proxy配置部分是haproxy最重要的配置部分,包含下面四种配置段:

  • defaults []:设置frontend/backend/listen配置段的默认值。
  • frontend :配置监听客户端连接的套接字。
  • backend :配置haproxy所代理的后端服务器组。
  • listen :定义一个完整的前端和后端代理,但后端可以不定义。所以有时候等价于frontend+backend。它常用于绑定前后端1对1的情况。

所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、_(下划线)、.(点号)和:(冒号)。此外,ACL名称会区分字母大小写。

目前,有两种主流的代理模式:tcp代理(即所谓的4层代理)和http代理(即所谓的7层代理)。在4层代理模式下,haproxy简单的在两端进行双向转发。在7层代理模式下,haproxy会对协议进行分析,可以根据协议来允许、阻塞、切换、增加、修改和移除request或response中的属性内容。

1.4.1 http事务模型相关设置

  1. (no) option http-keep-alive
    启用或禁用客户端和服务端到haproxy之间的长连接。haproxy将处理所有请求和响应报文,请求完后haproxy两端的连接都处于空闲状态。由于和后端保持了连接,可以以最快的方式重用会话。
  2. (no) option http-server-close
    启用或禁用在haproxy处理完第一次响应之后关闭haproxy到服务端之间长连接的功能,但客户端的长连接还保持,后续的每次请求都重新建立和后端的连接,每次响应后都关闭和后端的连接。启用该选项时,haproxy将会在转发给后端server的request数据包中添加一个"Connection:Close"标记,后端Server看到此标记就会在响应后关闭tcp连接。
  3. (no) option http-tunnel
    启用或禁用在haproxy处理完第一次请求和响应后关闭haproxy两端长连接的功能。在1.0-1.5.21版本该项是默认项,但现在不建议使用,因为会产生一些问题。
  4. (no) option forceclose
    启用或禁用传输完响应报文后关闭两端的连接。
  5. (no) option htthttpcloseose(废弃选项)
  6. (no) option http-pretend-keepalive
    有些服务器会无视带有"Connection:Close"标记的请求,从而http-server-close的后端发送响应后不会关闭tcp连接。设置该选项时,haproxy在收到响应后会主动关闭和后端的连接。不建议设置该选项,因为绝大多数服务器都能正常工作并且有很好的调整能力。

一般来说,对于高速局域网络来说,如果后端响应的速度非常快(比如后端是静态服务器响应小文件、后端是静态缓存服务器),这时建立tcp连接的代价就比较大,维持空闲连接的优势会非常明显。如果后端是动态应用程序,响应给haproxy的速度相对较慢,维持空闲连接的代价非常大,完全可以先释放长连接以腾出资源,在需要连接的时候再建立新tcp连接。因此:

(1).后端是静态内容缓存服务器时,或者就是静态服务器时,首选使用http-keep-alive模式;

(2).后端是动态应用程序服务器时,首选使用http-server-close模式

默认情况下,如果客户端请求根据调度算法被调度到另一台后端服务器时,http-keep-alive模式下和后端服务器的空闲连接会立即断开,并重新和被调度选中的后端服务器建立连接。可以使用"prefer-last-server"选项,使得haproxy先查看当前保持的空闲连接是否可用,如果可用,则继续使用该空闲连接,但是这样会影响调度性能。

frontend和backend都可以设置这些模式选项,如果它们交叉设置了,最终何种模式会生效?例如,frontend设置了http-keep-alive,而bakcend设置了http-server-close时,取何种模式?计算方式采用如下矩阵:keepalive优先级是最弱的,forceclose是优先级是最高的。

1.4.2 balance

balance <algorithm>
可用于default、listen、backend配置段。

指定代理时负载均衡算法,支持的算法有:

  1. roundrobin(默认):根据权重进行轮询,在服务器的处理时间保持均匀分布时,这是最平衡、最公平的算法。此算法是动态的,表示权重可以在haproxy运行时调整后端服务器的权重并生效;
  2. static-rr:基于权重进行轮询,与roundrobin类似,但是为静态方法,在haproxy运行时调整其服务器权重不会生效;
  3. leastconn:新的连接请求被派发至具有最少连接数目的后端服务器;在有着较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如HTTP;此算法是动态的,可以在运行时调整其权重;
  4. source:将请求的源地址进行hash运算,使得同一个客户端IP的请求始终被派发至某特定的服务器;但当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;类似于nginx的ip_hash,可用于负载均衡无cookie功能的基于TCP的协议。默认为静态;
  5. uri:对URI的左半部分("?"标记之前的部分)进行hash运算,并除以服务器的总权重来计算派发至某匹配服务器;这可以使得对同一个URI的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存以提高缓存的命中率;但此算法仅应用于提供http服务的后端服务器;默认为静态算法;缺点是后端server宕机会造成严重抖动,可以通过hash-type设置hash算法为一致性哈希解决。
  6. url_param:一般用于将同一用户ID转发至同一服务器的情况。在使用了basic认证时,url中的param一般都会使用user=XXX。使用该算法会对该参数进行hash运算,然后除以总权重以决定分配到哪台后端server。
  7. hdr(name):基于指定的请求首部名称进行调度。首部中指定名称相同的调度至同一服务器。一般使用"hdr(host)"根据请求首部中的host即目标主机来进行hash运算。使用use_domain_only选项可以基于域名来哈希,使得访问www.longshuai.com和web.longshuai.com的请求都调度至同一服务器。
  8. rdp-cookie
  9. rdp-cookie(name)

roundrobin和static-rr是有区别的,roundrobin是动态慢轮询,不用重启服务即可调整其权重,而static-rr必须重启服务修改的权重才生效。例如原有2台后端server,新添加一台后,roundrobin会从此时开始慢慢的将请求轮询至此新服务器,而static-rr由于需要重启,所以重启前新server不会被调度到,重启后新server和旧server平均调度。一般来说,考虑加权轮询的时候,roundrobin要比static-rr好。

一般可纳入考虑的算法有roundrobin/static-rr/leastconn/uri,其中leastconn算法用于代理ldap、mysql等长时间会话连接的情况,uri算法用于代理后端为缓存服务器的情况。

(1). 用于调度MySQL服务器,使用何种算法?答:leastconn
(2). 用于调度静态服务器组,使用何种算法?答:roundrobin
(3). 调度动态应用程序服务器组,使用何种算法?答:通常客户端需要和后端应用程序服务器保持联系,一般会使用cookie或者session来实现,但如果特殊情况下无法通过它们实现,则可以使用source作为最后"亲和性"手段。注意,使用source算法时,后端服务器数量一改变,就会导致大量的会话断开。
(4). 调度缓存服务器,使用何种算法?答:uri,且设置hash-type为一致性哈希算法。

1.4.3 hash-type

hash-type <method>
不能用于frontend区段

定义用于将hash码映射至后端服务器的方法;可用方法有map-based和consistent,一般情况推荐使用默认的map-based方法。

  • map-based:hash表是一个包含了所有在线服务器的静态数组。其hash值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时,大多数连接将会被重新派发至一个与此前不同的服务器上。对于缓存服务器的工作场景来说,此方法不适用。
  • consistent:(一致性哈希算法)hash表是一个由各服务器填充而成的树状结构;基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。

1.4.4 bind

bind [<address>]:<port_range> [, ...]
bind [<address>]:<port_range> [, ...] interface <interface>
能用于frontend和listen段

用于定义一个或几个监听的套接字。

  • <address>:可选项,可以为主机名、IPv4地址、IPv6地址或*;省略此选项、将其指定为*或0.0.0.0时,将监听当前系统的所有IPv4地址;
  • <port_range>:可以是一个特定的TCP端口,也可是一个端口范围(如5005-5010),代理服务器将通过指定的端口来接收客户端请求;注意,小于1024的端口需要有特定权限的用户才能使用;
  • <interface>:指定物理接口的名称;

例如:

    bind :80,:443
    bind 10.0.0.1:10080,10.0.0.1:10443

1.4.5 mode

指定haproxy实例运行模式。可为tcp、http。tcp为4层代理模式,不会对协议进行任何分析,只是单纯地转发数据包,如HTTPS/MYSQL等,http为7层代理模式。如果所有配置区段都没有设置mode,则默认为tcp模式。

1.4.6 log

log global
log <address> <facility> [<level> [<minlevel>]]

为每个实例启用事件和流量日志,因此可用于所有区段。每个实例最多可以指定两个log参数。配置方法和意义同前文全局配置参数的log。

如果使用log global,则表示从全局继承日志设置。另外,如果全局已经定义过两个log了,此处除引用global外还自定义了一个log,则此自定义的log失效,因为只支持两个日志设置。

1.4.7 capture request header和capture response header

capture request header <name> len <length>
capture response header <name> len <length>
仅能用于"frontend""listen"区段

捕获并记录最近一次出现的指定请求首部或响应首部。请求首部是从客户端发起的请求首部,响应首部是从后端server响应并在haproxy准备发送给客户端前捕获的。捕获的首部值使用大括号{}括起来后会添加进日志中。如果需要捕获多个首部值,它们将以指定的秩序出现在日志文件中,并以竖线"|"作为分隔符。不存在的首部记录为空字符串。

最常需要捕获的请求首部包括:在虚拟主机环境中使用的"Host"、上传请求首部中的"Content-length"、快速区别真实用户和网络机器人的"User-agent",以及代理环境中记录请求真实来源的"X-Forward-For"。

一般需要捕获的响应首部为:记录还有多少内容需要接收的"Content-length"、跟踪重定向路径的"Location"。

  • <name>:要捕获的首部的名称,此名称不区分字符大小写,但建议与它们出现在首部中的格式相同,比如大写首字母。需要注意的是,记录在日志中的是首部对应的值,而非首部名称。
  • <length>:指定记录首部值时所记录的精确长度,超出的部分将会被忽略。

可以捕获的请求首部的个数没有限制,但每个捕获最多只能记录64个字符。为了保证同一个frontend中日志格式的统一性,首部捕获仅能在frontend中定义。

例如:

capture request header Host len 15
capture request header X-Forwarded-For len 15
capture request header Referer len 15
capture response header Content-length len 9
capture response header Location len 15

1.4.8 maxconn

maxconn <conns>
不能用于backend区段

设定一个前端的最大并发连接数。对于大型站点来说,可以尽可能提高此值以便让haproxy管理连接队列,从而避免无法应答用户请求。当然,此最大值不能超出"global"段中的定义。此外,haproxy会为每个连接维持两个缓冲,每个缓冲的大小为16KB,再加上其它的数据,每个连接将大约占用33KB的RAM空间。这意味着经过适当优化后,有着1GB的可用RAM空间时将能维护20000-25000并发连接。

如果为指定了一个过大值,极端场景下,其最终占据的空间可能会超出当前主机的可用内存,这可能会带来意想不到的结果;因此,将其设定了一个可接受值方为明智决定。默认为2000。

1.4.9 use_backend

use_backend <backend> [{if | unless} <condition>]

定义当满足或不满足什么条件时使用哪个backend。条件判断是可选的,并且condition是基于acl的条件。

1.4.10 default_backend

default_backend <backend>
不可应用于backend区段。

在没有匹配的"use_backend"规则时为实例指定默认后端。在"frontend"和"backend"之间进行内容交换时,通常使用"use-backend"定义匹配规则;而没有被规则匹配到的请求将由此参数指定的后端接收。

例如,已有两组backend,名称分别为dynamic和static,当不匹配use_backend时将默认使用dynamic作为转发后端。

use_backend     dynamic  if  url_dyn
use_backend     static   if  url_css url_img extension_img
default_backend dynamic

1.4.11 server和default-server

server <name> <address>[:port] [param*]
声明后端server,因此不能用于defaults和frontend区段。
default-server [param*]
指定server的默认参数值,不能用于frontend区段

-<name>:为此服务器指定的内部名称,将出现在日志及警告信息中;

  • <address>:此服务器的IPv4地址,也支持使用可解析的主机名;
  • [:port]:haproxy将请求转发至后端服务器的哪个端口,为可选项;未设定时,将使用客户端请求时的同一端口;
  • [param*]:为此服务器设定的一系列参数;可用的参数非常多,下面是几个常用的参数;

服务器或默认服务器参数:

  • backup:设定为备用服务器,当其它所有后端server均不可用时将启用此server;
  • disabled:禁用此后端服务器。
  • check:启动对此server执行健康状态检查,但需要配合定义在backend的具体检查方法(如httpcheck,mysql-check)才会进行指定的检查方式,不指定检查方法时将默认以tcp方式检查。check可以借助于额外的参数完成更精细的设定,如:
    • inter <delay>:设定健康状态检查的时间间隔,单位为毫秒,默认为2000;
    • rise <count>:设定server从离线状态重新上线需要成功检查的次数;不指定默认为2,一般可设置为1。
    • fall <count>:确认server从正常状态转换为不可用状态需要检查的次数;默认为3。
  • cookie <value>:为指定server设定cookie值,指定的值将在请求入站时被检查,第一次为此值挑选的server将在后续的请求中被选中,其目的在于实现基于客户端cookie的持久连接;
  • maxconn <maxconn>:指定此后端服务器接受的最大并发连接数(不同于全局设置的maxconn,全局的maxconn是面向客户端的);如果发往此服务器的连接数高于指定的值,将被放于请求队列以等待其它连接释放;
  • maxqueue <maxqueue>:设定请求队列的最大长度;
  • observe <mode>:通过观察服务器的通信状况来判定其健康状态,默认禁用,支持的类型有"layer4"和"layer7",layer4表示检查tcp连接是否正常,layer7仅用于http代理场景,通过后端server发送的response来判断,例如可以判断状态码,响应报文头部是否无法解析等;
  • redir <prefix>:启用重定向功能,将发往此服务器的GET和HEAD请求均以302状态码响应,意味着不会将请求转发至后端服务器;在prefix后面不能使用/,且不能使用相对地址;例如:
    server srv1 192.168.1.1:80 redir http://image1.mydomain.com check
    
  • weight <weight>:权重,默认为1,最大值为256,0表示不参与负载均衡,即认为下线了不进行调度;

关于maxconn和maxqueue,这两个值都是此后端服务器的值。它们的大小和全局定义的maxconn是有一定大小比较关系的。如果没有定义maxqueue,则全局maxconn应该小于或等于后端所有服务器的maxconn之和,如果定义了maxqueue,则需要小于或等于后端所有服务器的maxconn和maxqueue之和。否则haproxy接收进来的请求超过后端服务器的压力极限,可能压垮后端。

例如:

server first  10.1.1.1:1080 cookie first  check inter 1000
server second 10.1.1.2:1080 cookie second check inter 1000
server backup "${SRV_BACKUP}:1080" backup
server www1_dc1 "${LAN_DC1}.101:80"
server www1_dc2 "${LAN_DC2}.101:80"
default-server inter 1000 weight 13

1.4.12 option httpchk

option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>
不能用于frontend段。

此指令表示基于http协议来做健康状况检查,只有返回状态码为2xx或3xx的才认为是健康的,其余所有状态码都认为不健康。不设置该选项时,默认采用tcp做健康检查,只要能建立tcp就表示健康。

  • uri:检查的uri路径,默认为"/"。接受带有查询参数的uri
  • method:http检查时使用的METHOD。不指定时默认为"OPTIONS"方法,也建议采用此方法,因为该请求方法对服务器造成的资源损耗最小。
  • version:检查的http协议版本,默认为http/1.0,但现在很多都采用HTTP/1.1,因此此处检查版本需要修改为HTTP/1.1,但对于该版本的HTTP协议来说,还强制要求指定Host,中间使用\r\n隔离。

例如下面的配置,会将健康检查时的页面请求发送至后端192.168.1.1的80端口来确定该后端是正常的,但客户端的请求将转发至该后端的443端口。

backend https_relay
    mode tcp
    option httpchk
    option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www
    server apache1 192.168.1.1:443 check port 80

1.4.13 stats相关

  • stats enable:启用基于程序编译时默认设置的统计报告,不能用于"frontend"区段。

只要没有另外的其它设定,默认就会使用如下的配置:

  - stats uri   : /haproxy?stats
  - stats realm : "HAProxy Statistics"
  - stats auth  : no authentication
  - stats scope : no restriction

尽管"stats enable"一条就能够启用统计报告,但还是建议设定其它所有的参数,以免依赖于默认设定而带来非预期后果。

例如:

  backend public_www
    server websrv1 172.16.100.11:80
    stats enable
    stats hide-version
    stats scope   .
    stats uri     /haproxyadmin?stats
    stats realm   Haproxy\ Statistics
    stats auth    statsadmin:password
    stats auth    statsmaster:password
  • stats hide-version:启用统计报告并隐藏HAProxy版本报告,不能用于"frontend"区段。
  • stats realm:stats auth身份认证时的提示信息。设置的提示信息中,如果有空白字符,则需要转义。仅在与"stats auth"配合使用时有意义。
  • stats auth:启用带认证的统计报告功能并授权一个用户帐号和对应的密码(明文)。也就是说,想要查看统计报告需要提供身份和密码。不能用于"frontend"区段。
  • stats admin:满足指定条件时启用统计报告页面的管理功能,它允许通过web接口启用或禁用后端服务器
    stats admin { if | unless } <cond>
    

下面是两个案例,第一个限制了仅能在本机打开报告页面时启用管理功能,第二个定义了仅允许通过认证的用户使用管理功能。

backend stats_localhost
    stats enable
    stats admin if LOCALHOST

backend stats_auth
    stats enable
    stats auth  haproxyadmin:password
    stats admin if TRUE

1.4.14 option forwardfor

option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

允许在发往服务器的请求首部中插入"X-Forwarded-For"首部。

  • except <network>:可选参数,当指定时表示请求中的源地址能匹配此网络时禁用此功能。
  • header <name>:可选参数,自定义首部名,如"X-Client"来替代"X-Forwarded-For"。有些独特的web服务器的确需要一个独特的首部。
  • if-none:仅在此首部不存在时才将其添加至请求报文问道中。

HAProxy工作于反向代理模式,其发往服务器的请求中的客户端IP均为HAProxy主机的地址而非真正客户端的地址,这会使得服务器端的日志信息记录不了真正的请求来源,"X-Forwarded-For"首部则可用于解决此问题。HAProxy可以向每个发往服务器的请求上添加此首部,并以客户端IP为其value。

下面是一个例子。

frontend www
    mode http
    option forwardfor except 127.0.0.1

1.4.15 错误页面相关

  1. errorfile
    errorfile <code> <file>
    
    在用户请求不存在的页面时,返回一个页面文件给客户端而非由haproxy生成的错误代码;可用于所有段中。
    • <code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;
    • <file>:指定用于响应的页面文件;
      例如:
      errorfile 400 /etc/haproxy/errorpages/400badreq.http
      errorfile 403 /etc/haproxy/errorpages/403forbid.http
      errorfile 503 /etc/haproxy/errorpages/503sorry.http
      
  2. errorloc和errorloc302
    errorloc <code> <url>
    errorloc302 <code> <url>
    
    请求错误时,返回一个HTTP重定向至某URL的信息;可用于所有配置段中。
    • <code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;
    • <url>:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需另外,这两个关键字都会返回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自身错误时产生某特定状态码信息的话,有可能会导致循环定向;

例如:

backend webserver
  server 172.16.100.6 172.16.100.6:80 check maxconn 3000 cookie srv01
  server 172.16.100.7 172.16.100.7:80 check maxconn 3000 cookie srv02
  errorloc 403 /etc/haproxy/errorpages/sorry.htm
  errorloc 503 /etc/haproxy/errorpages/sorry.htm

在backend服务器组启用cookie功能,以便实现cookie绑定。需要同时设置server指令中的cookie选项。

后端为静态服务器设置:
cookie NAME insert nocache
PHP做后端时设置:
cookie SESSION_COOKIE insert indirect nocache

当客户端绑定cookie对应的后端服务器宕机后,应该为此客户端重新调度一个后端server,否则将打不开页面。这时需要使用option redispatch,表示当找不到cookie对应的服务器时分配新的服务器给客户端。

1.4.17 reqadd和rspadd

reqadd  <string> [{if | unless} <cond>]
rspadd  <string> [{if | unless} <cond>]

满足条件时向请求首部或响应首部的尾端添加自定义的字段。条件可选,当不给定条件时表示所有的请求首部或响应首部尾端都添加字段。

其中string包含了字段名和字段值,当然,既然是自定义,值肯定是可以省略的。注意,空白字符需要转义。

例如:

acl is-ssl  dst_port       443
reqadd      X-Proto:\ SSL  if is-ssl

1.4.18 超时时间相关

时间单位默认都是毫秒。

  • timeout http-request
    haproxy等待客户端请求发送完整的超时时长。如果一开始发送了一部分,后续没有再发送,或者后续发送的一直是请求的某一部分,等达到超时时间将断开此连接。这可以防止DoS攻击。
  • timeout queue
    当调度的后端服务器已经满负载了,即达到了该backend的最大并发连接数时,后续要调度到此backend的请求将进入队列等待后端服务器释放可用。该超时时间设置的就是某一请求在队列中的最大等待时长,当达到此时长后将被认为该请求永远无法到达服务端,haproxy会丢弃该请求并向客户端返回503状态码。
  • timeout connect 和retries
    haproxy要和后端服务器建立连接时等待超时时间。一般如果haproxy和后端服务器处于局域网中,建立连接是瞬间的,所以该值可以设置的小一些。
    retries表示和服务端建立连接失败时重试连接的次数。
    注意:在健康检查时,将取timeout connect和inter的较小者作为检查时建立tcp连接的超时时间。
  • timeout client
    客户端和haproxy之间非活动连接保持的最大时长,达到此时长haproxy将断开和此客户端的连接。非活动表示客户端没有请求报文发送给haproxy。
  • timeout server
    服务端和haproxy之间非活动连接保持的最大时长,达到此时长haproxy将断开和此服务器的连接。非活动表示服务端没有响应报文发送给haproxy。
  • timeout http-keep-alive
    等待出现http请求报文出现的最大时长,即和客户端保持长连接的时长。建议设置小一些,以尽快释放连接,例如设置为2-3秒钟。
    如果此项未设置,则使用timeout http-request值,如果timeout http-request也没设置,则使用timeout client的值。
  • timeout check
    在和服务端建立连接后,健康状况检查判断的超时时长(意思是,在建立TCP连接后,后端节点需要响应消息给haproxy,响应的消息可能是(1)httpcheck方式时,经过hash计算的http页面(2)tcp检查方式时的回复消息。如果haproxy隔了一段时间,都没有接收完这些消息,就认为这次检查不健康。因此timeout check是read回应消息的超时时长。而min("timeout connect","inter")则是建立tcp连接的超时时间,它们之和才是一次不健康检查的总时间)。

1.4.19 http协议过滤:http-request

http-request {allow | auth [realm <realm>] | redirect <rule> | deny [deny_status <status>]} [{if | unless} <condition>]

做7层http协议过滤。当http协议相关项满足条件时执行一个action,可以执行的action非常多,此处只列出了几项。

  • allow:表示接受该http请求。
  • auth:表示提示输入用户认证信息,指定realm时将给出提示信息。
  • redirect:重定向功能。
  • deny:表示拒绝该http请求。
acl nagios src 192.168.129.3
acl local_net src 192.168.0.0/16
acl auth_ok http_auth(L1)

http-request allow if nagios
http-request allow if local_net auth_ok
http-request auth realm Gimme if local_net auth_ok
http-request deny

1.4.20 tcp请求和响应过滤

tcp-request content <action> [{if | unless} <condition>] 
tcp-response content <action> [{if | unless} <condition>]

做4层协议过滤。当满足条件时,haproxy对tcp请求或响应报文执行某个action。

对于request而言,只能用于listen和frontend。常用的action是accept和reject,表示满足条件时haproxy接受或拒绝该请求报文。

对于response而言,只能用于listen和backend。常用的action是accept、reject和close,前两者表示满足条件时接受或拒绝该响应报文,close表示满足条件时立即关闭和服务端的连接。

1.5 ACL

1.5.1 ACL语法

acl <aclname> <criterion> [flags] [operator] [<value>] ...

aclname:指定acl的名称,在引用时区分大小写。可随意指定,且多个acl指令可以指定同一个aclname,这表示"或"的逻辑关系。
flags:可选项,表示标识位。一般会用到的标识位只有"-i",表示不区分大小写。
operator:可选项,某些操作符,有"eq""ge""gt""le""lt",表示数学上的等于、大于、小于。
<criterion>:指定检查标准,即检查方法。见下文给出的常用4层标准和7层标准
value:根据criterion的不同,值的类型不同。

(1).4层常用检查标准,官方手册:https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#7.3.3

  • src <ip_addr>
  • src_port <PORT or PORT_ranges>
  • dst <ip_addr>
  • dst_port <PORT or PORT_ranges>

其中src、src_port、dst和dst_port就是检查标准creiterion,其后的值就是value。

例如:

acl accept_clients src 192.168.100.0/24
acl reject_clients src 172.16.0.0/16
tcp-request content accept if accept_clients
tcp-request content reject if reject_clients
tcp-request content reject   # 此项表明不匹配前两项的默认都拒绝

(2).7层常用检查标准,官方手册:https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#7.3.6

  • hdr(HEADER):检查首部字段的值是否为指定的值,如hdr(Connection) -i close表示首部字段Connection的值是否为不区分大小写的close。hdr(Host) -i www.longshuai.com表示首部字段Host的值是否为www.longshuai.com,即请求的主机是否是指定的值。
  • hdr_reg(HEADER):检查首部字段是否匹配指定的模式。如hdr_reg(Host) -i .*\.longshuai\.com
  • http_first_req:当正处理的请求是第一个请求时返回true。
  • method:请求的方法为指定的方法时返回方法对应的数值,也就表示true。例如"method GET"。
    acl valid_method method GET
    http-request deny if ! valid_method
    
  • path:匹配uri的path部分,一般用来匹配精确的文件资源。例如path -i /a.png
  • path_beg:匹配path的前缀部分。
  • path_end:匹配path的后缀部分。
  • path_reg:使用正则表达式来匹配path。
  • url:对整个url进行匹配。
  • url_beg:对url的前缀进行匹配。

还有很多很多检查方法,更多的查询官方手册,太多了。一般4层的检查标准和7层对路径path和首部hdr的标准就够了。

多个条件使用"AND"、"OR"、"!"操作符表示逻辑与、逻辑或和取反,不写时默认的操作符是"AND"。

1.5.2 ACL实现动静分离示例

acl url_static path_beg /static /images /img /css /viedo /download  # 定义静态检查标准
acl url_static path_end .gif .png .jpg .css .js .bmp                # 定义静态检查标准
acl host_www   path /index.html                                     # 为主页专门定制acl
acl url_dynamic path_end .php .php5                                 # 定义动态检查标准
acl host_www    hdr_beg(Host) -i www.longshuai.com                  # 定位到主页
use_backend static  if url_static
use_backend dynamic if url_dynamic
use_backend www if host_www
posted @ 2018-03-03 18:23  骏马金龙  阅读(10193)  评论(5编辑  收藏  举报