HAProxy基础

一、简介

  HAProxy是由C语言编写基于事件驱动模型的一款高效稳定、功能强大的负载均衡软件,其性能可媲美商业负载均衡软件,不过在最新的版本中HAProxy已经分为社区版本和企业版,社区版完全免费,企业版有丰富的额外功能。

优缺点:

优点
  1. 支持虚拟主机的,通过frontend指令来实现
  2. 能弥补Nginx的一些缺点比如Session的保持,Cookie的引导等工作
  3. 支持后端服务器健康检查,自动实现故障转移;
  4. 它跟LVS一样,本身仅仅就只是一款负载均衡软件,单纯从效率上来讲HAProxy更会比Nginx有更出色的负载均衡速度,在并发处理上也是优于Nginx;
  5. 同时支持四层和七层代理模式;
  6. 能对请求的url和header中的信息做匹配,更细粒度的七层负载均衡;
  7. 自带监控管理web页面;
  8. 能从进出两个方向修改http头信息;
  9. 同样支持多种负载均衡算法;

缺点

  1. 重载配置的功能需要重启进程,虽然也是 soft restart,但没有 Nginx 的 reaload 更为平滑和友好。
  2.  不支持 HTTP cache 功能(不知道最新版是否支持)。

二、安装配置

  HAProxy安装方式可以是yum安装或源码安装。yum安装的版本都是当前合适系统的稳定版本,个人喜欢使用yum安装。

安装

yum install haproxy -y #centos7默认安装版本是1.5
#主程序:/usr/sbin/haproxy
#配置文件:/etc/haproxy/haproxy.cfg
#启动服务:systemctl start haproxy
#停止服务:systemctl stop haproxy   
#开机启动:systemctl enable haproxy

配置文件结构

haproxy配置文件可分为全局配置(globalsettings)和 代理配置(proxies),而代理段配置包含defaults、frontend、backend、listen。
global settings:#全局参数配置,主要用于定义haproxy进程管理安全及性能相关的参数
defaults <name>:#默认配置参数,下面的段继承该配置,名称是可选的,这配置默认配置参数可由下一个"defaults"所重新设定
frontend <name>:#前端配置,定义一系列监听的套接字,这些套接字可接受客户端请求并与之建立连接,可以监听多个端口。
backend <name>:#后端配置,定义后台服务器,前端代理服务器将会把客户端的请求调度至这些服务器,类似nginx中的upstream
listen <name>:#定义一组前端和后端的完整代理,可理解为frontend+backend,通常用于tcp流量代理
#ps:name名称必须由大写和小写字母,数字,'-','_','.'组成

配置参数可支持的时间单位

- us : 微秒. 1 microsecond = 1/1000000 s
- ms : 毫秒. 1 millisecond = 1/1000 s
- s  : 秒  1s = 1000ms
- m  : 分 1m = 60s = 60000ms
- h  : 小时   1h = 60m = 3600s = 3600000ms
- d  : 天    1d = 24h = 1440m = 86400s = 86400000ms

一个超级简单的WEB配置示例如下:

global
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

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                 3000

frontend  webserver *:80                #监听80,也可以使用bind定义,类似于nginx中的server
    default_backend             web     #指明代理的后端服务器为web

backend web                             #定义web包含的服务器详细以及使用的算法,类似nginx中的upstream
    balance     roundrobin
    server  web1 10.1.210.52:80 check
    server  web2 10.1.210.53:80 check

说明:在以上配置中frontend段定义了前台代理配置,代理的后端服务器由default_backend指定,web则是代理的真实后端服务器名称,而web的定义由backend 字段负责。

全局配置参数( globalsettings)

