HAProxy02-HAProxy配置手册
- HAProxy配置手册(configuration.txt):version 2.5 2022/05/13
- https://www.haproxy.org/download/2.5/doc/configuration.txt
1、HTTP介绍
- 当HAProxy在HTTP模式下运行时,请求和响应都被完全分析和索引,因此可以对所有的hearder头构建响应的匹配规则。
- 如果了解HTTP请求和响应是如何形成的,以及HAProxy是如何分解它们的,就可以更容易地编写正确的规则和调试现有的配置。
1.1、HTTP事务模型
- HTTP协议是事务驱动的。这意味着每个请求将会有且仅有一个响c'l应。
- "HTTP close"模式:
- 从客户机到服务器建立TCP连接,客户机通过连接发送请求,服务器响应,然后关闭连接。一个新的请求将使用一个新的连接:
- [CON1] [REQ1] ... [RESP1] [CLO1] [CON2] [REQ2] ... [RESP2] [CLO2] ...
- 在"HTTP close"模式中,有多少HTTP事务(请求或响应),就有多少连接建立。由于服务器在响应后关闭了连接,因此客户机不需要知道内容长度。
- 从客户机到服务器建立TCP连接,客户机通过连接发送请求,服务器响应,然后关闭连接。一个新的请求将使用一个新的连接:
- "keep-alive"模式:
- 由于HTTP协议具有事务性,因此对"HTTP close"模式进行改进,以避免关闭两个后续事务之间的连接。服务器为每个响应添加一个特殊的头"Content-length",告诉客户端响应的长度,,这样客户机就不会无限期地等待。
- [CON] [REQ1] ... [RESP1] [REQ2] ... [RESP2] [CLO] ...
- 它的优点是减少了事务之间的延迟,减轻了服务器端的压力。它通常比"HTTP close"模式要好,但并不总是如此,因为客户端经常将并发连接限制在一个较小的值。
- 由于HTTP协议具有事务性,因此对"HTTP close"模式进行改进,以避免关闭两个后续事务之间的连接。服务器为每个响应添加一个特殊的头"Content-length",告诉客户端响应的长度,,这样客户机就不会无限期地等待。
- 流水线(pipelining)模式:
- 它使用keep-alive,但是客户机可以不用不等待第一个响应就发送第二个请求。如果页面中有很多图片,使用该模式的效果会非常好。
- [CON] [REQ1] [REQ2] ... [RESP1] [RESP2] [CLO] ...
- 这显然可以极大地提高性能,因为可以消除后续请求之间的网络延迟。由于许多HTTP代理不能正确地支持管道,因此没有办法将响应与相应的请求关联起来。由于这个原因,服务器必须按照接收到的请求的完全相同的顺序进行响应。
- 它使用keep-alive,但是客户机可以不用不等待第一个响应就发送第二个请求。如果页面中有很多图片,使用该模式的效果会非常好。
- 多路复用(multiplexed)模式:
- 多路复用模式在HTTP/2中实现的。为每个事务分配一个唯一的标识符,所有的事务复用一个现有的连接。客户端可以并行发送多个请求,响应可以以任意顺序到达,因为它们会携带标识符。
- HAProxy支持4种连接方式:
- keep alive:所有请求和响应都被处理(默认)
- tunnel:只处理第一个请求和响应,其他所有内容不进行分析就转发(弃用)。
- server close:响应后关闭面向服务器的连接。
- close:响应结束后主动关闭连接。
1.2、HTTP请求(request)
- HTTP请求示例:
Line number Contents 1 GET /serv/login.php?lang=en&profile=2 HTTP/1.1 #它们都由空格分隔。方法本身不能包含冒号':'。 2 Host: www.mydomain.com 3 User-agent: my small browser 4 Accept: image/jpeg, image/gif 5 Accept: image/png
1.2.1、Request line
- 第1行就是request line(请求行)。它总是由3个字段组成:
METHOD : GET URI : /serv/login.php?lang=en&profile=2 version tag : HTTP/1.1
- URI的几种形式:
- 相对URI:没有主机部分的URL。这通常是服务器、反向代理和透明代理接收的部分。
- 例如,/serv/login.php?lang=en&profile=2
- 绝对URI,也称为URL:由一个方案(scheme,协议名后跟'://')、一个主机名或地址、一个冒号(':')后跟一个端口号和相对URI组成(从端口后面第一个斜杠('/')开始到结尾的部分)。这通常是代理接收的,但支持HTTP/1.1的服务器也要接收这种形式。
- 例如,http://192.168.0.12:8080/serv/login.php?lang=en&profile=2
- 相对URI:没有主机部分的URL。这通常是服务器、反向代理和透明代理接收的部分。
- 相对URI由两部分组成:
- 问号之前的部分称为“路径”。它通常是服务器上静态对象的相对路径。
- 问号后面的部分称为“查询字符串”。它主要用于发送到动态脚本的GET请求,并且特定于所使用的语言、框架或应用程序。
1.2.2、请求头
- 从第二行开始就是请求头(header)了,它们由key:value组成(在冒号后可以添加一个空格)。value可以由多个值组成,不同的值之间使用逗号","分隔。例如,第4行和第5行为“Accept:”头定义了总共3个值。
- 请求头名称不区分大小写,如果它们引用其他请求头名称(例如“Connection:”报头),它们的值也不区分大小写。
- 在内部,所有的请求头名称都被规范为小写,以便HTTP/1.x和HTTP/2相互兼容。
- 注意,根据RFC7231的建议,HAProxy会使用LWS(一般是空格)替换header中的换行符来规范header。这可以帮助性能较差的HTTP解析器正确工作,而不会被这种复杂的构造所欺骗。
1.3、HTTP响应(response)
- HTTP响应示例:
- HTTP响应看起来很像HTTP请求。两者都称为HTTP消息。
Line number Contents 1 HTTP/1.1 200 OK 2 Content-length: 350 3 Content-Type: text/html
- 在特殊情况下,HTTP响应状态码可以是1xx。响应状态码1xx的特殊之处在于它们不传输响应的任何部分,它们只是作为一种信号消息,以请求客户端继续发布其请求。
- 响应状态码是100的情况下,所请求的信息将下一个非100响应携带。这意味着可以向单个请求发送多个响应,并且这仅在启用keep-alive时有效(1xx消息仅为HTTP/1.1)。HAProxy可以正确地转发或跳过它们,并且只处理下一个非100响应。因此,这些消息既不会被记录日志,也不会被转换,除非显式地另有说明。
- 响应状态码是100表明协议正在改变相同的连接,HAProxy必须切换到隧道模式,就像发生了CONNECT一样。然后,Upgrade头将包含关于连接正在切换到的协议类型的额外信息。
1.3.1. Response line
- 第1行就是response line(响应行)。它总是由3个字段组成:
version tag : HTTP/1.1 status code : 200 reason : OK
- 状态码总是3位数字。第一个数字表示大致状态:
- 1xx = 要跳过的信息(e.g. 100, 101)
- 2xx = OK, 内容如下(e.g. 200, 206)
- 3xx = OK, 后面没有内容(e.g. 302, 304)
- 4xx = 由客户端引起的错误(e.g. 401, 403, 404)
- 5xx = 由服务器引起的错误(e.g. 500, 502, 503)
- reason字段只是一个提示信息,不会被客户端解析。可以任何内容,一个或多个单词,如“OK”、“Found”或“Authentication Required”。
- HAProxy的响应状态码:
- 200 访问统计页面,响应监视请求
- 301 重定向,这取决于所配置的代码
- 302 重定向,这取决于所配置的代码
- 303 重定向,这取决于所配置的代码
- 307 重定向,这取决于所配置的代码
- 308 重定向,这取决于所配置的代码
- 400 无效或太大的请求
- 401 执行操作需要身份验证(访问stats页面时)
- 403 请求被“http-request deny”规则禁止
- 404 请求的资源不存在
- 408 请求完成之前发生请求超时
- 410 请求的资源不再可用且即将不再可用
- 500 HAProxy遇到不可恢复的内部错误,例如内存分配失败
- 501 HAProxy由于不支持的特性而无法满足客户端请求
- 502 后端服务器返回一个空的、无效的或不完整的响应,或者“http-response deny”规则阻塞响应
- 503 没有后端服务器可用来处理请求,或响应与“监视失败”条件匹配的监视请求
- 504 后端服务器响应之前发生响应超
1.3.2、响应头
- 响应头的原理与请求头的完全相同,因为HAProxy对两者使用相同的解析函数。
2、HAProxy配置
2.1、配置文件格式
- 配置HAProxy的方式用两种:
- (1)在启动HAProxy的时候,使用命令行参数。
- (2)通过配置文件配置HAProxy。
- HAProxy的配置文件由两部分组成:全局段和代理段。共分为五段:global、defaults、frontend、backend、listen。
- 全局段有:global
- global:全局配置参数段,主要是对Haproxy进程的控制和系统相关配置。
- 代理段有:defaults、frontend、backend、listen
- defaults:配置默认参数。如果frontend、backend、listen段未配置则使用defaults段的配置。(可由下一个“defaults”所重新设定)
- frontend:定义一系列监听的套接字,这些套接字可接受客户端的请求并与之建立连接。然后根据规则对请求中的域名、uri等进行匹配,可以对不同的请求进行不同的处理,最后转发给后端服务器。
- backend:定义一组后端服务器,可以对后端服务器设置不同的权重、队列长度、连接数的。一个Backend对应一个或者多个实体服务器
- listen:可以独立完整的定义一个代理,包含前端和后端,即将“frontend”和“backend”段中的内容全部整合到listen段中。通常只用于四层代理(TCP)。
- 配置文件中可以使用的配置段组合:
- global、defaults、frontend、backend
- global、defaults、listen、frontend、backend
- global、defaults、listen
2.2、转义和引用
- HAProxy支持字符转义,在要转义的字符前加上反斜杠('\')、双引号(弱引用)或单引号(强引用)。
- HAProxy中可用的转义:
- \ :转义空格,原作用是分隔符
- \#:转义#号,原作用是注释符
- \\:转义斜杠,原作用是转义符
- \':转义单引号,原作用是强引用
- \":转义双引号,原作用是弱引用
- \n:换行符
- \r:回车符
- \t:TAB键
- \xNN:插入具有ASCII码十六进制NN的字符(e.g \x0a for LF).
- 弱引用是对字符或字符序列加上双引号(")实现的。引用环境变量"$PATH"
- 强引用是对字符或字符序列上单引号(')实现的。
- 在不同的上下文对特殊字符(不可打印的字符将用尖括号内的名称替换)的使用。
Character | Unquoted | Weakly quoted | Strongly quoted -----------+---------------+-----------------------------+----------------- <TAB> | \<TAB>, \x09 | "<TAB>", "\<TAB>", "\x09" | '<TAB>' <LF> | \n, \x0a | "\n", "\x0a" | - <CR> | \r, \x0d | "\r", "\x0d" | - <SPC> | \<SPC>, \x20 | "<SPC>", "\<SPC>", "\x20" | '<SPC>' " | \", \x22 | "\"", "\x22" | '"' # | \#, \x23 | "#", "\#", "\x23" | '#' $ | $, \$, \x24 | "\$", "\x24" | '$' ' | \', \x27 | "'", "\'", "\x27" | - \ | \\, \x5c | "\\", "\x5c" | '\'
- 关键字参数解析器与关于引号的顶级解析器完全相同,只是不处理\#、\\$和\xNN转义。
- 配置文件中的每行配置都可能进行两次解析:
- 第一次,顶级解析器处理一层引号的转义。
- 第二次,haproxy关键字参数解析器对所有的转义再进行处理。
- 在需要逗号或右括号的参数周围放置单引号或双引号,如果字符串包含美元或反斜杠,请考虑使用反斜杠转义这些引号。
- 建议对整个表达式使用单引号,在表达式内部的每个参数使用双引号。
示例1:
- 一个非常常见的情况是“regsub”转换器。它的参数是一个正则表达式,如果里面需要一个右括号,这个括号将需要有自己的引号。
//将路径中的“foo”替换为“blah” http-request set-path %[path,regsub(foo,blah,g)] //错误用法,关键字参数解析器时会出错 http-request set-path %[path,regsub((foo|bar),blah,g)] |--------|--------| arg1=(foo|bar _/ / trailing garbage _________/ //错误用法,引号被顶级解析器处理,关键字参数解析器时会出错 http-request set-path %[path,regsub("(foo|bar)",blah,g)] ------------ -------- ---------------------------------- word1 word2 word3=%[path,regsub((foo|bar),blah,g)] //正确用法 http-request set-path %[path,regsub(\"(foo|bar)\",blah,g)] //正确用法 http-request set-path '%[path,regsub("(foo|bar)",blah,g)]'
示例2:
- 当使用正则表达式时,可能会出现'$'字符或者在替换字符串中使用反斜杠'\'。因此建议在最外层使用单引号。
//正确用法 http-request set-path '%[path,regsub("^/(here)(/|$)","my/\1",g)]'
2.3、环境变量
- 可以在HAProxy的配置文件中使用环境变量。
- 变量名可以包含字母数字或下划线(“_”),但不应以数字开头。
- 使用环境变量的方法,在双引号中使用"$"符引用环境变量名,且可以选择用大括号"{}"将环境变量名括起来。
- 为环境变量指定一个默认值,例如"${LOCAL_SYSLOG-127.0.0.1}:514"。注意,默认值只替换不存在的变量,而不是空的变量。
- HAProxy内置的环境变量,它们可以在配置文件中使用,也可以被程序继承:
- HAPROXY_LOCALPEER:在进程启动时定义,包含本地对等体的名称。(详见管理指南中的“-L”)
- HAPROXY_CFGFILES:HAProxy加载的配置文件列表,以分号分隔。在您指定目录的情况下可能会很有用。
- HAPROXY_MWORKER:在master-worker模式下,该变量设置为1。
- HAPROXY_CLI:为每个进程配置的stats套接字侦听器地址,用分号分隔。
- HAPROXY_MASTER_CLI:master-worker模式下,master CLI的监听器地址,用分号分隔。
- 伪变量是内部解析的,可以作为常规变量使用。伪变量总是以点('.')开头,并且是唯一允许使用点的变量。
- .FILE:当前正在解析的配置文件的名称。
- .LINE:当前正在解析的配置文件的行号,从1开始。
- .SECTION:当前正在解析的段(section)的名称或类型(如果section没有名称就是类型)。
- 例如,如果"LINE"变量在"log-format"中使用,它的行号将在解析和编译"log-format"之前被解析。通过这种方式,可以输出信息来帮助在变量、日志、错误状态、健康检查、header值中定位规则,甚至可以使用行号来命名一些配置对象,比如服务器。
示例:
bind "fd@${FD_APP1}" log "${LOCAL_SYSLOG-127.0.0.1}:514" local0 notice # send to local server user "$HAPROXY_USER"
2.4、条件语句
- 有条件地启用或禁用配置的某些任意部分,例如启用/禁用SSL或加密,启用或禁用一些生产前的侦听器而不修改配置,或调整配置的语法以在迁移期间支持两个不同版本的HAProxy。
- 条件语句有四种指令:
.if <condition> .elif <condition> .else .endif
- 条件(condition)可以是一个空字符串(表示false),也可以是由以下任意组合组成的表达式:
- 整数0,表示false
- 一个非零整数(例如:'1'),表示"true"。
- 使用断言
- 使用小括号
- 将感叹号'!'放在任意非空元素的前,表示取反。
- 逻辑与AND('&&'),它将从左到右计算,直到有一个返回false。(AND操作符优先于OR操作符)
- 与逻辑OR('||'),它将从右到左计算,直到其中一个返回true。
- 当前支持的断言列表如下:
- defined(<name>) :如果存在环境变量名,无论其内容如何,返回true
- feature(<name>) :如果特性名称在“haproxy -vv”报告的特性列表中,则返回true(这意味着名称出现在“+”之后)
- streq(<str1>,<str2>) :仅当两个字符串相同时返回true
- strneq(<str1>,<str2>) :两个字符串不同时返回true
- version_atleast(<ver>) :如果当前的haproxy版本至少是ver版本,则返回true,否则返回false。版本语法与“haproxy -v”所示相同,并且假定缺少的组件为零。
- version_before(<ver>) :如果当前的haproxy版本严格比ver早,则返回true,否则返回false。版本语法与“haproxy -v”所示相同,并且假定缺少的组件为零。
示例:
.if defined(HAPROXY_MWORKER) listen mwcli_px bind :1111 ... .endif .if strneq("$SSL_ONLY",yes) bind :80 .endif .if streq("$WITH_SSL",yes) .if feature(OPENSSL) bind :443 ssl crt ... .endif .endif .if feature(OPENSSL) && (streq("$WITH_SSL",yes) || streq("$SSL_ONLY",yes)) bind :443 ssl crt ... .endif .if version_atleast(2.4-dev19) profiling.memory on .endif .if !feature(OPENSSL) .alert "SSL support is mandatory" .endif
- 提供了四个指令来报告某些状态:
- .diag "message" :只有在诊断模式下才会发出此消息(- dd)
- .notice "message" :以NOTICE级别发出此消息
- .warning "message" :以WARNING级别发出此消息
- .alert "message" :在ALERT级别发出此消息
示例:
.if "${A}" .if "${B}" .notice "A=1, B=1" .elif "${C}" .notice "A=1, B=0, C=1" .elif "${D}" .warning "A=1, B=0, C=0, D=1" .else .alert "A=1, B=0, C=0, D=0" .endif .else .notice "A=0" .endif .diag "WTA/2021-05-07: replace 'redirect' with 'return' after switch to 2.4" http-request redirect location /goaway if ABUSE
2.5、时间格式
- 有些参数涉及时间,例如超时类的。默认以毫秒为单位(除非另有明确说明)。也可以通过在数值后面加上单位来表示。
- us :微秒,1s = 1000000us
- ms :毫秒,1s = 1000ms(默认单位)
- s :秒
- m :分钟,1m = 60s
- h : 小时,1h = 60m = 3600s
- d :天,1d = 24h = 1440m = 86400s
2.6、配置文件示例
示例1:
- 在所有接口上侦听端口80,并将请求转发到单个后端“servers”,单个服务器“server1”侦听127.0.0.1:8000
global daemon maxconn 256 defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms frontend http-in bind *:80 default_backend servers backend servers server server1 127.0.0.1:8000 maxconn 32
示例2:
- 和上面的示例相同。配置较短但表现力较差,尤其是在HTTP模式下。
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
3、全局参数
- global:全局配置参数段,主要是对Haproxy进程的控制和系统相关配置。
- global段支持以下参数:
* Process management and security - ca-base - chroot - crt-base - cpu-map - daemon - default-path - description - deviceatlas-json-file - deviceatlas-log-level - deviceatlas-separator - deviceatlas-properties-cookie - expose-experimental-directives - external-check - gid - grace - group - hard-stop-after - h1-accept-payload-with-any-method - h1-case-adjust - h1-case-adjust-file - insecure-fork-wanted - insecure-setuid-wanted - issuers-chain-path - h2-workaround-bogus-websocket-clients - localpeer - log - log-tag - log-send-hostname - lua-load - lua-load-per-thread - lua-prepend-path - mworker-max-reloads - nbthread - node - numa-cpu-mapping - pidfile - pp2-never-send-local - presetenv - resetenv - uid - ulimit-n - user - set-dumpable - set-var - setenv - stats - ssl-default-bind-ciphers - ssl-default-bind-ciphersuites - ssl-default-bind-curves - ssl-default-bind-options - ssl-default-server-ciphers - ssl-default-server-ciphersuites - ssl-default-server-options - ssl-dh-param-file - ssl-server-verify - ssl-skip-self-issued-ca - unix-bind - unsetenv - 51degrees-data-file - 51degrees-property-name-list - 51degrees-property-separator - 51degrees-cache-size - wurfl-data-file - wurfl-information-list - wurfl-information-list-separator - wurfl-cache-size - strict-limits * Performance tuning - busy-polling - max-spread-checks - maxconn - maxconnrate - maxcomprate - maxcompcpuusage - maxpipes - maxsessrate - maxsslconn - maxsslrate - maxzlibmem - no-memory-trimming - noepoll - nokqueue - noevports - nopoll - nosplice - nogetaddrinfo - noreuseport - profiling.tasks - spread-checks - server-state-base - server-state-file - ssl-engine - ssl-mode-async - tune.buffers.limit - tune.buffers.reserve - tune.bufsize - tune.comp.maxlevel - tune.fd.edge-triggered - tune.h2.header-table-size - tune.h2.initial-window-size - tune.h2.max-concurrent-streams - tune.http.cookielen - tune.http.logurilen - tune.http.maxhdr - tune.idle-pool.shared - tune.idletimer - tune.lua.forced-yield - tune.lua.maxmem - tune.lua.session-timeout - tune.lua.task-timeout - tune.lua.service-timeout - tune.maxaccept - tune.maxpollevents - tune.maxrewrite - tune.pattern.cache-size - tune.pipesize - tune.pool-high-fd-ratio - tune.pool-low-fd-ratio - tune.rcvbuf.client - tune.rcvbuf.server - tune.recv_enough - tune.runqueue-depth - tune.sched.low-latency - tune.sndbuf.client - tune.sndbuf.server - tune.ssl.cachesize - tune.ssl.force-private-cache - tune.ssl.hard-maxrecord - tune.ssl.keylog - tune.ssl.lifetime - tune.ssl.maxrecord - tune.ssl.default-dh-param - tune.ssl.ssl-ctx-cache-size - tune.ssl.capture-buffer-size - tune.ssl.capture-cipherlist-size (deprecated) - tune.vars.global-max-size - tune.vars.proc-max-size - tune.vars.reqres-max-size - tune.vars.sess-max-size - tune.vars.txn-max-size - tune.zlib.memlevel - tune.zlib.windowsize * Debugging - quiet - zero-warning
3.1、进程管理和安全相关的参数
1、chroot <jail dir>
- 修改haproxy的工作目录至指定的目录,并在放弃特权之前执行chroot()操作。这增加了安全级别,以防未知的漏洞被利用,因为这将使攻击者很难利用系统。只在进程以超级用户权限启动时才有效。
- 注意,要确保指定的目录为 空目录 且任何用户都不能有 写权限。
2、daemon
- 以守护进程的方式运行。等价于命令行“-D”参数。
3、user <user name>
- 运行haproxy进程的用户
4、group <group name>
- 运行haproxy进程的用户组
5、log <address> [len <length>] [format <format>] <facility> [max level [min level]]
- 添加全局syslog服务器。可以定义多个全局服务器。它们将接收启动和退出的日志,以及来自配置了“log global”的代理的所有日志。
- <address>:syslog服务器的地址,可以是IPv4或IPv6等。可以指定一个UDP端口,如果没有指定端口,默认使用514(标准syslog端口)
- <length>:如果一条日志长度大于此值,在发送给syslog服务器之前将被截断。取值范围为80-65535。默认值1024。如果请求uri被截断了,可能需要增加“tune.http. logurilen”。
- <format>日志格式。它可能是local、rfc3164、rfc5424、priority、short、timed、iso或raw之一。
- <facility>必须是下面标准syslog的24个设施之一:
- kern、user、mail、daemon、auth、syslog、lpr、news、uucp、cron、auth2、ftp、ntp、audit、alert、cron2、local0、local1、local2、local3、local4、local5、local6、local7
- [max level [min level]]:缺省情况下,发送所有消息。如果指定了最大级别,则只发送严重性至少与此级别同等重要的消息。可以指定一个可选的最低级别,则比此级别更严重的日志不被发送。
- 日志有8个级别(从低到高):emerg、alert、crit、err、warning、notice、info、debug
6、log-send-hostname [<string>]
- 在syslog信息的最前方添加当前主机名,可以是"string"指定的名称,也可以缺省使用当前主机名。
7、pidfile <pidfile>
- 将所有守护进程的pid写入文件(daemon模式或master模式)。
8、ulimit-n <number>
- 设置每个进程最多可以打开number个文件描述符。默认情况下,它是自动计算的,所以建议不要使用此选项。
9、node <name>
- 在HA配置中,两个或多个服务器使用同一个VIP地址时,通过不同的节点名,可以很容易地立即发现处理请求的服务器。
- 只允许字母、数字、连字符和下划线,就像DNS名称一样。
10、description <text>
- 添加描述当前实例的信息。
- 注意,它需要转义某些字符(例如#),并且此文本被插入到html页面中,因此您应该避免使用"<"和">"字符。
3.2、性能调整相关的参数
1、maxconn <number>
- 将每个进程的最大并发连接数设置为number。它等价于命令行参数“-n”。当达到此限制时,代理将停止接受连接。“ulimit-n”参数会根据这个值自动调整。
- 如果没有设置此值,它将根据“ulimit -n”命令报告的当前文件描述符限制自动计算,如果强制执行内存限制,则可能会根据缓冲区大小、分配给压缩的内存、SSL缓存大小、是否使用SSL和相关的maxsslconn(也可以是自动的)将其减少到更低的值。
- 注意:“select”轮询器在某些平台上不能使用超过1024个文件描述符。如果您的平台只支持select,并且在启动时报告“select FAILED”,则需要减少maxconn,直到它工作(一般略低于500)。
2、maxpipes <number>
- 将每个进程的最大管道(pipe)数设置为number。haproxy使用pipe完成基于内核的tcp报文重组。
- 每个pipe会打开两个文件描述符,因此"ulimit-n"值将相应地增加。默认值是maxconn/4。
- splice代码会动态地分配和释放管道,并会退回到标准复制,因此将这个值设置得太低只会影响性能。
3、noepoll
- 在Linux上禁用“epoll”轮询器。它等价于命令行参数“-de”。在支持epoll的系统上,接下来通常会使用“poll”轮询器。
4、nokqueue
- 在BSD上禁用“kqueue”轮询器。它等价于命令行参数“-dk”。在支持kqueue的系统上,接下来通常会使用“poll”轮询器。
5、nopoll
- 禁用“poll”轮询器。它等价于命令行参数“-dp”。在支持“poll”的系统上,接下来通常会使用“select”轮询器。永远不需要禁用“poll”,因为它在支持HAProxy的所有平台上都可用。
6、nosplice
- 在Linux上,禁止在套接字之间使用内核tcp拼接,然后,数据将使用recv/send调用进行复制。它等价于命令行参数“-dS”。在Linux内核2.6.25到2.6.28之间的大多数版本都有tcp重组功能的bug,并且会转发损坏的数据,所以不能使用它们。这个选项使得在有疑问的情况下全局禁用内核拼接变得更容易。参见“option splice-auto”、“option splice-request”和“option splice-response”。
7、spread-checks <0..50, in percent>
- 可以避免以精确的间隔向服务器发送健康检查,例如,当许多逻辑服务器位于同一物理服务器上时。有了这个参数的帮助,就有可能在0到+/- 50%之间的检查间隔中添加一些随机性。2到5之间的值似乎显示良好的结果。默认值保持为0。
8、tune.bufsize <number>
- 将缓冲区(buffer)大小设置为number(以字节为单位)。
- 较小的值允许在相同的RAM中共存更多的会话(并发连接),而较大的值允许应用携带较大的cookie。
- 默认值是16384,可以在编译时更改。不过强烈建议使用默认值,因为非常低的值将破坏一些服务,例如统计数据,而大于默认值的值将增加内存使用,可能导致系统耗尽内存。至少全局maxconn参数的减小倍数应该与这个参数的增加倍数相同。
- 此外,使用HTTP/2要求该值必须为16384或更多。如果HTTP请求大于(tune.bufsize - tune.maxrewrite),HAProxy将返回HTTP 400(错误请求)错误。类似地,如果HTTP响应大于此大小,HAProxy将返回HTTP 502(坏网关)。
- 注意,使用该参数设置的值在32位机器上将自动四舍五入到8的下一个倍数,在64位机器上为16。
9、tune.maxaccept <number>
- 设置进程在切换到其他工作之前可以一次性接受的最大连续连接数。
- 在单进程模式中,较高的数字通常在高连接速率下提供更好的性能。该值单独应用于每个侦听器,以便考虑侦听器绑定的进程数量。该值默认为4,表示最佳效果。
- 在多进程模式下,它除以侦听器绑定的进程数的两倍。
- 将该值设置为-1将完全禁用该限制。一般不建议修改。
- 如果从一个古老的配置继承了一个明显更高的值,那么删除它可能是值得的,因为它既可以提高性能,又可以降低响应时间。
10、tune.maxpollevents <number>
- 设定一次系统调用(polling调用)可以处理的事件的最大数量。默认值取决于操作系统。其值小于200会以网络带宽为代价略微降低延迟,其值大于200则会以延迟换取略微增加的带宽。
11、tune.maxrewrite <number>
- 将保留的缓冲区空间大小设置为number(以字节为单位)。保留的空间用于头重写或追加。
- 套接字上的第一次读取永远不会超过bufsize-maxrewrite。
- 设置过高会阻止处理大型请求或响应。设置过低会阻止向已经很大的请求或POST请求添加新的头信息。
- 通常明智的做法是将其设置为1024左右。如果它比bufsize大,它会自动调整到bufsize的一半。这意味着您在更改bufsize时不必担心它。
12、tune.rcvbuf.client <number>和tune.rcvbuf.server <number>
- 强制客户端或服务器端的内核套接字接收缓冲区大小为指定的字节值。此值适用于所有TCP/HTTP前端和后端。
- 通常不应该设置这个值,默认大小(0)允许内核根据可用内存的数量自动调优这个值。
- 有时将它设置为非常低的值(例如4096)有助于通过防止它缓冲接收到的大量数据来节省内核内存。但是,较低的值将显著增加CPU使用率。
13、tune.sndbuf.client <number>和tune.sndbuf.server <number>
- 强制内核套接字在客户端或服务器端发送缓冲区大小为指定的字节值。此值适用于所有TCP/HTTP前端和后端。
- 通常不应该设置这个值,默认大小(0)允许内核根据可用内存的数量自动调优这个值。
- 有时将它设置为非常低的值(例如4096)有助于通过防止它缓冲接收到的大量数据来节省内核内存。但是,较低的值将显著增加CPU使用率。
- 另一个用例是防止由于内核在再次通知HAProxy之前等待读取大部分缓冲区而导致的客户端极慢的写超时。
4、代理参数
- 代理参数可以用在下面代理段中:
defaults [<name>] [ from <defaults_name> ] frontend <name> [ from <defaults_name> ] backend <name> [ from <defaults_name> ] listen <name> [ from <defaults_name> ]
- 代理名称由大写字母、数字、'-'(破折号)、'_'(下划线)、'.'(点)和':'(冒号)组成。
- ACL名称区分大小写,这意味着“www”和“WWW”是两个不同的ACL。
- HAProxy支持三种连接模式:
- KAL:keep alive(“option http-keep-alive”),这是默认模式,所有请求和响应都被处理,连接保持打开,但在响应和新请求之间空闲。
- SCL:server close("option http-server-close"),响应结束后,面向后端服务器的连接被关闭,但面向客户端的连接仍然打开。
- CLO: close("option httpclose"),连接在响应结束后关闭,并在两个方向附加"connection: close"。
- 前端和后端都可以使用不同连接模式,最终HAProxy使用的连接模式如矩阵所示:
- KAL最弱,CLO最强
Backend mode | KAL | SCL | CLO ----+-----+-----+---- KAL | KAL | SCL | CLO ----+-----+-----+---- Frontend mode SCL | SCL | SCL | CLO ----+-----+-----+---- CLO | CLO | CLO | CLO
4.1、代理参数矩阵
- 大多数关键词只能用在部分section中。
- 被"deprecated"标记的关键词,这些关键词继承自旧语法,可能会造成混淆或功能上的限制,并且有新的推荐关键词来替换它们。
- 被"(*)"标记的关键词,可以在这些关键词前面使用"no"反转其含义,例如"no option contstats"
- 被"(!)"标记的关键词,只可以在defaults使用,不能再anonymous(匿名)中使用。
-- keyword -------------------------- defaults - frontend - listen -- backend - acl X (!) X X X backlog X X X - balance X - X X bind - X X - bind-process X X X X capture cookie - X X - capture request header - X X - capture response header - X X - clitcpka-cnt X X X - clitcpka-idle X X X - clitcpka-intvl X X X - compression X X X X cookie X - X X declare capture - X X - default-server X - X X default_backend X X X - description - X X X disabled X X X X dispatch - - X X email-alert from X X X X email-alert level X X X X email-alert mailers X X X X email-alert myhostname X X X X email-alert to X X X X enabled X X X X errorfile X X X X errorfiles X X X X errorloc X X X X errorloc302 X X X X errorloc303 X X X X -- keyword -------------------------- defaults - frontend - listen -- backend - error-log-format X X X - force-persist - - X X filter - X X X fullconn X - X X hash-type X - X X http-after-response X (!) X X X http-check comment X - X X http-check connect X - X X http-check disable-on-404 X - X X http-check expect X - X X http-check send X - X X http-check send-state X - X X http-check set-var X - X X http-check unset-var X - X X http-error X X X X http-request X (!) X X X http-response X (!) X X X http-reuse X - X X http-send-name-header - - X X id - X X X ignore-persist - - X X load-server-state-from-file X - X X log (*) X X X X log-format X X X - log-format-sd X X X - log-tag X X X X max-keep-alive-queue X - X X maxconn X X X - mode X X X X monitor fail - X X - -- keyword -------------------------- defaults - frontend - listen -- backend - monitor-uri X X X - option abortonclose (*) X - X X option accept-invalid-http-request (*) X X X - option accept-invalid-http-response (*) X - X X option allbackups (*) X - X X option checkcache (*) X - X X option clitcpka (*) X X X - option contstats (*) X X X - option disable-h2-upgrade (*) X X X - option dontlog-normal (*) X X X - option dontlognull (*) X X X - option forwardfor X X X X option h1-case-adjust-bogus-client (*) X X X - option h1-case-adjust-bogus-server (*) X - X X option http-buffer-request (*) X X X X option http-ignore-probes (*) X X X - option http-keep-alive (*) X X X X option http-no-delay (*) X X X X option http-pretend-keepalive (*) X - X X option http-server-close (*) X X X X option http-use-proxy-header (*) X X X - option httpchk X - X X option httpclose (*) X X X X option httplog X X X - option httpslog X X X - option independent-streams (*) X X X X option ldap-check X - X X option external-check X - X X option log-health-checks (*) X - X X option log-separate-errors (*) X X X - -- keyword -------------------------- defaults - frontend - listen -- backend - option logasap (*) X X X - option mysql-check X - X X option nolinger (*) X X X X option originalto X X X X option persist (*) X - X X option pgsql-check X - X X option prefer-last-server (*) X - X X option redispatch (*) X - X X option redis-check X - X X option smtpchk X - X X option socket-stats (*) X X X - option splice-auto (*) X X X X option splice-request (*) X X X X option splice-response (*) X X X X option spop-check - - - X option srvtcpka (*) X - X X option ssl-hello-chk X - X X option tcp-check X - X X option tcp-smart-accept (*) X X X - option tcp-smart-connect (*) X - X X option tcpka X X X X option tcplog X X X X option transparent (*) X - X X option idle-close-on-response (*) X X X - external-check command X - X X external-check path X - X X persist rdp-cookie X - X X rate-limit sessions X X X - redirect - X X X retries X - X X -- keyword -------------------------- defaults - frontend - listen -- backend - retry-on X - X X server - - X X server-state-file-name X - X X server-template - - X X source X - X X srvtcpka-cnt X - X X srvtcpka-idle X - X X srvtcpka-intvl X - X X stats admin - X X X stats auth X X X X stats enable X X X X stats hide-version X X X X stats http-request - X X X stats realm X X X X stats refresh X X X X stats scope X X X X stats show-desc X X X X stats show-legends X X X X stats show-node X X X X stats uri X X X X stick match - - X X stick on - - X X stick store-request - - X X stick store-response - - X X stick-table - X X X tcp-check comment X - X X tcp-check connect X - X X tcp-check expect X - X X tcp-check send X - X X tcp-check send-lf X - X X -- keyword -------------------------- defaults - frontend - listen -- backend - tcp-check send-binary X - X X tcp-check send-binary-lf X - X X tcp-check set-var X - X X tcp-check unset-var X - X X tcp-request connection X (!) X X - tcp-request content X (!) X X X tcp-request inspect-delay X (!) X X X tcp-request session X (!) X X - tcp-response content X (!) - X X tcp-response inspect-delay X (!) - X X timeout check X - X X timeout client X X X - timeout client-fin X X X - timeout connect X - X X timeout http-keep-alive X X X X timeout http-request X X X X timeout queue X - X X timeout server X - X X timeout server-fin X - X X timeout tarpit X X X X timeout tunnel X - X X transparent (deprecated) X - X X unique-id-format X X X - unique-id-header X X X - use_backend - X X - use-fcgi-app - - X X use-server - - X X
4.2、常用代理参数
1、acl(访问控制规则)
- acl <aclname> <criterion> [flags] [operator] <value> ...
- 声明访问控制列表。
2、balance(负载平衡算法)
- balance <algorithm> [ <arguments> ]
- <algorithm>:负载平衡算法。仅适用于没有使用持久连接,或将请求重新分派到另一个服务器。
- <arguments>:算法的可选参数列表。目前只有"url_param"和"uri"支持可选参数。
- balance url_param <param> [check_post]
- 声明负载均衡算法
- backend的默认负载均衡算法设是roundrobin。每个backend只能设置一次算法。
示例:
balance roundrobin balance url_param userid balance url_param session_id check_post 64 balance hdr(User-Agent) balance hdr(host) balance hdr(Host) use_domain_only
3、bind(监听地址)
- bind [<address>]:<port_range> [, ...] [param*]
- bind /<path> [, ...] [param*]
- 监听一个或多个地址和或端口。
示例:
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}"
4、capture request header(捕获请求头)
- capture request header <name> len <length>
- <name>:要捕获的header头的名称,header头名称不区分字符大小写,但建议按照它们在请求中出现的样子来写,比如大写首字母。需要注意的是,记录在日志中的是header头的值,而非header头的名称。
- <length>:记录header头的值时所记录的精确长度,超出的部分将会被忽略。
- 将捕获的header头的值使用花括号'{}'括起来,然后记录到日志中。
- 如果要捕获多个header头的值,它们将由竖线('|')分隔,并且将以它们声明的顺序出现在日志文件中。
- 不存在的header头将被记录为空字符串。
- 经常需要捕获的header头有:在虚拟主机环境中使用的“Host”、上传时的请求头中的“Content-length”、快速区别真实用户和机器人的“User-agent”,以及代理环境中记录真实请求来源的“X-Forward-For”。
- 捕获的请求头的数量和长度都没有限制。为了保证同一个frontend中日志格式的统一,header头的捕获仅能在frontend中定义。
示例:
capture request header Host len 15 capture request header X-Forwarded-For len 15 capture request header Referer len 15
5、cookie(cookie持久)
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ] [ dynamic ] [ attr <value> ]*
- <name>:cookie的名称,它将被监视、修改或插入,以带来持久性。该cookie通过响应中的“Set-Cookie”头发送给客户端,并在所有请求中由客户端以“cookie”头返回。
- rewrite:表明cookie将由后端服务器提供,HAProxy必须修改其值以设置其中的服务器标识符。当“Set-cookie”和“Cache-control”头的复杂组合留给应用程序管理时,这种模式很方便。应用程序可以决定发出持久性cookie是否合适。由于应该监视所有响应,因此该模式不能在HTTP隧道模式下工作。除非应用程序行为非常复杂和/或损坏,否则建议不要在新的部署中使用这种模式。该关键字与“insert”和“prefix”不兼容。
- insert:如果客户端没有允许它访问此服务器的cookie,HAProxy必须在服务器响应中插入持久性cookie。如果不使用“preserve”选项,如果后端服务器发出同名的cookie,将在处理之前删除。因此,此模式可用于升级在“rewrite”模式下运行的现有配置。cookie将只是一个会话cookie,不会存储在客户端磁盘上。默认情况下,除非添加了“indirect”选项,服务器将看到客户端发出的cookie。由于缓存效果,通常明智的做法是添加“nocache”或“postonly”关键字。"insert"关键字与"rewrite"和"prefix"不兼容。
- prefix:表示将完成一个现有的cookie,而不是依赖于专用cookie进行持久性。在某些特定的环境中,客户端不支持多个cookie,而应用程序已经需要它,这可能需要它。在这种情况下,每当服务器设置一个名为<name>的cookie时,它将以服务器的标识符和分隔符作为前缀。该前缀将从所有客户端请求中删除,以便服务器仍然找到它发出的cookie。由于所有的请求和响应都可能被修改,因此该模式不适用于隧道模式。“prefix”关键字与“rewrite”和“insert”不兼容。注意:强烈建议不要使用带“prefix”的“indirect”,否则服务器cookie更新不会发送给客户端。
- indirect:不会向已经为处理请求的服务器提供有效cookie的客户端发送cookie。如果服务器本身设置了这样的cookie,它将被删除,除非同时设置了“保存”选项。在“插入”模式下,这将从传输到服务器的请求中额外删除cookie,使持久性机制从应用程序的角度完全透明。注意:强烈建议不要使用带“prefix”的“indirect”,否则服务器cookie更新不会发送给客户端。
- nocache:当客户端和HAProxy之间有缓存时,建议将此选项与插入模式结合使用,因为它确保当需要插入cookie时,可缓存的响应将被标记为不可缓存。这一点很重要,因为如果所有持久性cookie都添加到一个可缓存的主页上,那么所有客户都将从外部缓存获取页面,并共享相同的持久性cookie,导致一个服务器接收到比其他服务器多得多的流量。请参见“insert”和“postonly”选项。
- postonly:该选项确保cookie插入只会在响应POST请求时执行。它是"nocache"选项的一个替代选项,因为POST响应是不可缓存的,所以这确保了持久性cookie永远不会被缓存。由于大多数站点在第一次POST(通常是一个登录请求)之前不需要任何类型的持久性,这是一种非常有效的优化缓存的方法,而不用冒险在缓存中找到持久性cookie。参见“insert”和“nocache”选项。
- preserve:这个选项只能用于"insert"和/或"indirect"。它允许服务器本身发出持久性cookie。在这种情况下,如果在响应中发现一个cookie,HAProxy将不动它。这对于在注销请求后结束持久性非常有用。为此,服务器只需要发送一个带有无效值(例如空)或带有过去日期的cookie。通过将这种机制与“disable-on-404”检查选项相结合,可以执行完全优雅的关闭,因为用户在注销后肯定会离开服务器。
- httponly:这个选项告诉HAProxy在插入cookie时添加一个“HttpOnly”cookie属性。使用这个属性,用户代理就不会与非http组件共享cookie。有关此属性的更多信息,请查看RFC6265。
- secure:该选项告诉HAProxy在插入cookie时添加一个“Secure”cookie属性。使用此属性,用户代理将永远不会在非安全通道上发出此cookie,这意味着通过此标志学习到的cookie将只在SSL/TLS连接上显示。有关此属性的更多信息,请查看RFC6265。
- domain:此选项允许指定插入cookie的域。它只需要一个参数:有效的域名。如果域名以一个点开头,浏览器就可以将它用于以该名称结尾的任何主机。也可以通过多次调用此选项来指定多个域名。有些浏览器可能对域的数量有小的限制,所以在这样做时要小心。根据记录,发送10个域到MSIE 6或Firefox 2工作正常。
- maxidle:此选项允许在一段空闲时间后忽略插入的cookie。它只适用于插入模式的cookie。当一个cookie发送给客户端时,这个cookie发出的日期也会被发送。在这个cookie的进一步展示中,如果日期比参数指定的延迟时间(以秒为单位)要早,它将被忽略。否则,当响应发送到客户端时,如果需要,它将被刷新。这对于防止从未关闭浏览器的用户在同一台服务器上停留太长时间(例如,在场大小改变后)特别有用。当设置了此选项,并且cookie没有日期时,它总是被接受,但会在响应中刷新。这将维护管理员访问其站点的能力。日期在24小时之后的cookie将被忽略。这样做可以让管理员修复时区问题,而不会有把用户踢出站点的风险。
- maxlife:该选项允许插入的cookie在一段生命周期后被忽略,无论它们是否正在使用。它只适用于插入模式cookie。当一个cookie第一次发送给客户端时,这个cookie发出的日期也会被发送。在这个cookie的进一步展示中,如果日期比参数指定的延迟时间(以秒为单位)要早,它将被忽略。如果请求中的cookie没有日期,则接受它并设置日期。日期在24小时之后的cookie将被忽略。这样做可以让管理员修复时区问题,而不会有把用户踢出站点的风险。与maxidle相反,该值不会刷新,只有第一次访问日期才计数。此时可以同时使用maxidle和maxlife。这对于防止从未关闭浏览器的用户在同一台服务器上停留太长时间(例如,在场大小改变后)特别有用。这比maxidle方法更强,因为它强制在绝对延迟之后重新分派。
- dynamic:激活动态cookies。在使用时,根据服务器的IP和端口,以及在“dynamic-cookie-key”后端指令中指定的密钥,为每个服务器动态创建一个会话cookie。cookie会在每次IP地址改变时重新生成,并且只针对IPv4/IPv6生成。
- attr:这个选项告诉HAProxy在插入cookie时添加一个额外的属性。属性值可以包含除控制字符和";"以外的任何字符。这个选项可以重复使用。
示例:
cookie JSESSIONID prefix cookie SRV insert indirect nocache cookie SRV insert postonly indirect cookie SRV insert indirect nocache maxidle 30m maxlife 8h
6、default_backend(默认后端)
- default_backend <backend>
- <backend>:使用的后端名称。
- 声明默认后端。
- 所有没有被ACl规则匹配的请求都将转发到默认后端。
示例:
use_backend dynamic if url_dyn use_backend static if url_css url_img extension_img default_backend dynamic
7、errorfile(由haproxy提供错误页面)
- errorfile <code> <file>
- <code>:指定对哪些状态码返回指定的文件,可用的状态码有200、400、401、403、404、405、407、408、410、413、425、429、500、501、502、503和504。
- <file>:指定用于响应的文件。建议文件名以".http"结尾,这样人们就不会将响应与HTML错误页面混淆,并且使用绝对路径,因为文件是在执行chroot之前读取的。
- 当客户端请求的文件不存在时,返回一个指定的文件给客户端而非由haproxy生成的错误代码。
- 这个参数并不意味着重写后端服务器返回的错误,而是重写HAProxy检测和返回的错误。这就是为什么支持的错误列表仅限于一个小集合的原因。
- 200是为了响应匹配“monitor-uri”规则的请求而发出的。
- errorfile指定的文件在HAProxy启动时被解析,并且根据HTTP规范必须是有效的。它们不应该超过配置的缓冲区大小(BUFSIZE),通常是16kB,否则将返回一个内部错误。另外,明智的做法是不要引用本地内容(例如图片),以避免在所有服务器关闭时客户端和HAProxy之间的循环,导致返回一个错误而不是一个图片。最后,响应不能超过(tune.bufsize - tune.maxrewrite),这样“http-after-response”规则仍然有操作的空间(参见“tune.maxrewrite”)。
- 在读取配置文件的同时读取这些文件(errorfile指定的文件)并保存在内存中。由于这个原因,即使将errorfile指定的文件删除了,也会继续返回错误。
示例:
errorfile 400 /etc/haproxy/errorfiles/400badreq.http errorfile 408 /dev/null #解决Chrome预连接(pre-connect)bug errorfile 403 /etc/haproxy/errorfiles/403forbid.http errorfile 503 /etc/haproxy/errorfiles/503sorry.http
8、errorloc(由sorry server来提供错误页面)
- errorloc <code> <url>
- errorloc302 <code> <url>
- errorloc303 <code> <url>
- <code>:指定对哪些状态码返回指定的URL,可用的状态码有200、400、401、403、404、405、407、408、410、413、425、429、500、501、502、503和504。
- <url>:它是Location头中指定的页面的具体路径,可以是指向同一站点上的错误页面的相对URI,也可以是指向另一个站点上的错误页面的绝对URI。注意,如果URI本身可能产生相同的错误(例如500),相对URI可以避免重定向循环。
- 当客户端请求的文件不存在时,返回一个重定向的URL给客户端而非由haproxy生成的错误代码。
- 这个参数并不意味着重写后端服务器返回的错误,而是重写HAProxy检测和返回的错误。这就是为什么支持的错误列表仅限于一个小集合的原因。
- 200是为了响应匹配“monitor-uri”规则的请求而发出的。
- 注意,这前两个都返回302状态码,它告诉客户机使用相同的HTTP方法获取指定的URL。对于POST等非GET方法,这可能会造成很大的问题,因为发送到客户机的URL可能不允许用于除GET以外的其他方法。要解决这个问题,请使用“errorloc303”,它发送HTTP 303状态代码,指示客户端必须通过GET请求获取URL。
示例:
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.html errorloc 503 /etc/haproxy/errorpages/sorry.html
9、hash-type(hash的类型)
- hash-type <method> <function> <modifier>
- <method>:将hash值映射到后端服务器的方法,方法有两个map-based和consistent,在大多数场景下推荐使用默认的map-based方法。
- map-based:hash表是一个包含了所有活动后端服务器的静态数组。其hash值将会非常平滑,将考虑权重,但其为静态方法,即对后端服务器的权重进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选后端服务器是根据其在数组中的位置进行的,因此,当服务器数量发生变化时,大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。
- consistent:“一致性哈希算法”,hash表是一个由各后端服务器组成的树状结构(将后端服务器分布在hash环上)。基于hash键在hash树中查找相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一小部分请求产生影响,因此,尤其适用于后端服务器为cache的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果,因此,可能需要不时的调整服务器的权重以获得更好的均衡性。
- <function>:要使用哈希函数
- sdbm:这个函数最初是为SDBM (ndbm的公共域重新实现)数据库库创建的。研究发现,它在置乱位中表现良好,能更好地分配密钥,减少分裂。它也恰好是一个良好的通用哈希函数,具有良好的分布,除非总服务器权重是64的倍数,在这种情况下,应用雪崩修改器可能会有所帮助。
- djb2:这个函数最初是由Dan Bernstein多年前在comp.lang.c上提出的。研究表明,对于某些工作负载,该函数提供了比sdbm更好的分布。它通常在基于文本的输入中工作得很好,但在只有数字的输入或总服务器权重是33的倍数时,它的表现可能非常差,除非还使用雪崩修改器。
- wt6:这个函数是为HAProxy设计的,同时在过去测试其他函数。它不像其他的那样流畅,但对输入数据集或服务器数量的敏感性要低得多。它可以作为sdbm+雪崩或djb2+雪崩的替代方案,用于一致的散列,或者在URL参数中的源IP地址或访问者标识符等数字数据上进行散列。
- crc32:这是最常见的CRC32实现,用于以太网,gzip, PNG等。它比其他方法慢,但可能提供更好的分布或更难以预测的结果,尤其是在字符串上使用时。
- <modifier>:指示一个可选的方法在哈希后应用的键
- avalanche:该指令指出,上面的哈希函数的结果不应该以原始形式使用,但必须首先应用4字节的完整雪崩哈希。这个步骤的目的是混合从前一个散列得到的结果位,以避免在输入包含一些有限的值或服务器的数量是散列的某个组件的倍数(SDBM为64,DJB2为33)时产生任何不希望的影响。启用雪崩会使结果更难以预测,但也不像使用原始函数时那么流畅。对于某些工作负载,可能需要进行一些测试。这个散列是Bob Jenkins提出的众多散列之一。
- <method>:将hash值映射到后端服务器的方法,方法有两个map-based和consistent,在大多数场景下推荐使用默认的map-based方法。
- 默认的method是"map-based"。默认的function是“sdbm”,函数的选择应该基于哈希值的范围。
10、http-request(七层访问控制)
- http-request语句定义了一组应用于第7层处理的规则。当在frontend、listen或者backend部分满足规则时,规则将按其声明顺序计算。任何规则都可以有选择地跟随一个基于acl的条件,在这种情况下,只有当条件为真时才对其进行评估。
- http-request <action> [options...] [ { if | unless } <condition> ]
- <action>:满足规则时的操作动作。
- add-acl(<file-name>) <key fmt>
- add-header <name> <fmt>
- allow
- auth [realm <realm>]
- cache-use <name>
- capture <sample> [ len <length> | id <id> ]
- del-acl(<file-name>) <key fmt>
- del-header <name> [ -m <meth> ]
- del-map(<file-name>) <key fmt>
- deny [ { status | deny_status } <code>] ...
- disable-l7-retry
- do-resolve(<var>,<resolvers>,[ipv4,ipv6]) <expr>
- early-hint <name> <fmt>
- normalize-uri <normalizer>
- redirect <rule>
- reject
- replace-header <name> <match-regex> <replace-fmt>
- replace-path <match-regex> <replace-fmt>
- replace-pathq <match-regex> <replace-fmt>
- replace-uri <match-regex> <replace-fmt>
- replace-value <name> <match-regex> <replace-fmt>
- return [status <code>] [content-type <type>] ...
- sc-inc-gpc(<idx>,<sc-id>)
- sc-inc-gpc0(<sc-id>)
- sc-inc-gpc1(<sc-id>)
- sc-set-gpt(<idx>,<sc-id>) { <int> | <expr> }
- sc-set-gpt0(<sc-id>) { <int> | <expr> }
- set-dst <expr>
- set-dst-port <expr>
- set-header <name> <fmt>
- set-log-level <level>
- set-map(<file-name>) <key fmt> <value fmt>
- set-mark <mark>
- set-method <fmt>
- set-nice <nice>
- set-path <fmt>
- set-pathq <fmt>
- set-priority-class <expr>
- set-priority-offset <expr>
- set-query <fmt>
- set-src <expr>
- set-src-port <expr>
- set-timeout { server | tunnel } { <timeout> | <expr> }
- set-tos <tos>
- set-uri <fmt>
- set-var(<var-name>) <expr>
- set-var-fmt(<var-name>) <fmt>
- send-spoe-group <engine-name> <group-name>
- silent-drop
- strict-mode { on | off }
- tarpit [ { status | deny_status } <code>] ...
- track-sc0 <key> [table <table>]
- track-sc1 <key> [table <table>]
- track-sc2 <key> [table <table>]
- unset-var(<var-name>)
- use-service <service-name>
- wait-for-body time <time> [ at-least <bytes> ]
- wait-for-handshake
- cache-use <name>
- <action>:满足规则时的操作动作。
示例1:
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
示例2:
acl key req.hdr(X-Add-Acl-Key) -m found acl add path /addacl acl del path /delacl acl myhost hdr(Host) -f myhost.lst http-request add-acl(myhost.lst) %[req.hdr(X-Add-Acl-Key)] if key add http-request del-acl(myhost.lst) %[req.hdr(X-Add-Acl-Key)] if key del
示例3:
acl value req.hdr(X-Value) -m found acl setmap path /setmap acl delmap path /delmap use_backend bk_appli if { hdr(Host),map_str(map.lst) -m found } http-request set-map(map.lst) %[src] %[req.hdr(X-Value)] if setmap value http-request del-map(map.lst) %[src] if delmap
11、log(每个实例记录日志)
- log global
- log <address> [len <length>] [format <format>] [sample <ranges>:<sample_size>] <facility> [<level> [<minlevel>]]
- no log
- <address>:syslog服务器的地址,可以是IPv4或IPv6等。可以指定一个UDP端口,如果没有指定端口,默认使用514(标准syslog端口)
- <length>:如果一条日志长度大于此值,在发送给syslog服务器之前将被截断。取值范围为80-65535。默认值1024。
- <format>日志格式。它可能是local、rfc3164、rfc5424、priority、short、timed、iso或raw之一。
- <facility>必须是下面标准syslog的24个设施之一:
- kern、user、mail、daemon、auth、syslog、lpr、news、uucp、cron、auth2、ftp、ntp、audit、alert、cron2、local0、local1、local2、local3、local4、local5、local6、local7
- [max level [min level]]:缺省情况下,发送所有消息。如果指定了最大级别,则只发送严重性至少与此级别同等重要的消息。可以指定一个可选的最低级别,则比此级别更严重的日志不被发送。
- 日志有8个级别(从低到高):emerg、alert、crit、err、warning、notice、info、debug
- 决定从连接记录什么内容的是前端,而且在内容切换的情况下,来自后端的日志条目将被忽略。连接记录在“info”级别。
- 但是,后端日志声明定义了记录服务器状态变化的方式和位置。“notice”级别表示服务器上升,“warning”级别表示终止信号和最终服务终止,“alert”级别表示服务器宕机。
- 注意:根据RFC3164,消息在发出之前被截断为1024字节。
示例:
log global log stdout format short daemon # send log to systemd log stdout format raw daemon # send everything to stdout log stderr format raw daemon notice # send important events to stderr log 127.0.0.1:514 local0 notice # only send important events log tcp@127.0.0.1:514 local0 notice notice # same but limit output level and send in tcp log "${LOCAL_SYSLOG}:514" local0 notice # send to local server
12、maxconn(frontend最大并发连接数)
- maxconn <conns>
- <conns>:frontend将接受服务的最大并发连接数。多余的连接将由系统在套接字的侦听队列中排队。
- 如果系统支持,在大型站点上将这个限制提高到非常高的水平是很有用的,这样HAProxy就可以管理连接队列,而不是让客户端等待未应答的连接尝试。
- 这个值不应该超过全局的maxconn。一个连接包含两个缓冲区,每个缓冲区的长度为tune.bufsize(默认为16kB),以及其他一些数据,导致每个已建立的连接消耗内存大约33kB。这意味着,如果经过适当调整,1GB内存可以承受大约20000-25000个并发连接。
13、mode(实例运行的模式)
- mode { tcp|http }
- tcp:该实例将工作在纯TCP模式下。客户端和后端服务器之间建立全双工连接,不进行七层检查。这是默认模式。它应该用于SSL, SSH, SMTP,…
- http:该实例将在HTTP模式下工作。在连接到任何后端服务器之前,haproxy将对客户端的请求进行深入分析。任何不符合rfc的请求将被拒绝。第七层滤波、处理和交换将成为可能。这是HAProxy最大的价值所在。
- 在进行内容切换时,前端和后端必须处于相同的模式(通常为HTTP),否则配置将被拒绝。
14、option dontlognull
- option dontlognull
- no option dontlognull
- 启用或禁用空连接的日志记录
- 启用“dontlognull”选项,表示不会记录没有传输数据的连接。请注意,错误仍然会返回给客户端,并在统计中进行解释。如果这不是所希望的,可以使用http-ignore-probes选项。
- 一般建议不要在不受控制的环境中使用此选项(如互联网),否则扫描和其他恶意活动将不会被记录。
- 如果在“defaults”部分启用了该选项,则可以在特定实例中通过在其前面添加“no”关键字禁用该选项。
- no option dontlognull:记录空连接的日志信息
- 在某些环境中,有些组件将定期连接到各种系统,以确保它们仍然存在。这种情况可能来自另一个负载均衡器,也可能来自监视系统。默认情况下,即使是简单的端口探测或扫描也会产生日志。
15、option forwardfor(插入X-Forwarded-For)
- option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
- <network>:可选参数,可以是IP,也可以是一个网络。如果请求中的原IP被其匹配,就禁用此选项。
- <name>:可选参数。可使用一个自定义的首部,如“X-Client”来替代“X-Forwarded-For”。有些独特的web服务器的确需要用于一个独特的首部。
- if-none:可选参数。仅在此header头不存在时才将其添加至请求报文中
- 由于HAProxy工作在反向代理模式下,后端服务器将HAProxy的IP地址视为其客户端地址。当服务器日志中需要用户的IP地址时,这有时会令人恼火。为了解决这个问题,HAProxy可能会在所有发送到后端服务器的请求中添加一个的header头“X-Forwarded-For”。这个“X-Forwarded-For”的值就是用户的IP地址。由于此消息头总是附加在现有消息头列表的末尾,后端服务器必须配置为始终只使用此消息头的最后一次出现。注意,必须只使用头的最后一次出现,因为客户端确实可能已经带来了一个。
- 关键字“header”可以用来提供一个不同的头名称来替换默认的“X-Forwarded-For”。当你可能已经有了来自不同应用程序(例如stunnel)的“X-Forwarded-For”报头,并且你需要保存它时,这将非常有用。
- 通过“except”关键字,可以禁用为已知的源地址或网络添加报头。任何匹配网络的源IP都不会导致添加此报头。最常见的用途是使用私有网络或127.0.0.1。支持IPv4和IPv6。
- 此选项可以在前端或后端指定。如果其中至少有一个使用它,则将添加头。注意,如果两者都定义了,则后端header子参数的设置优先于前端的设置。如果前端和后端至少又一个使用了"if-none"参数,那么"if-none"参数就会生效。
示例:
frontend www mode http option forwardfor except 127.0.0.1 # stunnel already adds the header backend www mode http option forwardfor header X-Client
16、redirect(重定向)
- redirect location <loc> [code <code>] <option> [{if | unless} <condition>]
- redirect prefix <pfx> [code <code>] <option> [{if | unless} <condition>]
- redirect scheme <sch> [code <code>] <option> [{if | unless} <condition>]
- <loc>:使用“redirect location”(位置重定向),<loc>中的确切值被放置到HTTP “Location” header头中。
- 当在“http-request”规则中使用时,<loc>值遵循日志格式规则,可以包括一些动态值。
- <pfx>:使用“redirect prefix”(前缀重定向),“Location”头是由<pfx>和完整的URI路径(包括查询字符串)构建的,除非指定了“drop-query”选项。
- 如果<pfx>等于“/”,那么在原始URI之前不会插入任何内容。它允许重定向到相同的URL(例如,插入cookie)。
- 当在“http-request”规则中使用时,<pfx>值遵循日志格式规则,可以包括一些动态值。
- <sch>:使用"redirect scheme"(协议重定向),通过<sch>、"://"、"Host"和URI(包括查询字符串)构建"Location",除非指定了"drop-query"选项。
- 如果没有找到路径或路径是“*”,则使用“/”代替。
- 如果没有找到“Host”头,则返回一个空的主机,大多数最新的浏览器将其解释为重定向到相同的主机。
- 此指令主要用于将HTTP重定向到HTTPS。
- 当在“http-request”规则中使用时,<sch>值遵循日志格式规则,可以包括一些动态值。
- <code>:可选的。表明是哪种类型的HTTP重定向。
- 只支持301、302、303、307和308,如果不指定编码,默认使用302。
- 301表示"Moved permanently"(永久移动),浏览器可能会缓存。
- 302表示"Moved temporarily"(临时移动),意味着浏览器不应该缓存。
- 303等价于302,不同之处在于浏览器将通过GET方法获取位置信息。
- 307与302类似,但明确表示必须重用相同的方法。
- 如果必须使用相同的方法,308替换301。
- <option>:可以调整重定向的预期行为的选项
- drop-query:当在基于前缀的重定向中使用此关键字时,将设置位置,而不需要任何可能的查询字符串,这对于将用户定向到不安全的页面(例如)非常有用。它对位置类型的重定向没有影响。
- append-slash:可以与“drop-query”结合使用,将URL不以“/”结尾的用户重定向到以“/”结尾的用户。确保搜索引擎只看到一个URL是很有用的。为此,首选返回码301。
- ignore-empty:仅在使用日志格式表达式生成位置时有效(即在http-request或http-response中使用时)。它指出,如果表达式的结果为空,则应该静默跳过该规则。它的主要用途是允许使用简单的映射对已知路径进行大规模重定向。
- set-cookie NAME[=value]:一个"Set-Cookie"报头将被添加NAME(可选的"=value")到响应中。这有时用来表示用户已被看到,例如防止某些类型的DoS。没有添加其他cookie选项,因此cookie将是一个会话cookie。请注意,对于浏览器来说,唯一没有等号的cookie名称与带有等号的cookie是不同的。
- clear-cookie NAME[=]:“set - cookie”报头将添加NAME(和可选的“=”),但将“Max-Age”属性设置为零。这将告诉浏览器删除此cookie。例如,它在注销页面上很有用。需要注意的是,清除cookie“NAME”不会删除具有“NAME=value”的cookie集。您必须为此清除cookie“NAME=”,因为浏览器会产生影响。
- <loc>:使用“redirect location”(位置重定向),<loc>中的确切值被放置到HTTP “Location” header头中。
示例:
#将URL重定向到HTTPS acl clear dst_port 80 acl secure dst_port 8080 acl login_page url_beg /login acl logout url_beg /logout acl uid_given url_reg /login?userid=[^&]+ acl cookie_set hdr_sub(cookie) SEEN=1 redirect prefix https://mysite.com set-cookie SEEN=1 if !cookie_set redirect prefix https://mysite.com if login_page !secure redirect prefix http://mysite.com drop-query if login_page !uid_given redirect location http://mysite.com/ if !login_page secure redirect location / clear-cookie USERID= if logout #发送重定向请求没有'/'的文章。 acl missing_slash path_reg ^/article/[^/]*$ redirect code 301 prefix / drop-query append-slash if missing_slash #当HAProxy处理SSL时,将所有HTTP重定向到HTTPS。 redirect scheme https if !{ ssl_fc } #在所有没有www.前缀的主机前面追加它 http-request redirect code 301 location http://www.%[hdr(host)]%[capture.req.uri] unless { hdr_beg(host) -i www } #只将旧url永久重定向到新url http-request redirect code 301 location %[path,map_str(old-blog-articles.map)] ignore-empty
17、server(声明后端服务器)
- server <name> <address>[:[port]] [param*]
- <name>:分配给此服务器的内部名称。此名称将出现在日志和警报中。如果设置了“http-send-name-header”,它将被添加到发送到后端服务器的请求头中。
- <address>:后端服务器的IPv4或IPv6地址。地址“0.0.0.0”或“*”具有特殊含义,它表示连接将被转发到与客户端连接相同的IP地址。
- <port>:后端服务的端口。如果不设置,后端服务器使用与frontend相同的端口。
- <param*>:后端服务器的参数列表。“server”关键字接受大量的选项,并有一个完整的部分专门用于它。
示例:
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"
18、use_backend(后端)
- use_backend <backend> [{if | unless} <condition>]
- <backend>:后端名称,或解析为后端名称的“log-format”字符串。
- <condition>:一个由acl组成的条件。如果省略,则无条件地应用规则。
示例:
正则表达式匹配,如果请求的域名满足正则表达式中的2个域名返回true acl frank_web hdr_reg(host) -i ^(www.test.com|news.test.com)$ #域匹配,如果请求的域名满足fund.test.com.sh返回true acl frank_fund hdr_dom(host) -i fund.test.com #当满足frank_web的策略时使用的后端是server_web use_backend server_web if frank_web #当满足frank_fund的策略时使用的后端是server_blog use_backend server_blog if frank_fund
19、option http-keep-alive
- 使用keepAlive连接,后端为静态建议使用http-keep-alive
20、option http-server-close
- 在服务器端关闭HTTP连接,后端为动态应用程序建议使用http-server-close
4.3、HAProxy使用的负载平衡算法
- backend的默认负载均衡算法设是roundrobin。每个backend只能设置一次算法。
- balance <algorithm> [ <arguments> ]
- balance url_param <param> [check_post]
- roundrobin
- 基于权重进行轮询。当服务器的处理时间保持均匀分布时,这是最平衡、最公平的算法。
- 该算法是动态的,这表示服务器的权重可以动态调整,例如对于慢启动。
- 每个backend段最多可以有4095个活动的后端服务器。
- 注意,在一些大型服务器组中,当服务器在停机一段时间后重新启动时,有时可能在数百个请求之后才能轮询到重新启动的服务器。
- static-rr
- 基于权重进行轮询。
- 与roundrobin类似:
- 只是该算法是静态的,这意味着动态调整服务器的权重不会生效。
- 该算法对后端服务器的数量没有限制。还使用更少的CPU(大约减少1%)。
- 不支持慢启动,在高负荷的情况下,服务器重新上线时会立即被分配大量连接。
- leastconn
- 连接数最少的后端服务器接收请求。除了已建立的连接外,它还将考虑排队的连接数量,以排队到最小的队列中。在具有相同负载的后端服务器组中执行轮询。
- 该算法是动态的,这意味着服务器的权重可以动态调整,例如对于慢启动。
- 建议在需要长连接的会话的场景中使用该算法,如LDAP、SQL、TSE等。但不太适用于短会话的协议,如HTTP。
- source
- 将请求的源地址进行hash运算,并除以后端服务器的权重之和,然后将请求派发至某个匹配的后端服务器。
- 这可以将同一个客户端的请求始终被派发至同一个后端服务器。
- 但是,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器。
- 常用于负载均衡无cookie功能的基于TCP的协议。
- 该算法默认是静态的,不过可以使用“hash-type”修改此特性。
- 将请求的源地址进行hash运算,并除以后端服务器的权重之和,然后将请求派发至某个匹配的后端服务器。
- uri
- 对URI的左部分(“问号”标记之前的部分)或整个URI(如果存在“whole”参数)进行hash运算,并除以后端服务器的权重之和,然后将请求派发至某个匹配的后端服务器。
- 这可以将同一个uri始终被派发至同一个后端服务器。
- 但是,当服务器权重总数发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器。
- 与代理缓存和反病毒代理一起使用,以最大限度地提高缓存命中率。
- 该算法有两个可选参数“len”和“depth”,后面都跟一个正整数:
- "len"参数:只使用URI开头的n个字符进行hash运算。注意,将"len"设为1很少有意义,因为大多数uri都以"/"开头。
- "depth"参数:只使用URI开头的n个目录深度进行hash运算,uri中的每一个斜杠都是一个目录深度。
- 如果同时指定了两个参数,哪个短哪个生效。
- “path-only”参数:从路径的第一个“/”开始进行hash运算。这可以用来忽略绝对uri的权限部分,并确保HTTP/1和HTTP/2 uri将提供相同的散列。
- 该算法默认是静态的,不过可以使用“hash-type”修改此特性。
- 注意,该算法只能用于HTTP模式。
- 对URI的左部分(“问号”标记之前的部分)或整个URI(如果存在“whole”参数)进行hash运算,并除以后端服务器的权重之和,然后将请求派发至某个匹配的后端服务器。
- url_param
- 在每个HTTP GET请求中检索<arguments>。
- 如果使用了修饰符“check_post”,如果在URL的'?'之后的字符串中没有搜索到<arguments>,就会搜索HTTP POST的请求实体。
- 如果指定的参数后面跟着一个等号('=')和一个值,那么该值将被执行并hash运算除以后端服务器的权重之和。该算法可以通过追踪请求中的用户标识进而确保同一个用户ID的请求将被送往同一个特定的服务器。
- 如果没有找到匹配的参数和值,就采用轮询算法。
- 该算法默认是静态的,不过可以使用“hash-type”修改此特性。
- 注意,该算法只能用于HTTP模式。
- 在每个HTTP GET请求中检索<arguments>。
- hdr(<name>)
- 检索每个请求头,如果有请求头的key等于<name>,就对<name>是值进行hash运算。和ACL 'hdr()'函数一样。如果没有请求头中没有相应的key,或有key无值,则使用轮询算法。
- 'use_domain_only'参数:可选参数,仅对带有特定标题(如“Host”)的主域部分进行hash。例如,在Host值haproxy.1wt.eu中,仅对1wt进行hash。
- 该算法默认是静态的,不过可以使用“hash-type”修改此特性。
- rdp-cookie
- rdp-cookie(<name>)
- 对于每个传入的TCP请求,RDP cookie的<name>(或者“mstshash”,如果省略)将被查找和hash。这种机制作为降级的持久性模式非常有用,因为它可以始终将相同的用户(或相同的会话ID)发送到相同的服务器。如果没有找到cookie,则使用普通的轮询算法。
- 注意,为了使其工作,前端必须确保RDP cookie已经存在于请求缓冲区中。为此,必须使用“tcp-request content accept”规则和“req.rdp_cookie_cnt” ACL。
- 该算法默认是静态的,不过可以使用“hash-type”修改此特性。
- random
- random(<draws>)
- first
- 第一个具有可用连接槽的服务器接收连接。
- 从最低的数字标识符到最高的数字标识符进行选择后端服务器(服务器参数“id”)。
- 只要连接数没有到达一个服务器的maxconn值,就不会使用下一个服务器。该算法在没有设置maxconn的情况下是没有意义的。
- 算法的目的是始终使用最小数量的服务器,以便在非密集时间里关闭额外的服务器。这种算法忽略了服务器权重,并给长会话(如RDP或IMAP)带来了比HTTP更大的好处。
5、后端服务器可以使用的参数(param)
- server <name> <address>[:port] [settings ...]
- default-server [settings ...]
1、backup
- 指定备用的后端服务器。仅在所有非备用后端服务器都不可用的情况下,才使用备用后端服务器。
2、check(启用健康检查)
- 如果未设置,则不执行健康检查,并且始终认为后端服务器是可用的。
- 如果设置了,但没有配置检查方法,仅进行简单的tcp检查(仅检查端口是否存在)。当设置了“SSL”或“check-ssl”时是SSL/TLS,当设置了“send-proxy”或“check-send-proxy”时,两者都可能与连接前缀(如代理协议头)结合在一起。
- 如果设置了,并进行应用程序级健康检查,可以尝试获取一个文件,如果可以获取到,就表示后端服务器是可用的。
- inter <delay>:设置检查之间的时间间隔
- rise <count>:定义健康检查需要成功多少次才能说后端服务器是可用的。默认值是2。
- fall <count>:定义健康检查需要失败多少次才能说后端服务器是不可用的。默认值是3。
示例:
#简单的tcp检查 backend foo server s1 192.168.0.1:80 check #这实现了TCP连接+ TLS握手 backend foo server s1 192.168.0.1:443 ssl check #简单的TCP检查就足以确保检查成功 backend foo option tcp-check tcp-check connect server s1 192.168.0.1:443 ssl check
3、cookie <value>
- 为后端服务器的cookie设置一个值<value>。在一个客户端的请求第一到达HAProxy时,将该cookie值传给客户端,那么这个客户端以后的请求将被转发到同一个后端服务器。
- 多个后端服务器可以使用同一个cookie值。
4、maxconn <maxconn>
- 指定可以发送到此后端服务器的最大并发连接数。如果传入的并发连接数高于这个值,它们将被放置在请求队列中,等待一个槽被释放。这个参数非常重要,因为它可以避免脆弱的服务器在极端负载下崩溃。如果指定了"minconn"参数,则限制变为动态的。默认值为“0”,即无限制。
- 在HTTP模式下,该参数限制的是并发请求数,而不是连接数。多个请求可以通过单个TCP连接进行多路复用。例如,如果您指定maxconn为50,您可能会看到1到50个实际服务器连接,但不超过50个并发请求。
5、maxqueue <maxqueue>
- 指定该后端服务器的队列的最大长度。如果达到这个限制,下一个请求将被重新分派到其他服务器,而不是无限期地等待服务。这将打破持久性,但可能允许人们在他们试图连接的服务器死亡时快速重新登录。默认值是“0”,这意味着队列是无限的。
6、observe <mode>
- 通过观察服务器的通信状况来判定其健康状态。默认情况下,此功能是禁用的,启用它还需要启用健康检查。支持“layer4”和“layer7”两种模式。在第4层模式中,只有成功/不成功的tcp连接。在第7层,这只允许http代理,从服务器收到的响应被验证,像有效/错误的http代码,不可解析的头、超时等等。有效的状态码包括100到499、501和505。
7、redir <prefix>
- 启用重定向功能,将发往此服务器的GET和HEAD请求均以302状态码响应;需要注意的是,在prefix后面不能使用/,且不能使用相对地址,以免造成循环;
8、weight <weight>
- 后端服务器相对于其他后端服务器的权重,默认为1,最大值为256。0表示不参与负载均衡(不被调度),但仍将接受持久连接。
6、ACL的用法
- HAProxy能够从请求或响应、客户端或服务器信息、表、环境信息等中提取数据。
- 提取数据的操作称为获取样本。
- haproxy的ACL用于实现基于请求报文的首部、响应报文的内容或其它的环境状态信息来做出转发决策,这大大增强了其配置弹性。
- 其配置法则通常分为两步,首先去定义ACL,即定义一个测试条件,而后在条件得到满足时执行某特定的动作,如阻止请求、转发至某特定的后端或添一个头部。
6.1、ACL的基础
- 访问控制列表(Access Control list, ACL)通常根据从请求或响应中提取的内容做出决策。
- (1)从请求或响应中提取数据样本。
- (2)将提取到的样本与控制规则进行匹配。
- (3)根据匹配,进行相应的动作(拒绝、选择后端或添加header头)
6.1.1、ACL语法
acl <aclname> <criterion> [flags] [operator] [<value>] ...
1、<aclname>:ACL名称
- ACL名称由大小写字母、数字、“-”(短划线)、“_”(下划线)、“.”'(点)和':'(冒号)。ACL名称区分大小写。
- haproxy中,acl可以重名,这可以把多个测试条件定义为一个共同的acl。
2、<criterion>:测试标准
- 可以通过测试标准(即各种获取数据的方法)从请求或响应中获取样本数据。测试方式可以由[flags]指定的标志进行调整。
- 有些测试标准也可以为其在之前指定一个操作符[operator]。
3、[flags]:标志位
- -i:在匹配所有后续模式时忽略大小写。
- 只对其后的条目有效。
- acl valid-ua hdr(user-agent) -f exact-ua.lst -i -f generic-ua.lst test
- -f:从文件中加载模式。
- 后面跟着文件名,其中所有行都将作为单独的值读取。如果要从多个文件加载模式,甚至可以传递多个“-f”参数。空行以及'#'开头的行将被忽略。
- -m:使用特定的模式匹配方法
- -n:禁止DNS解析
- 它与ip文件加载一起使用。默认情况下,如果解析器不能解析ip地址,它认为解析的字符串可能是一个域名,并尝试dns解析。
- -M:加载-f指定的文件,像映射文件一样。
- 允许ACL使用映射文件。如果设置了此标志,则将文件解析为两列文件。第一列包含ACL使用的模式,第二列包含示例。
- -u:强制ACL的id唯一
- 强制指定ACL的唯一id。这个惟一的id与套接字接口一起用于标识ACL并动态更改其值。请注意,即使设置了id,文件也始终由其名称标识。
- --:强制结束的标志。当字符串看起来像一个标志时很有用。
4、[<value>]:与样本数据进行匹配的数据
- 获取数据的方法返回的数据类型:boolean、整数、IP地址、字符串、数据块。
- ACL引擎可以将获取数据样本的方法返回的数据类型与下面的数据进行匹配:
- boolean
- 整数、整数范围
- IP地址、一个网络(network)
- 字符串(exact, substring, suffix, prefix, subdir, domain)
- 正则表达式
- hex block
5、模式匹配方法
- 标志位-m使用的模式匹配方法:
- found:只检查是否可以在流中找到,但不要将其与任何模式进行比较。可以检测某些内容,如headers、cookie等。即使它们是空的,没有与任何东西比较,也没有计算它们。
- bool:检查该值为布尔值。它只能应用于返回布尔值或整型值且不接受模式的获取。返回0或false表示不匹配,其他值表示匹配。
- int:将值匹配为整数。它可以用于整型和布尔型样本。false为整数0,true为整数1。
- ip:匹配IPv4或IPv6地址。它只与IP地址样本兼容,所以它是隐含的,永远不需要。
- bin:将内容与表示二进制序列的十六进制字符串相匹配。这可以用于二进制或字符串样本。
- len:将样本长度匹配为整数。这可以用于二进制或字符串样本。
- str:(精确匹配)根据字符串匹配内容。这可以用于二进制或字符串样本。
- sub:(子字符串匹配)检查内容是否包含至少一个提供的字符串模式。这可以用于二进制或字符串样本。
- reg:(正则表达式匹配)根据正则表达式列表匹配内容。这可以用于二进制或字符串样本。
- beg:(前缀匹配)检查内容是否像提供的字符串模式一样开始。这可以用于二进制或字符串样本。
- end:(后缀匹配)检查内容是否像提供的字符串模式一样结束。这可以用于二进制或字符串样本。
- dir:(子目录匹配)检查用斜杠分隔的部分内容是否与提供的字符串模式完全匹配。这可以用于二进制或字符串样本。
- dom:(域匹配)检查以点分隔的部分内容是否与提供的字符串模式完全匹配。这可以用于二进制或字符串样本。
#检测HTTP请求中是否存在cookie "JSESSIONID" acl jsess_present req.cook(JSESSIONID) -m found #为了对缓冲区中前500个字节的数据应用正则表达式,可以使用以下acl: acl script_tag req.payload(0,500) -m reg -i <script> #在使用"-i"时,regex库会慢很多的系统中,可以在匹配之前将样本转换为小写 acl script_tag req.payload(0,500),lower -m reg <script>
- 所有acl特定的条件都包含一个默认匹配方法。通常,这些条件是由连接原始示例获取方法的名称和匹配方法组成的。例如,"hdr_beg"将"beg"匹配应用于使用"hdr"获取方法检索的样本。由于所有acl特定的条件都依赖于一个示例获取方法,所以总是可以使用原始的示例获取方法和使用“-m”的显式匹配方法。
- 如果在特定于acl的条件上使用“-m”指定了备用匹配,则匹配方法将简单地应用于底层示例获取方法。例如,下面的所有acl都是完全等价的:
acl short_form hdr_beg(host) www. acl alternate1 hdr_beg(host) -m beg www. acl alternate2 hdr_dom(host) -m beg www. acl alternate3 hdr(host) -m beg www.
6.1.2、可以匹配的数据
1、匹配布尔值
- 为了匹配布尔值,不需要任何值,所有值都被忽略。
- 默认情况下,所有类型为"Boolean"的获取方法都使用布尔匹配。当使用布尔匹配时,获取的值按原样返回,这意味着布尔值“true”将始终匹配,而布尔值“false”将永远不匹配。
- 布尔匹配也可以使用“-m bool”强制返回整型值的获取方法。然后,整数值0被转换为布尔值“false”,所有其他值被转换为“true”。
2、匹配整数
- 默认情况下,整型匹配应用于整型获取方法。它也可以使用“-m int”强制转换布尔值,在这种情况下,“false”被转换为整数0,“true”被转换为整数1。
- 整数匹配也支持整数范围和操作符。注意,整型匹配只适用于正值。范围是用冒号分隔的下界和上界表示的值,两者都可以省略。
- 例如,“1024:65535”是一个有效的范围,用来表示非特权端口的范围,“1024:”也可以。“0:1023”是特权端口的有效表示,“:1023”也可以。
- 可用的整数匹配操作符有:
- eq:等于
- ge:大于或等于
- gt:大于
- le:小于或等于
- lt:小于
示例:
#匹配任何负的Content-Length报头: acl negative-length req.hdr_val(content-length) lt 0 #SSL的版本号在3.0到3.1之间(包括): acl sslv3 req.ssl_ver 3:3.1
3、匹配字符串
- 字符串匹配适用于字符串或二进制获取方法,并以6种不同的形式存在:
- 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匹配。
示例:
#如果字符串<tag>在二进制样本中存在,则匹配 acl tag_found req.payload(0,0),hex -m sub 3C7461673E
4、匹配正则表达式(regex)
- 就像字符串匹配一样,regex匹配适用于传入的逐字字符串,除了反斜杠(“\”),它使转义一些字符(如空格)成为可能。
5、匹配任意数据块
可以将一些提取的样本与可能不安全地表示为字符串的二进制块进行匹配。为此,当匹配方法设置为二进制时,模式必须作为偶数中的一系列十六进制数字传递。每个两位数的序列表示一个字节。十六进制数字可以使用大写或小写。
示例:
# match "Hello\n" in the input stream (\x48 \x65 \x6c \x6c \x6f \x0a) acl hello req.payload(0,6) -m bin 48656c6c6f0a
6、匹配IPv4和IPv6地址
- IPv4地址值可以指定为纯地址或附加一个子网掩码,在这种情况下,只要它在网络内,IPv4地址就匹配。纯地址也可以用可解析的主机名替换,但是通常不鼓励这样做,因为这会增加读取和调试配置的难度。如果使用了主机名,您至少应该确保它们存在于/etc/hosts中,以便在解析配置时,配置不依赖于任何随机的DNS匹配。
- 为了避免随机解析IP地址带来的麻烦,IPv6模式中永远不允许使用主机名。
6.2、使用acl形成条件
- 条件是acl和操作符的组合。支持3种操作符:
- AND(隐性)
- OR(显式使用关键字"OR"或"||"操作符)
- !(用感叹号表示否定)
- 这些条件通常用在"if"或"unless"语句之后,表示条件何时触发动作。
示例:
#阻止"OPTIONS"以外的方法对请求“*”,以及没有内容长度的POST请求,和内容长度大于0的GET或HEAD请求,最后每个请求不是GET/HEAD/POST/OPTIONS ! acl missing_cl req.hdr_cnt(Content-length) eq 0 http-request deny if HTTP_URL_STAR !METH_OPTIONS || METH_POST missing_cl http-request deny if METH_GET HTTP_CONTENT http-request deny unless METH_GET or METH_POST or METH_OPTIONS
示例:
#为“www”网站的静态内容请求和“img”、“video”、“download”和“ftp”主机上的每个请求选择不同的后端: acl url_static path_beg /static /images /img /css acl url_static path_end .gif .png .jpg .css .js acl host_www hdr_beg(host) -i www acl host_static hdr_beg(host) -i img. video. download. ftp. #现在使用后端“static”为所有静态主机,并为主机的静态url“www”。其余部分使用后端“www”。 use_backend static if host_static or host_www url_static use_backend www if host_www
- 也可以使用“匿名acl”形成规则。这些是未命名的ACL表达式,不需要声明就可以动态构建。它们必须用大括号括起来,每个大括号之前和之后都有一个空格(因为大括号必须被视为独立的单词)。例子:
acl missing_cl req.hdr_cnt(Content-length) eq 0 http-request deny if METH_POST missing_cl #与上面的两行等价 http-request deny if METH_POST { req.hdr_cnt(Content-length) eq 0 }
6.3、获取数据样本(即ACL的<aclname>)
- 一般都是从四层或七层获取数据样本。
1、hdr([<name>[,<occ>]]) : string
- 相当于在请求中使用req.hdr(),在响应中使用res.hdr()。
2、req.hdr([<name>[,<occ>]]) : string
- 返回HTTP请求中某个header头<name>的最后一个值(使用逗号分割)。如果需要某个header头的全部值,可以使用req.fhdr()。
- 可选地,可以将特定发生事件指定为位置号。正值表示从第一次出现开始的位置,1是第一个出现的位置。负值表示相对于最后一个的位置,-1表示最后一个。
- 典型的用法是将X-Forwarded-For头转换为IP后,与IP stick-table相关联。
- ACL衍生品:
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
3、path : string
- 返回HTTP请求中URL路径,从第一个斜杠开始,在问号之前结束(没有主机部分)。
- 一种典型的应用是具有预取功能的缓存,以及需要从数据库聚合多个信息并将其保存在缓存中的门户。注意,对于传出缓存,使用“url”会更明智。对于acl,它通常用于匹配精确的文件名(例如:"/login.php"),或者使用派生形式的目录部分。
- ACL衍生品:
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是否以/static、/images、/javascript或/stylesheets开始 acl url_static path_beg -i /static /images /javascript /stylesheets #URL是否以.jpg、.gif、.png、.css或.js结尾。 acl url_static path_end -i .jpg .gif .png .css .js
4、method : integer + string
- 返回一个与HTTP请求中的方法对应的整数值。例如,“GET”等于1(检查源以建立匹配)。
示例:
#只接受GET和HEAD请求 acl valid_method method GET HEAD http-request deny if ! valid_method
5、be_sess_rate([<backend>]) : integer
- 返回一个与后端(backend)会话创建速率(即每秒创建的会话数)相对应的整数值。当一个昂贵或脆弱的后端达到过高的会话速率时,使用acl切换到备用后端,或限制服务滥用(例如防止吸走在线词典)。使用日志格式指令将该元素添加到日志中也会很有用。
示例:
#如果过于频繁地请求字典,则重定向到错误页 backend dynamic mode http acl being_scanned be_sess_rate gt 100 redirect location /denied.html if being_scanned
6、fe_sess_rate([<frontend>]) : integer
- 返回一个与前端(frontend)会话创建速率(即每秒创建的会话数)相对应的整数值。它与acl一起使用,将传入会话速率限制在一个可接受的范围内,以防止在最早的时刻滥用服务,例如,在与其他第4层acl结合使用时,为了迫使客户端等待一段时间,以使速率低于限制。使用日志格式指令将该元素添加到日志中也会很有用。请参见前端使用的“rate-limit sessions”指令。
示例:
#该前端限制接收邮件为10/s,最大并发连接数为100。我们接受任何低于10/s的连接,并强制多余的客户端等待100毫秒。 #由于客户端被限制为最多100个,所以每秒接收的邮件不能超过10个。 frontend mail bind :25 mode tcp maxconn 100 acl too_fast fe_sess_rate ge 10 tcp-request inspect-delay 100ms tcp-request content accept if ! too_fast tcp-request content accept if WAIT_END