环境搭建- -HAProxy
提供高可用性、负载均衡,以及基于 TCP 和 HTTP 的应用程序代理。
本文内容摘自HAProxy用法详解
安装 HAProxy
YUM 安装方式
1 | yum -y install haproxy |
haproxy 信息如下:
1 | Name : haproxy |
haproxy 相关文件如下:
1 | rpm -ql haproxy |
1 | /etc/haproxy |
配置文件
HAProxy 的配置文件由两部分组成:全局设定和对代理的设定,共分为五段:global,defaults,frontend,backend,listen。
配置文件格式
HAProxy 的配置参数类型:
- 命令行参数:最优先处理
- global 配置段:用于设定全局配置参数;
- proxy 相关配置段:如 defaults、listen、frontend 和 backend
时间格式
一些包含了值的参数表示时间,如超时时长。这些值一般以毫秒为单位,但也可以使用其它的时间单位后缀。
1 | us: 微秒(microseconds) |
全局配置
-
进程管理及安全相关的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17- chroot <jail dir>:修改 haproxy 的工作目录至指定的目录并在放弃权限之前执行 chroot() 操作,可以提升 haproxy的安全级别,不过需要
注意的是要确保指定的目录为空目录且任何用户均不能有写权限;
- daemon:让 haproxy 以守护进程的方式工作于后台,其等同于“-D”选项的功能,当然,也可以在命令行中以 “-db” 选项将其禁用;
- gid <number>:以指定的 GID 运行 haproxy,建议使用专用于运行 haproxy 的 GID,以免因权限问题带来风险;
- group <group name>:同 gid,不过指定的组名;
- log <address> <facility> [max level [min level]]:定义全局的 syslog 服务器,最多可以定义两个;
- log-send-hostname [<string>]:在 syslog 信息的首部添加当前主机名,可以为“string”指定的名称,也可以缺省使用当前主机名;
- nbproc <number>:指定启动的 haproxy 进程的个数,只能用于守护进程模式的 haproxy;默认只启动一个进程,鉴于调试困难等多方面的原因,
一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;
- pidfile:指定保存 pid 的文件
- uid:以指定的 UID 身份运行 haproxy 进程;
- ulimit-n:设定每进程所能够打开的最大文件描述符数目,默认情况下其会自动进行计算,因此不推荐修改此选项;Linux 默认单进程打开文件数
为 1024 个
- user:同 uid,但使用的是用户名;
- stats:用户访问统计数据的接口
- node:定义当前节点的名称,用于 HA 场景中多 haproxy 进程共享同一个 IP 地址时;
- description:当前实例的描述信息; -
性能调整相关的参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26- maxconn <number>:设定每个 haproxy 进程所接受的最大并发连接数,其等同于命令行选项“-n”;“ulimit -n” 自动计算的结果正是参照此
参数设定的;
- maxpipes <number>:haproxy 使用 pipe 完成基于内核的 tcp 报文重组,此选项则用于设定每进程所允许使用的最大 pipe 个数;每个
pipe 会打开两个文件描述符,因此,“ulimit -n”自动计算时会根据需要调大此值;默认为 maxconn/4,其通常会显得过大;
- noepoll:在 Linux 系统上禁用 epoll 机制;
- nokqueue:在 BSE 系统上禁用 kqueue 机制;
- nopoll:禁用 poll 机制;
- nosepoll:在 Linux 禁用启发式 epoll 机制;
- nosplice:禁止在 Linux 套接字上使用内核 tcp 重组,这会导致更多的 recv/send 系统调用;不过,在 Linux 2.6.25-28 系列的内核上,
tcp 重组功能有 bug 存在;
- spread-checks <0..50, in percent>:在 haproxy 后端有着众多服务器的场景中,在精确的时间间隔后统一对众服务器进行健康状况检查可能
会带来意外问题;此选项用于将其检查的时间间隔长度上增加或减小一定的随机时长;
- tune.bufsize <number>:设定 buffer 的大小,同样的内存条件小,较小的值可以让 haproxy 有能力接受更多的并发连接,较大的值可以让
某些应用程序使用较大的 cookie 信息;默认为 16384,其可以在编译时修改,不过强烈建议使用默认值;
- tune.chksize <number>:设定检查缓冲区的大小,单位为字节;更大的值有助于在较大的页面中完成基于字符串或模式的文本查找,但也会占用更
多的系统资源;不建议修改;
- tune.maxaccept <number>:设定 haproxy 进程内核调度运行时一次性可以接受的连接的个数,较大的值可以带来较大的吞吐率,默认在单进程
模式下为 100,多进程模式下为 8,设定为 -1 可以禁止此限制;一般不建议修改;
- tune.maxpollevents <number>:设定一次系统调用可以处理的事件最大数,默认值取决于 OS;其值小于 200 时可节约带宽,但会略微增大网络
延迟,而大于 200 时会降低延迟,但会稍稍增加网络带宽的占用量;
- tune.maxrewrite <number>:设定为首部重写或追加而预留的缓冲空间,建议使用 1024 左右的大小;在需要使用更大的空间时,haproxy 会
自动增加其值;
- tune.rcvbuf.client <number>:
- tune.rcvbuf.server <number>:设定内核套接字中服务端或客户端接收缓冲的大小,单位为字节;强烈推荐使用默认值;
- tune.sndbuf.client:
- tune.sndbuf.server: -
Debug 参数相关
1
2- debug
- quiet -
超时时长
1
2
3
4
5
6
7
8
9
10timeout http request: 在客户端建立连接但不请求数据时,关闭客户端连接
timeout queue: 等待最大时长
timeout connect: 定义 haproxy 将客户端请求转发至后端服务器所等待的超时时长
timeout client: 客户端非活动状态的超时时长
timeout server: 客户端与服务器端建立连接后,等待服务器端的超市时长超时时长
timeout http-keep-alive: 定义保持连接的超时时长
timeout check: 健康状态监测时的超时时长,过短会误判,过长资源消耗
maxcon: 每个 server 最大的连接数
http-server-close: 在使用长连接时,为避免客户端超时没有关闭长连接,此功能可以是服务端关闭长连接
redispatch: 在使用基于 cookie 定向时,一旦后端某一 server 宕机时,会将会话重新定向至某一上游服务器,必须做转发 -
实现访问控制
1
2http-request: 7 层过滤
tcp-request content:tcp 层过滤,4 层过滤 -
代理
代理相关的配置可以在如下配置段中设定1
2
3
4- defaults <name> # 用于为所有其他配置段提供默认参数,可以被下一个配置重新设定
- frontend <name> # 用于定义一系列监听的套接字,这些套接字可接受客户端请求并与之建立连接
- backend <name> # 用于定义一系列“后端”服务器,代理将会将对应客户端的请求转发至这些服务器
- listen <name> # 通过关联“frontend” 和 “backend” 定义一个完整的代理,通常只对 TCP 流量有用注: 所有代理的名称只能使用大写字母、小写字母、数字、-(中线)、_(下划线)、.(点号)和:(冒号)。此外,ACL 名称会区分字母大小写。
配置文件中的关键字
balance
1 | balance [] |
定义负载均衡算法,可用于 ‘defaults’、‘listen’ 和 ‘backend’。用于在负载均衡场景中挑选一个 server,其仅应用于持久信息不可用的条件下或 需要将一个连接重新派发至另一个服务器时。
支持的算法有:
- roundrobin: 基于权重进行轮询,在服务器的处理时间保持均匀分布时,这是最平衡、最公平的算法。此算法是动态的,这表示其权重可以在运行时 进行调整。不过在设计上,每个后端服务器技能最多接收 4128 个连接;支持慢启动
- static-rr: 基于权重进行轮询,与 roundrobin 类似,但是为静态方法,在运行时调整其服务器权重不会生效;不过,在后端服务器连接数上没有 限制;不支持慢启动,在高负荷的情况下,服务器重新上线时会立即被分配大量连接。
- leastconn(WLC):适用于长连接的会话,新的连接请求被派发至最少连接数目的后端服务器;在有着较长时间会话的场景中推荐使用此算法,如 LDAP、 SQL 等,其并不太适用于较短会话的应用层协议,如 HTTP;此算法是动态的,可以在运行期间调整权重。
- source: 将请求的源地址进行 hash 运算,并由后端服务器的权重总是相除后派发至某匹配的服务器;可以使得同一个客户端 IP 的请求始终被派发
至某特定的服务器;不过当服务器权重总是发生变化时,如某服务器宕机或添加了新的服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;
常用语负载均衡无 cookie 功能的基于 TCP 的协议;其默认为静态,不过也可以使用 hash-type 修改此特性
- 对源地址 hash,第一次调度时使用 WLC
source:IP 层,位于同一个 NAT 服务器背后的多个请求都会定向至同一个 upstream server,不利于负载均衡,一般只有不支持使用 cookie 插入又需要保持会话时使用;
cookie:应用层,有更好的负载均衡效果; - hash/weight%ip :除以权重取模
- 对源地址 hash,第一次调度时使用 WLC
- uri:对 URI 的左半部分(“问题”标记之前的部分)或整个 URI 进行 hash 运算,并由服务器的总权重相除后派发至某匹配的服务器;这可以使得对同一 个 URI 的请求总是被派发至某特定的服务器,除非服务器的权重总数发生了变化;此算法常用于代理缓存或反病毒代理以提高缓存的命中率;需要注意的是, 此算法仅应用于 HTTP 后端服务器场景;其默认为静态算法,不过也可以使用 hash-type 修改此特性;
- url_param:通过
为 URL 指定的参数在每个 HTTP GET 请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值, 那么此值将被执行 hash 运算并被服务器的总权重相除后派发至某匹配的服务器;此算法可以通过追踪请求中的用户标识进而确保同一个用户 ID 的请求将 被送往同一个特定的服务器,除非服务器的总权重发生了变化;如果某请求中没有出现指定的参数或其没有有效值,则使用轮叫算法对相应请求进行调度; 此算法默认为静态的,不过其也可以使用 hash-type 修改此特性; - hdr(
):对于每个 HTTP 请求,通过 指定的 HTTP 首部将会被检索;如果相应的首部没有出现或其没有有效值,则使用轮叫算法对相应 请求进行调度;其有一个可选选项“use_domain_only”,可在指定检索类似 Host 类的首部时仅计算域名部分(比如通过 www.baidu.com 来说, 仅计算 baidu 字符串的 hash 值)以降低 hash 算法的运算量;此算法默认为静态的,不过其也可以使用 hash-type 修改此特性; - rdp-cookie(name):表示根据据 cookie(name) 来锁定并哈希每一次 TCP 请求。
bind
1 | bind [<address>]:<port_range> [, ...] |
此指令仅能用于 frontend 和 listen 区段,用于定义一个或几个监听的套接字。
<address>:可选选项,其可以为主机名、IPv4 地址、IPv6 地址或 * ;省略此选项、将其指定为 * 或 0.0.0.0 时,将监听当前系统的所有 IPv4 地址;
<port_range>:可以是一个特定的 TCP 端口,也可是一个端口范围(如5005-5010),代理服务器将通过指定的端口来接收客户端请求; 需要注意的是,每组监听的套接字<address:port>在同一个实例上只能使用一次,而且小于 1024 的端口需要有特定权限的用户才能使用, 这可能需要通过 uid 参数来定义;
<interface>:指定物理接口的名称,仅能在 Linux 系统上使用;其不能使用接口别名,而仅能使用物理接口名称,而且只有管理有权限指定绑定的物理接口;
mode
1 | mode {tcp|http|health} |
设定实例的运行模式或协议。当实现内容交换时,前端和后端必须工作于同一种模式(一般说来都是 HTTP 模式),否则将无法启动实例。
tcp:实例运行于纯 TCP 模式,在客户端和服务器端之间将建立一个全双工的连接,且不会对7层报文做任何类型的检查;通常用于 SSL、SSH、SMTP 等应用;
http:实例运行于 HTTP 模式,客户端请求在转发至后端服务器之前将被深度分析,所有不与 RFC 格式兼容的请求都会被拒绝;此为默认模式;
health:实例工作于 health 模式,其对入站请求仅响应“OK”信息并关闭连接,且不会记录任何日志信息;此模式将用于响应外部组件的健康状态检查请求;
目前来讲,此模式已经废弃,因为 tcp 或 http 模式中的 monitor 关键字可完成类似功能;
hash-type
1 | hash-type <method> |
定义用于将 hash 码映射至后端服务器的方法;其不能用于 frontend 区段;可用方法有 map-based 和 consistent,在大多数场景下推荐使用默认的 map-based 方法。
- map-based:hash 表是一个包含了所有在线服务器的静态数组。其 hash 值将会非常平滑,会将权重考虑在列,但其为静态方法,对在线服务器的权重 进行调整将不会生效,这意味着其不支持慢速启动。此外,挑选服务器是根据其在数组中的位置进行的,因此,当一台服务器宕机或添加了一台新的服务器时, 大多数连接将会被重新派发至一个与此前不同的服务器上,对于缓存服务器的工作场景来说,此方法不甚适用。
- consistent:“一致性哈希算法”,hash 表是一个由各服务器填充而成的树状结构,将服务器散列在 hash 环上;基于 hash 键在 hash 树中查找 相应的服务器时,最近的服务器将被选中。此方法是动态的,支持在运行时修改服务器权重,因此兼容慢速启动的特性。添加一个新的服务器时,仅会对一 小部分请求产生影响,因此,尤其适用于后端服务器为 cache 的场景。不过,此算法不甚平滑,派发至各服务器的请求未必能达到理想的均衡效果。 因此,可能需要不时的调整服务器的权重以获得更好的均衡性。
log
1 | log global |
为每个实例启用事件和流量日志,因此可用于所有区段。每个实例最多可以指定两个 log 参数,不过,如果使用了“log global”且”global”段已经定了两个 log 参数时,多余的 log 参数将被忽略。
- global:当前实例的日志系统参数同”global”段中的定义时,将使用此格式;每个实例仅能定义一次“log global”语句,且其没有任何额外参数;
- <address>:定义日志发往的位置,其格式之一可以为<IPv4_address:PORT>,其中的 port 为 UDP 协议端口,默认为 514;格式之二为 Unix 套接字文件路径,但需要留心 chroot 应用及用户的读写权限;
- <facility>:可以为 syslog 系统的标准 facility 之一;
- <level>:定义日志级别,即输出信息过滤器,默认为所有信息;指定级别时,所有等于或高于此级别的日志信息将会被发送;
maxcon
1 | maxcon <conns> |
设定一个前端的最大并发连接数,因此,其不能用于 backend 区段。对于大型站点来说,可以尽可能提高此值以便让 haproxy 管理连接队列,从而避免 无法应答用户请求。当然,此最大值不能超出“global”段中的定义。此外,需要留心的是,haproxy 会为每个连接维持两个缓冲,每个缓冲的大小为 8KB, 再加上其它的数据,每个连接将大约占用 17KB 的 RAM 空间。这意味着经过适当优化后,有着 1GB 的可用 RAM 空间时将能维护 40000-50000 并发连接。
如果为<conns>指定了一个过大值,极端场景下,其最终占据的空间可能会超出当前主机的可用内存,这可能会带来意想不到的结果;因此,将其设定了一个 可接受值方为明智决定。其默认为 2000。
default_backend
1 | default_backend <backend> |
在没有匹配的”use_backend”规则时为实例指定使用的默认后端,因此,其不可应用于 backend 区段。在”frontend”和”backend”之间进行内容交换时, 通常使用”use-backend”定义其匹配规则;而没有被规则匹配到的请求将由此参数指定的后端接收。
- <backend>:指定使用的后端的名称;
使用案列:
1
2
3use_backend dynamic if url_dyn
use_backend static if url_css url_img extension_img
default_backend dynamic
server
1 | server <name> <address> [:port] [param*] |
为后端声明一个 server。因此,不能用于 defaults 和 frontend 区段。
- <name>:为此服务器指定的内部名称,其将出现在日志及警告信息中;如果设定了”http-send-server-name”,它还将被添加至发往此服务器的请求 首部中;
- <address>:此服务器的的 IPv4 地址,也支持使用可解析的主机名,只不过在启动时需要解析主机名至相应的 IPv4 地址;
- [:port]:指定将连接请求所发往的此服务器时的目标端口,其为可选项;未设定时,将使用客户端请求时的同一相端口;
- [param*]:为此服务器设定的一系参数;其可用的参数非常多,具体请参考官方文档中的说明,下面仅说明几个常用的参数;
服务器或默认服务器参数:- backup:设定为备用服务器,仅在负载均衡场景中的其它 server 均不可用于启用此 server;
- check:启动对此 server 执行健康状态检查,其可以借助于额外的其它参数完成更精细的设定,如:
- inter <delay>:设定健康状态检查的时间间隔,单位为毫秒,默认为 2000;也可以使用 fastinter 和 downinter 来根据服务器端状态 优化此时间延迟;
- rise <count>:设定健康状态检查中,某离线的 server 从离线状态转换至正常状态需要成功检查的次数;
- fall <count>:确认 server 从正常状态转换为不可用状态需要检查的次数;
- cookie <value>:为指定 server 设定 cookie 值,此处指定的值将在请求入站时被检查,第一次为此值挑选的 server 将在后续的请求中被 选中,其目的在于实现持久连接的功能;
- maxconn <maxconn>:指定此服务器接受的最大并发连接数;如果发往此服务器的连接数目高于此处指定的值,其将被放置于请求队列,以等待 其它连接被释放;haproxy 有 n 个进程,每个支持 m 个连接,后端有 x 个服务器,每个最大支持 y 个连接,则 n*m <= x*y,如果后端服 务器支持排队,则 n*m <= x*(y+z),z 为每个服务器的排队队列
- maxqueue <maxqueue>:设定请求队列的最大长度;
- observe <mode>:通过观察服务器的通信状况来判定其健康状态,默认为禁用,其支持的类型有“layer4”和“layer7”,“layer7”仅能用于 http 代理场景;
- redir <prefix>:启用重定向功能,将发往此服务器的 GET 和 HEAD 请求均以 302 状态码响应;需要注意的是,在 prefix 后面不能
使用 /,且不能使用相对地址,以免造成循环;例如:
1
server srv1 127.0.0.1:80 redir http://www.baiduc.com check
- weight <weight>: 权重,默认为 1,最大值为 256,0 表示不参与负载均衡(不被调度)。检查方法:例如:
1
2
3
4option httpchk
option httpchk
option httpchk
option httpchk: 不能用于 frontend 段,1
2
3
4backend https_relay
mode tcp
option httpchk OPTIONS * HTTP/1.1\r\nHost:\ www.feiyu.com
server apache1 192.168.1.1:443 check port 80
capture request header
1 | capture request header <name> len <length> |
捕获并记录指定的请求首部最近一次出现时的第一个值,仅能用于“frontend”和“listen”区段。捕获的首部值使用花括号 {} 括起来后添加进日志中。 如果需要捕获多个首部值,它们将以指定的次序出现在日志文件中,并以竖线“|”作为分隔符。不存在的首部记录为空字符串,最常需要捕获的首部包括在 虚拟主机环境中使用的“Host”、上传请求首部中的“Content-length”、快速区别真实用户和网络机器人的“User-agent”,以及代理环境中记录真实请求 来源的“X-Forward-For”。
<name>:要捕获的首部的名称,此名称不区分字符大小写,但建议与它们出现在首部中的格式相同,比如大写首字母。需要注意的是,记录在日志中的是 首部对应的值,而非首部名称。
<length>:指定记录首部值时所记录的精确长度,超出的部分将会被忽略。
可以捕获的请求首部的个数没有限制,但每个捕获最多只能记录 64 个字符。为了保证同一个 frontend 中日志格式的统一性,首部捕获仅能在 frontend 中定义。
capture response header
1 | capture response header <name> len <length> |
捕获并记录响应首部,其格式和要点同请求首部。
stats enable
启用基于程序编译时默认设置的统计报告,不能用于“frontend”区段。只要没有另外的其它设定,它们就会使用如下的配置:
1 | - stats uri : /haproxy?stats |
尽管“stats enable”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。下面是一个配置案例。
1 | backend public_www |
stats hide-version
1 | stats auth <user>:<passwd> |
启用带认证的统计报告功能并授权一个用户帐号,其不能用于“frontend”区段。
<user>:授权进行访问的用户名;
<passwd>:此用户的访问密码,明文格式;
此语句将基于默认设定启用统计报告功能,并仅允许其定义的用户访问,其也可以定义多次以授权多个用户帐号。可以结合“stats realm”参数在提示
用户认证时给出一个领域说明信息。在使用非法用户访问统计功能时,其将会响应一个“401 Forbidden”页面。其认证方式为HTTP Basic认证,密码传输
会以明文方式进行,因此,配置文件中也使用明文方式存储以说明其非保密信息故此不能相同于其它关键性帐号的密码。
尽管“stats auth”一条就能够启用统计报告,但还是建议设定其它所有的参数,以免其依赖于默认设定而带来非期后果。
配置示例
HTTP 服务器配置完整示例
1 | --------------------------------------------------------------------- |
负载均衡 MySQL 配置示例
1 | --------------------------------------------------------------------- |
-
2021-04-02
HAProxy 是目前比较流行的一种集群调度工具。