chroot: #修改haproxy的工作目录至指定的目录,并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不过需要注意的是确保指定的目录为空目录且任何用户均不能有写权限;
daemon: #让haproxy以守护进程的方式工作于后台,其等同于"-D"选项的功能,当然,也可以在命令行中以"-db"选项将其禁用;
gid: #以指定的GID运行haproxy,建议使用专用于运行haproxy的GID,以避免因权限带来的风险;
group: #同gid,不过这里为指定的组名;
uid: #已指定的UID身份运行haproxy进程;
user: #同uid,但这里使用的为用户名;
log: #定义全局的syslog服务器,最多可以定义两个;
nbproc: #指定启动的haproxy进程个数,只能用于守护进程模式的haproxy;默认为止启动一个进程,鉴于调试困难等多方面的原因,一般只在但进程仅能打开少数文件描述符的场中才使用多进程模式;
pidfile: #pid文件的存放位置;
ulimit-n:  #设定每个进程所能够打开的最大文件描述符,默认情况下其会自动进行计算,因此不建议修改此选项;
node: #定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时;
description: #当前实例的描述信息;
maxconn: #设定每个haproxy进程所接受的最大并发连接数,其等同于命令行选项"-n","ulimit-n"自动计算的结果正式参照从参数设定的;
maxpipes: #haproxy使用pipe完成基于内核的tcp报文重组,此选项用于设定每进程所允许使用的最大pipe个数,每个pipe会打开两个文件描述符,因此,"ulimit -n"自动计算的结果会根据需要调大此值,默认为maxcoon/4;
noepoll: #在linux系统上禁用epoll机制;
nokqueue: #在BSE系统上禁用kqueue机制;
nopoll: #禁用poll机制;
nosepoll: #在linux系统上禁用启发式epoll机制;
nosplice: #禁止在linux套接字上使用tcp重组,这会导致更多的recv/send调用,不过,在linux2.6.25-28系列的内核上,tcp重组功能有bug存在;
spread-checks<0..50,in percent>: #在haprorxy后端有着众多服务器的场景中,在紧缺是时间间隔后统一对中服务器进行健康状况检查可能会带来意外问题,此选项用于将检查的时间间隔长度上增加或减少一定的随机时长,为当前检查检测时间的%;
maxconnrate:#设置每个进程每秒种所能建立的最大连接数量,速率,一个连接里可以有多个会话,也可以没有会话
maxsessrate:#设置每个进程每秒种所能建立的最大会话数量
maxsslconn:#每进程支持SSL 的最大连接数量
tune.bufsize: #设定buffer的大小,同样的内存条件下,较小的值可以让haproxy有能力接受更多的并发连接,较大的值了可以让某些应用程序使用较大的cookie信息,强烈建议使用默认值;
tune.chksize: #设定检查缓冲区的大小,单位为字节,更大的值有助于在较大的页面中完成基于字符串或模式的文本查找,但也会占用更多的系统资源,不建议修改;
tune.maxaccept: #设定haproxy进程内核调度运行时一次性可以接受的连接的个数,较大的值可以带来较大的吞吐量。
tune.maxpollevents: #设定一次系统调用可以处理的事件最大数,默认值取决于OS,其至小于200时可介于带宽,但会略微增大网络延迟,但大于200时会降低延迟,但会稍稍增加网络带宽的占用;
tune.maxrewrite: #设定在首部重写或追加而预留的缓存空间,建议使用1024左右的大小,在需要更大的空间时,haproxy会自动增加其值;
tune.rcvbuf.client: #设定内核套接字中客户端接收缓存区的大小,单位为字节,强烈推荐使用默认值;
tune.rcvbuf.server: #设定内核套接字中服务器接收缓存区的大小,单位为字节,强烈推荐使用默认值;
tune.sndbuf.client: #设定内核套接字中客户端发送缓存区的大小,单位为字节,强烈推荐使用默认值;
tune.sndbuf.server: #设定内核套接字中服务器端发送缓存区的大小,单位为字节,强烈推荐使用默认值;
debug: #调试模式,输出启动信息到标准输出;
quiet: #安装模式,启动时无输出;

defaults默认的配置

defaults
  mode http   #默认负载均衡模式为http
  log global    #日志定义
  option httplog   #启用日志记录HTTP请求,默认haproxy日志记录是不记录HTTP请求
  option dontlognull   #设置日志中不记录空连接。
  option httpclose   # 每次请求完毕后主动关闭http通道
  option forwardfor  except 127.0.0.0/8 #插入x-forward标记,反向代理时候可以通过该字段获取客户端真实IP
  retries 3   # 定义连接后端服务器的失败重连次数
  timeout http-request 10s:#在客户端建立连接但不请求数据时,关闭客户端连接
    timeout queue 1m : #服务器的maxconn时,连接在队列中保持挂起状态而设置的超时时间,想客户端返回503错误
    timeout connect 10s: #定义haproxy将客户端请求转发至后端服务器所等待的超时时长
    timeout client 1m:#客户端非活动状态的超时时长
    timeout server 1m:#客户端与服务器端建立连接后,等待服务器端的超时时长
    timeout http-keep-alive 10s: #定义保持连接的超时时长
    timeout check           10s: #健康状态监测时的超时时间,过短会误判,过长资源消耗
    maxconn                 3000: #每个server最大的连接数

超时参数

timeout http request :#在客户端建立连接但不请求数据时,关闭客户端连接
timeout queue :#等待最大时长
timeout connect: #定义haproxy将客户端请求转发至后端服务器所等待的超时时长
timeout client:#客户端非活动状态的超时时长
timeout server:#客户端与服务器端建立连接后,等待服务器端的超时时长,
timeout http-keep-alive :#定义保持连接的超时时长
timeout check:#健康状态监测时的超时时间,过短会误判,过长资源消耗

三、常用配置参数

bind

bind [<address>]:<port_range> [,...] [param*]
#此指令仅能用于frontend和listen区段,用于定义一个或几个监听的套接字

  • <address>:可选选项,其可以为主机名、IPv4地址、IPv6地址或*;
  • <port_range>:可以是一个特定的TCP端口,也可是一个端口范围(如5005-5010);
  • <param>: 其他格式代理比如sock、ipv6等

示例:

listen http_proxy
    bind :80,:443
    bind 10.0.0.1:10080,10.0.0.1:10443
    bind /var/run/ssl-frontend.sock user root mode 600 accept-proxy

listen http_https_proxy
    bind :80
    bind :443 ssl crt /etc/haproxy/site.pem

listen http_https_proxy_explicit
    bind ipv6@:80
    bind ipv4@public_ssl:443 ssl crt /etc/haproxy/site.pem
    bind unix@ssl-frontend.sock user root mode 600 accept-proxy

listen external_bind_app1
    bind fd@${FD_APP1}

balance

balance <algorithm> [ <arguments> ] 
balance url_param <param> [check_post]
#定义负载均衡算法,可用于defaults、listen和backend段。

algorithm有如下几种算法:
  • roundrobin(默认):根据权重进行轮询,在服务器的处理时间保持均匀分布时,这是最平衡、最公平的算法。此算法是动态的,权重可以在haproxy运行时调整后端服务器的权重并生效,每个后端中最多支持4095个后端服务器;
  • static-rr:基于权重进行轮询,与roundrobin类似,但是为静态方法,在haproxy运行时调整其服务器权重不会生效;
  • leastconn:最少连接数,新的连接请求被派发至具有最少连接数目的后端服务器;在有着较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如HTTP;此算法是动态的,可以在运行时调整其权重;
  • source:将请求的源地址进行hash运算,使得同一个客户端IP的请求始终被派发至某特定的服务器;但当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;类似于nginx的ip_hash,可用于负载均衡无cookie功能的基于TCP的协议。默认为静态;
  • uri:对URI(get传递参数不计入url)进行hash运算,并除以服务器的总权重来计算派发至某匹配服务器;这可以使得对同一个URI的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存以提高缓存的命中率;但此算法仅应用于提供http服务的后端服务器;默认为静态算法;缺点是后端server宕机会造成严重抖动,可以通过hash-type设置hash算法为一致性哈希解决。
  • url_param:对用户请求的uri的<params>部分中的参数的值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个后台服务器;
  • hdr(name):根据请求报文中指定的header(如use_agent, referer, hostname)进行调度;把指定的header的值做hash计算,默认为静态;
  • rdp-cookie :表示根据据cookie(name)来锁定并哈希每一次TCP请求,相同的用户或者相同的会话都会到达后端同一台服务器,如果找不到cookie,会使用roundrobin算法代替; 

mode

mode { tcp|http|health }
#指定代理模式

  • tcp:实例运行于纯TCP模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查;通常用于SSL、SSH、SMTP等应用;
  • http:实例运行于HTTP模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与RFC格式兼容的请求都会被拒绝;此为默认模式;
  • health:实例工作于health模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息;此模式将用于响应外部组件的健康状态检查请求;目前来讲,此模式已经废弃,因为tcp或http模式中的monitor关键字可完成类似功能; 

hash-type

hash-type <method> <function> <modifier>
#用于将hash码映射至后端服务器的方法;可用方法有map-based和consistent,一般情况推荐使用默认的map-based方法。

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

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>:定义日志级别,即输出信息过滤器,默认为所有信息;指定级别时,所有等于或高于此级别的日志信息将会被发送;

示例:

[root@app51 ~]# vi /etc/haproxy/haproxy.cfg
log         127.0.0.1 local2
[root@app51 ~]# systemctl restart haproxy
[root@app51 ~]# vi /etc/rsyslog.conf

###haproxy
$ModLoad imudp
$UDPServerRun 514
local2.*      /var/log/haproxy.log
[root@app51 ~]# systemctl restart rsyslog

capture request header&capture response header

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

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

示例:

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

use_backend& default_backend

use_backend <backend> [{if | unless} <condition>]
#用于定义满足条件的backend,条件判断是可选的,并且condition是基于acl的条件。
default_backend <backend>
#用于指定默认的backend,在没有匹配的”use_backend”规则时为实例指定使用的默认后端。

示例:

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

server

server <name> <address>[:port] [param*]
#为后端声明一个server,因此,不能用于defaults和frontend区段。

  • <name>:为此服务器指定的内部名称,其将出现在日志及警告信息中;如果设定了”http-send-server-name”,它还将被添加至发往此服务器的请求首部中;
  • <address>:此服务器的的IPv4地址,也支持使用可解析的主机名,只不过在启动时需要解析主机名至相应的IPv4地址;
  • [:port]:指定将连接请求所发往的此服务器时的目标端口,其为可选项;未设定时,将使用客户端请求时的同一相端口;
  • [param*]:为此服务器设定的一系参数;其可用的参数非常多,具体请参考官方文档中的说明,下面仅说明几个常用的参数;
服务器或默认服务器参数:
  1. backup:设定为备用服务器,仅在负载均衡场景中的其它server均不可用于启用此server;
  2. check:启动对此server执行健康状态检查,其可以借助于额外的其它参数完成更精细的设定,如:inter <delay>:设定健康状态检查的时间间隔,单位为毫秒,默认为2000;也可以使用fastinter和downinter来根据服务器端状态优化此时间延迟;
  3. rise <count>:设定健康状态检查中,某离线的server从离线状态转换至正常状态需要成功检查的次数;
  4. fall <count>:确认server从正常状态转换为不可用状态需要检查的次数;
  5. cookie <value>:为指定server设定cookie值,此处指定的值将在请求入站时被检查,第一次为此值挑选的server将在后续的请求中被选中,其目的在于实现持久连接的功能;
  6. maxconn <maxconn>:指定此服务器接受的最大并发连接数;如果发往此服务器的连接数目高于此处指定的值,其将被放置于请求队列,以等待其它连接被释放;haproxy 有n个进程,每个支持m个连接,后端有x个服务器,每个最大支持y个连接,则 n*m <= x*y,如果后端服务器支持排队,则n*m <= x*(y+z),z为每个服务器的排队队列
  7. maxqueue <maxqueue>:设定请求队列的最大长度;
  8. observe <mode>:通过观察服务器的通信状况来判定其健康状态,默认为禁用,其支持的类型有“layer4”和“layer7”,“layer7”仅能用于http代理场景;
  9. redir <prefix>:启用重定向功能,将发往此服务器的GET和HEAD请求均以302状态码响应;需要注意的是,在prefix后面不能使用/,且不能使用相对地址,以免造成循环重定向;
  10. weight <weight>:权重,默认为1,最大值为256,0表示不参与负载均衡(不被调度);

示例:

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 transp ipv4@
server backup ${SRV_BACKUP}:1080 backup
server www1_dc1 ${LAN_DC1}.101:80
server www1_dc2 ${LAN_DC2}.101:80

option httpchk

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

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

示例:

option httpchk GET /index.html

option forwardfor

option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
#允许在发往服务器的请求首部中插入“X-Forwarded-For”首部。

  • <network>:可选参数,当指定时,源地址为匹配至此网络中的请求都禁用此功能。
  • <name>:可选参数,可使用一个自定义的首部,如X-Client来替代X-Forwarded-For。有些独特的web服务器的确需要用于一个独特的首部。
  • if-none:仅在此首部不存在时才将其添加至请求报文问道中。
HAProxy工作于反向代理模式,其发往服务器的请求中的客户端IP均为HAProxy主机的地址而非真正客户端的地址,这会使得服务器端的日志信息记录不了真正的请求来源,X-Forwarded-For首部则可用于解决此问题。HAProxy可以向每个发往服务器的请求上添加此首部,并以客户端IP为其value。
需要注意的是,HAProxy工作于隧道模式,其仅检查每一个连接的第一个请求,因此,仅第一个请求报文被附加此首部。如果想为每一个请求都附加此首部,请确保同时使用了option httpclose、option forceclose和option http-server-close几个option。
示例:
frontend www
mode http
option forwardfor except 127.0.0.1

option httplog

option httplog [ clf ]
#启用记录HTTP请求、会话状态和计时器的功能,认情况下,日志输入格式非常简陋,因为其仅包括源地址、目标地址和实例名称
#而“option httplog”参数将会使得日志格式变得丰富许多,其通常包括但不限于HTTP请求、连接计时器、会话状态、连接数、捕获的首部及cookie、“frontend”、“backend”及服务器名称,当然也包括源地址和端口号等。
  • clf:使用CLF格式来代替HAProxy默认的HTTP格式,通常在使用仅支持CLF格式的特定日志分析器时才需要使用此格式

errorfile

errorfile <code> <file>
#错误页面配置,常用错误如404、403、400、500等

  • <code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有400、403、408、500、502、503和504;
  • <file>:指定用于响应的页面文件;

示例:

errorfile 400 /etc/haproxy/errorfiles/400badreq.http
errorfile 408 /dev/null  # workaround Chrome pre-connect bug
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
errorfile 503 /etc/haproxy/errorfiles/503sorry.http

errorloc&errorloc302

errorloc <code> <url>
errorloc302 <code> <url>
#请求错误时,返回一个HTTP重定向至某URL的信息;可用于所有配置段中。

  • <code>:指定对HTTP的哪些状态码返回指定的页面;这里可用的状态码有200、400、403、408、500、502、503和504;
  • <url>:Location首部中指定的页面位置的具体路径,可以是在当前服务器上的页面的相对路径,也可以使用绝对路径;需要注意的是,如果URI自身错误时产生某特定状态码信息的话,有可能会导致循环定向;
需要留意的是,这两个关键字都会返回302状态吗,这将使得客户端使用同样的HTTP方法获取指定的URL,对于非GET法的场景(如POST)来说会产生问题,因为返回客户的URL是不允许使用GET以外的其它方法的。如果的确有这种问题,可以使用errorloc303来返回303状态码给客户端。
 

修改头部信息相关

reqadd <string> [{if | unless} <cond>] #在HTTP请求的末尾添加标头 
rspadd <string> [{if | unless} <cond>] #在HTTP响应的末尾添加标头 
reqdel <search> [{if | unless} <cond>] #删除与HTTP请求中的正则表达式匹配的所有头信息 
rspdel <search> [{if | unless} <cond>] #删除与HTTP响应中的正则表达式匹配的所有头信息
reqidel <search> [{if | unless} <cond>] #忽略大小写删除同reqdel
rspidel <search> [{if | unless} <cond>] #忽略大小写删除同rspidel

示例:

#Add "X-Proto: SSL" to requests coming via port 81
acl is-ssl  dst_port       81
reqadd      X-Proto:\ SSL  if is-ssl
# remove X-Forwarded-For header and SERVER cookie
reqidel ^X-Forwarded-For:.*
reqidel ^Cookie:.*SERVER=

附上:官方1.5使用手册

四、 ACL

  ACL(Access Control List),即访问控制列表,HAProxy的ACL提供了一种灵活的解决方案来执行内容切换,并且通常基于从请求,响应或任何环境状态中提取的内容来做出决策。控制列表原则很简单:

  • 从数据流,表,环境中提取数据样本
  • 对提取的样本可选地应用格式转换
  • 对一个样本应用一个或多个模式匹配
  • 当模式匹配样本时才执行动作

需要提醒的是,获取的样本数据不光可以使用在acl中,也可以使用别处,例如记录log中。

定义ACL语法:

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

<aclname>: ACL名称,必须由大写和小写字母,数字,' - '(短划线),'_'(下划线),'.' 组成。ACL名称区分大小写
<criterion>:获取样本方法的名称,可以分为tcp和http类型,常用获取样本方法名称如下:
###基于tcp的criterion#####
dst : #目标ip
dst_port : #目标端口
src : #源ip
src_port : #源端口

###基于http的criterion#####
###url_path相关
#ps: path从第一个"/"开始,不包含host,不包含参数
path : #精确匹配
path_beg : #前缀匹配
path_dir : #子串匹配
path_dom : #子域名匹配
path_end : #路径后缀匹配
path_len : #路径长度匹配
path_reg : #路径的正则表达式模式匹配
path_sub : #路径的子字串匹配

###url相关
#ps:url包含了包含host和path以及参数
url : #精确匹配
url_beg : #前缀匹配
url_dir : #子串匹配
url_dom : #子域名匹配
url_end : #后缀匹配
url_len : #长度匹配
url_reg : #正则表达式匹配
url_sub : #子字串匹配

###http头信息相关
hdr([<name>[,<occ>]]) : #精确匹配
hdr_beg([<name>[,<occ>]]) : #前缀匹配
hdr_dir([<name>[,<occ>]]) : #子串匹配
hdr_dom([<name>[,<occ>]]) : #子域名匹配
hdr_end([<name>[,<occ>]]) : #后缀匹配
hdr_len([<name>[,<occ>]]) : #长度匹配
hdr_reg([<name>[,<occ>]]) : #正则表达式匹配
hdr_sub([<name>[,<occ>]]) : #子字串匹配

###http请求方法
method [string] :#匹配http请求方法,string为http方法

[flags]:标志,用于对<criterion>进行局部调整,一下为可使用的列表:

-i : #忽略大小写
-f filename : #从文件中载入模式
-m method : #指定模式匹配方法
-n : #禁止DNS解析
-M : #-f 载入的文件作为映射文件使用
-u : #强制ACL的名称唯一
-- : #强制结束flag结束,避免了字符串中含有的- 引起混淆
其中flag中的 -m 选项可使用的模式匹配方法如下,需要说明的是有些方法已被默认指定无需声明,例如int,ip:
 "found" : #只是用来探测数据流中是否存在指定数据,不进行任何比较
 "bool" : #检查结果返回布尔值。匹配没有模式,可以匹配布尔值或整数,不匹配0和false,其他值可以匹配
 "int" : #匹配整数类型数据;可以处理整数和布尔值类型样本,0代表false,1代表true
 "ip" : #匹配IPv4,IPv6地址类型数据。该模式仅被IP地址兼容,不需要特别指定
 "bin" : #匹配二进制数据
 "len" : #匹配样本的长度的整数值
 "str" : #精确匹配,根据字符串匹配文本
 "sub" : #子串匹配,匹配文本是否包含子串
 "reg" : #正则匹配,根据正则表达式列表匹配文本
 "beg" : #前缀匹配,检查文本是否以指定字符串开头
 "end" : #后缀匹配,检查文本是否以指定字符串结尾
 "dir" : #子目录匹配,检查部分文本中以" / "作为分隔符的内容是否含有指定字符串
 "dom" : #域匹配。检查部分文本中以" . "作为分隔符的内容是否含有指定字符串

[operator]:操作符,通常分字符串和整数,如下

###匹配整数值:
eq #等于
ge #大于等于
gt #大于
le #小于
lt #小于等于
###匹配字符串:
exact match #精确匹配
substring match #子串匹配
prefix match #前缀匹配
suffix match #后缀匹配
subdir match #子路径匹配
domain match #子域名匹配
[operator]

[<value>]:值,操作符右边的值,通常为以下几种类型:

boolean #布尔型 
integer or integer range #整数或整数范围
IP address / network #IP或网络地址 
string #字符串
hex block  #16进制的块匹配
value类型

在使用多个ACL作为条件可使用逻辑运算符:

  • and #默认操作符,可省略
  • ||  #或者使用
  •  !  #取反 

 

ACL之4层访问控制

  四层访问控制一般只能针对IP以及端口来进行,其指定是 tcp-request。

语法:

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

  • < condition >: 即为ACL定义的访问控制列表
  • < action > :常用值有 "accept", “reject”,代表着允许或者拒绝

示例:

#阻断来自非10.1.210.52访问80端口的请求
frontend  webserver
    acl myhost src 10.1.210.52
    acl myport dst_port 80
    tcp-request connection reject if !myhost  myport
    bind 0.0.0.0:80
    default_backend             app

ACL之七层访问控制

   七层上的访问控制方法有多种,列如可以利用http的报文、头信息、URL、PATH等相关信息进行访问控制,访问控制的指令也有多个,常用指令如下:

#阻断符合ACL的访问请求
block { if | unless } <condition> 
#允许或拒绝http请求的控制指令
http-request { allow | deny}  [ { if | unless } <condition> ]
#根据条件来调用指定后端
use_backend <backend> [{if | unless} <condition>]

在以上控制指令中,block语法可以使用http-request deny代替。
示例一:根据条件制定后端服务器
#请求资源为图片,则调用图片服务器后端
 acl picture path_end -i .jpg .png .gif
 use_backend server_img if picture

示例二:阻断请求

#根据http头信息中的User-Agent阻断火狐浏览器访问
frontend  webserver
    bind 0.0.0.0:80
    acl bad_curl hdr_sub(User-Agent) -i  .*firefox.* #hdr_sub根据头信息中的字符串匹配
    block if bad_curl
    default_backend             app

示例三:允许或拒绝http请求

#拒绝POST HEAD 方式之外的HTTP请求
acl valid_method method POST HEAD
http-request deny if ! valid_method

其他控制指令

除了以上控制指令还有比如内部状态控制指令,如会话速率:

# 与后端建立会话速率,每秒钟建立的新会话
be_sess_rate([<backend>]) : integer
#与前端代理会话建立速率,每秒钟建立的新会话
fe_sess_rate([frontend]) <integer>

示例一:

# 某后端被请求速率大于100,则重定向至错误页,可以用于阻止一些攻击行为
mode http
acl being_scanned be_sess_rate gt 100
redirect location /denied.html if being_scanned

示例二:

#限定入站邮件速率不能大于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

五、状态监控

  HAProxy优点之一就是自带状态监控页面,开启监控页面需要配置stats enable。

开启stats

listen admin
bind *:5656 # 定义监听端口
stats enable # 启用状态统计报告
stats auth admin:admin # 设置统计页面用户名和密码设置
stats uri /admin # 定义统计页面的URL,默认为/haproxy?stats
stats hide-version # 隐藏统计页面上HAProxy的版本信息
stats refresh 30s # 统计页面自动刷新时间
stats admin if TRUE #如果认证通过就做管理功能,可以管理后端的服务器
stats realm “LOGIN” #登陆页面提示信息

访问:http://ip:5656/admin登陆后即可看到管理页面。

六、常用配置示例

https配置

frontend web *:80
    bind *:443 ssl crt /etc/haproxy/haproxy.crt #haproxy.crt包含key和pem秘钥对
    reqadd X-Forwarded-Proto:\ https  #头信息中添加https协议
    redirect scheme https if !{ ssl_fc }  #将80端口跳转到443
    default_backend webserver
backend webserver
    balance roundrobin
    server app1 10.1.210.52:80 check
    server app2 10.1.210.53:80 check

mysql代理(双主)

listen mysql_36 0.0.0.0:3306                     
   mode tcp
   option tcplog
   balance leastconn
   option tcpka
   option mysql-check user haproxy
   server 10.1.210.52 10.1.210.53:3306 weight 1 check inter 1s rise 2 fall 2

动静分离

frontend webservs
    bind *:80
    acl url_static path_beg -i /static /images /javascript /stylesheets
    acl url_static path_end -i .jpg .gif .png .css .js .html
    acl url_php path_end -i .php
    acl host_static hdr_beg(host) -i img. imgs. video. videos. ftp.   image. download.
    use_backend static if url_static or host_static
    use_backend dynamic if url_php
    default_backend dynamic
backend static
    balance roundrobin
    server node1 10.1.210.52:80 check maxconn 1000
backend dynamic
    balance roundrobin
    server node2 10.1.210.53:80 check maxconn 1000

 

posted @ 2019-01-22 16:45  W-D  阅读(3349)  评论(0编辑  收藏  举报