Haproxy

时间: 20181121


目录

SRE(Site Reliability Engineer)

不同的调度器的特点

Haproxy.cfg

主配置段defaults

后端配置

session sticky会话保持方式

HAProxy功能

HAProxy组成

global配置

日志系统

性能调整

配置段

配置参数

哈希算法

健康状态检测server后check的参数

cookie配置

统计监控接口配置stats

HAProxy sock文件通信管理后端主机(命令行)

工作模式mode

健康状态检测

forwardfor配置

为指定的MIME类型启用压缩传输功能

错误页配置

修改报文首部

连接超时

ACL

base

url

req.hdr

预定义ACL

配置ACL

基于ACL的动静分离示例

配置4层转发

配置HAProxy支持https协议

总结


SRE(Site Reliability Engineer)网站可靠性工程师



不同的调度器的特点

nginx向后调度时需要消耗额外端口

nginx可以直接提供后端服务器监控,查看其是否正常

lvs不会消耗端口


Haproxy.cfg

Global Settings

Proxies

frontend

backend

listen

defaults


主配置段defaults

maxconn <number> 最大并发连接

connections to <number> 

maxconnrate <number> 最大连接速率

maxsslcoon <number> 最大ssl连接

spread-checks 分散检查


后端配置

frontend, backend

bind 绑定地址

server 定义后端服务器

server <name> address <params>

[param*]

maxconn 定义当前server最大并发连接数

backlog 后端队列

backup 后端备用服务器,一般用来显示say sorry

check

addr

port

inter 检测时间间隔,默认为2s

rise 连续多少次成功会将后端fail的服务器标记为可用

fail 连续多少次结果为失败时才标记为不可用默认为3

注意: option httpck, "smtpchk", "mysql-check", "pgsql-check"

and "ssl-hello-check" 用于定义应用层检测方法默认为tcp握手检测

cookie 定义是否要给客户端添加所定义的cookie信息

disabled 标记为可用 

on-error <mode> 后端服务故障时的行动策略

- fastinter 强制快速间隔检测后端服务器状态

- fail-check

- sudden-death  

- mark-down

redir 重定向

weight

balance

roundrobin最多支持4095个后端server  (适用于短连接)

static-rr 需要重启才可生效  (适用于短连接)

leastconn 最少连接(适用于长连接)

支持加权时运行时调整


first优先使用,即当第一个请求满时,才往第二个转发请求

source   源hash 是否支持运行时调整权重受限于hash-type

uri  uri-hash 是否支持运行时调整权重受限于hash-type 非常适合后端为缓存服务器

url_param 可以通过参数实现定向向后端调用

hdr 其于首部参数实现调用特定的后端或持续

rdp

status enable

status uri /customize

status auth name:password

status admin if true|LOCALHOST 在web界面可以管理后端服务器设置其状态

maxcoon

mode

http

tcp

health

cookie <name> insert nocache indirect

option forwardfor 

errorfile <code> <file>

errorfile 400 /path/400badreq.html

errorfile 403 /path/forbidden.html

errorloc <code> <url>

reqadd 添加向后端请求的http首部

rspadd 添加向客户端响应的http首部

reqdel

reqidel


log

global

<address>

no log

compression

option httpchk <method> <uri> <version>

http-check expect [!] <match>



acl <acl_name> <criterior> [flags] [operator] <value>

<value>的类型

- boolean

- integer or integer range

- IP address / network

- string (exact, substring, suffix, prefix, subdir, domain)

- regular expression

- hex block


<flags>

-i 忽略大小写

-m 使用指定的模式匹配方式

-n 禁用dns反解其域名

-u 

--


[operator]


<criterian>


timeout



session sticky会话保持方式

session sticky: ip_hash, sh, source

session replication cluster

session server


haproxy 不支持缓存


HAProxy功能

HAProxy是TCP / HTTP反向代理服务器,尤其适合于高可用性环境

可以针对HTTP请求添加cookie,进行路由后端服务器

可平衡负载至后端服务器,并支持持久连接

支持基于cookie进行调度

支持所有主服务器故障切换至备用服务器

支持专用端口实现监控服务

支持不影响现有连接情况下停止接受新连接请求

可以在双向添加,修改或删除HTTP报文首部

支持基于pattern实现连接请求的访问控制

通过特定的URI为授权用户提供详细的状态信息

支持http反向代理

支持动态程序的反向代理

支持基于数据库的反向代理


HAProxy组成


程序环境:

主程序:/usr/sbin/haproxy

配置文件:/etc/haproxy/haproxy.cfg

Unit file:/usr/lib/systemd/system/haproxy.service

配置段:

global:全局配置段

进程及安全配置相关的参数

性能调整相关参数

Debug参数

proxies:代理配置段

defaults:为frontend, backend, listen提供默认配置

frontend:前端,相当于nginx中的server {}

backend:后端,相当于nginx中的upstream {}

listen:同时拥有前端和后端,适用于一对一环境

简单的配置示例

frontend web

bind *:80

default_backend websrvs

backend websrvs

balance roundrobin

server srv1 192.168.0.101:80 check

server srv2 192.168.0.102:80 check


global配置

global配置参数:

进程及安全管理:chroot, deamon,user, group, uid, gid

nbproc <number> 要启动的haproxy的进程数量,系统默认单进程,要求使用daemon模式

ulimit-n <number> 每个haproxy进程可打开的最大文件数,系统自动会指定,不建议设置

daemon 后端方式运行,建议使用

log 定义全局的syslog服务器;最多可以定义两个

log <address> [len <length>] <facility> [max level [min level]]

address: rsyslog服务器地址

len: 记录日志的长度,默认1024


日志系统

log:

log global

log <address> [len <length>] <facility> [<level> [<minlevel>]]

length 日志行的长度,默认1024

no log

注意:

默认发往本机的日志服务器

(1) local2.* /var/log/local2.log

(2) $ModLoad imudp

$UDPServerRun 514

log-format <string>:

课外实践:参考文档实现combined格式的记录


将特定信息记录在日志中

capture cookie <name> len <length> 

捕获请求和响应报文中的 cookie并记录日志

capture request header <name> len <length>

捕获请求报文中指定的首部并记录日志

示例:

capture request header X-Forwarded-For len 15

capture response header <name> len <length>

捕获响应报文中指定的首部并记录日志

示例:

capture response header Content-length len 9

capture response header Location len 15


性能调整:

maxconn <number>:设置每个haproxy进程所能接受的最大并发连接数

maxconnrate <number>:设置每个进程每秒种所能建立的最大连接数量

maxse***ate <number>:设置每个进程每秒种所能建立的最大会话数量

maxsslconn <number>: 每进程支持SSL的最大连接数量

spread-checks <0..50, in percent> 健康检测延迟时长百分比,建议2-5之间


配置段

代理配置段:

- defaults <name>

- frontend <name>

- backend <name>

- listen <name>

Frontend段:指定接收客户端连接侦听套接字设置

Backend段:指定将连接请求转发至后端服务器的相关设置

Listen段:指定完整的前后端设置

proxy 名称:使用字母 数字 - _ . : 并区分字符大小写


配置参数:

bind:指定一个或多个前端侦听地址和端口

bind [<address>]:<port_range> [, ...] [param*]

示例:

listen http_proxy

bind :80,:443

bind 10.0.0.1:10080,10.0.0.1:10443

bind /run/ssl-frontend.sock user root mode 600 accept-proxy


Balance配置

balance:后端服务器组内的服务器调度算法

balance <algorithm> [ <arguments> ]

balance url_param <param> [check_post]

调度算法:

roundrobin:基于权重轮询,动态算法,支持权重的运行时调整,支持慢启动;

每个后端backend中最多支持4095个server,此为默认调度算法

server options: weight #

static-rr:基于权重轮询,静态算法,不支持权重的运行时调整及慢启动;后端

主机数量无上限

leastconn:加权最少连接,动态算法,最少连接的后端服务器优先分配接收新

连接,相同连接时轮询,推荐在较长会话的场景使用,例如MySQL,LDAP等

,不适合http

first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达

到上限,新请求才会分配给下一台服务,不支持权重

source:源地址hash,新连接先按权重分配,后续连接按source分配请求,实

现会话绑定


uri:

对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,

以后派发至某挑出的服务器,适用于后端缓存服务器

<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<q

uery>#<frag>

左半部分:/<path>;<params>

整个uri:/<path>;<params>?<query>#<frag>

url_param:

对用户请求的uri中的<params>部分中的参数的值作hash计算,并由服

务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以

确保来自同一个用户的请求始终发往同一个Backend Server

http://www.winthcloud.com/bbs/hello;type=title

hdr(<name>):对于每个http请求,此处由<name>指定的http首部将会

被取出做hash计算; 并由服务器总权重相除以后派发至某挑出的服务

器;无有效值的会被轮询调度hdr(Cookie)

rdp-cookie 远程桌面相关

rdp-cookie(<name>)


哈希算法

hash-type:哈希算法

hash-type <method> <function> <modifier>

method:

map-based:除权取余法,哈希数据结构是静态数组

consistent:一致性哈希,哈希数据结构是一棵树

function : 哈希函数,取值:sdbm,djb2,wt6

modifier: 取值avalanche时,将修改哈希值,而非直接使用

default_backend <backend>

无use_backend 匹配时,使用默认的backend,用于frontend中

default-server [param*]

为backend中的各server设定默认选项



server <name> <address>[:[port]] [param*]

定义后端主机的各服务器及其选项

server <name> <address>[:port] [settings ...]

default-server [settings ...]

<name>:后端服务器在haproxy上的内部名称;出现在日志及警告信息

<address>:后端服务器地址,支持使用主机名

[:[port]]:端口映射;省略时,表示同bind中绑定的端口

[param*]:参数

weight <weight>:权重,默认为1

maxconn <maxconn>:当前后端server的最大并发连接数

backlog <backlog>:当server的连接数达到上限后的后援队列长度

backup:设定当前server为备用服务器Sorry Server


健康状态检测server后check的参数

check:对当前server做健康状态检测,只用于四层检测

addr :检测时使用的IP地址

port :针对此端口进行检测

inter <delay>:检测之间的时间间隔,默认为2000ms

rise <count>:连续多少次检测结果为“成功”才标记为可用;默认为2

fall <count>:连续多少次检测结果为“失败”才标记为不可用;默认为3

注意:option后面加httpchk,smtpchk, mysql-check, pgsql-check,ssl-hellochk

方法,可用于实现应用层检测

disabled:标记为不可用

redir <prefix>:将发往此server的所有GET和HEAD类的请求重定向至指定的URL


cookie配置

cookie <value>:为当前server指定cookie值,实现基于cookie的会话黏性

cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] 

[ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* 

[ maxidle <idle> ] [ maxlife <life> ]

<name>:cookie名称,用于实现持久连接

rewrite:重写

insert:插入

prefix:前缀

nocache:当client和hapoxy之间有缓存时,不缓存cookie


cookie配置示例

基于cookie的session sticky的实现

backend websrvs

cookie WEBSRV insert nocache

server srv1 172.16.0.6:80 weight 2 check rise 1 fall 2 cookie srv1

server srv2 172.16.0.7:80 weight 1 check rise 1 fall 2 cookie srv2


统计接口启用相关的参数


stats enable   启用统计页;基于默认的参数启用stats page

stats hide-version   隐藏版本

stats refresh <delay>  设定自动刷新时间间隔

stats uri <prefix>  自定义stats page uri,默认值:/haproxy?stats

stats realm <realm>  认证时的realm,示例:stats realm : HAProxy\ Statistics

stats auth <user>:<passwd>认证时的账号和密码,可使用多次默认:no authentication

stats admin { if | unless } <cond>  启用stats page中的管理功能


配置示例

listen stats

bind :9527

stats enable

stats hide-version

stats uri /hastats

stats realm HAPorxy\ Stats\ Page

stats auth admin1:password1

stats auth admin1:password2

stats refresh 3s

stats admin if TRUE (这里只是测试使用,真环境要配置acl)


HAProxy sock文件通信管理后端主机(命令行)

首先需要设置socket支持管理

global

        stats socket /var/run/haproxy.sock mode 600 level admin

        stats timeout 2m


    stats socket /var/lib/haproxy/stats level admin  

安装通信软件

yum install socat

echo "help"| socat stdio /usr/local/haproxy/stats 

然后根据提示就可以设置相应的主机了 如将server设置为drain模式

echo "set server bktest/web1 state drain" | socat stdio 

/var/lib/haproxy/stats


工作模式mode

maxconn <conns>:为指定的frontend定义其最大并发连接数;默认为3000

mode { tcp|http|health }

定义haproxy的工作模式

tcp:基于layer4实现代理;可代理mysql, pgsql, ssh, ssl等协议,https时使用

此模式,默认模式

http:仅当代理协议为http时使用,CentOS中haproxy实际的默认模式

health:工作为健康状态检查的响应模式,当连接请求到达时回应“OK”

后即断开连接,较少使用


TCP模式示例:

listen ssh

bind :22022

balance leastconn

mode tcp

server sshsrv1 172.16.0.6:22 check

server sshsrv2 172.16.0.7:22 check


健康状态检测

对后端服务器做http协议健康状态检测:通常用于backend

option httpchk 默认向后端服务器发请求:OPTIONS / HTTP/1.0

option httpchk <uri>

option httpchk <method> <uri>

option httpchk <method> <uri> <version>

定义基于http协议的7层健康状态检测机制

http-check expect [!] <match> <pattern>

http协议健康状态检测响应内容或指定响应码


forwardfor配置


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

在由haproxy发往后端主机的请求报文中添加“X-Forwarded-For”首部,

其值为前端客户端的地址;用于向后端主发送真实的客户端IP

[ except <network> ]:请求报请来自此处指定的网络时不予添加此首部

如haproxy自身所在网络

[ header <name> ]:使用自定义的首部名称,而非“X-Forwarded-For”

[ if-none ] 如果没有首部才添加首部,如果有使用默认值


为指定的MIME类型启用压缩传输功能

compression algo <algorithm> ...:启用http协议的压缩机制,指明压缩算

法gzip, deflate

compression type <mime type> ...:指明压缩的MIMI类型


错误页配置

errorfile <code> <file> 自定义错误页

<code>:HTTP status code.

支持200, 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 <code> <url>

相当于errorloc302 <code> <url>,利用302重定向至指URL

示例:errorloc 503 http://www.winthcloud.com/error_pages/503.html


修改报文首部

在请求报文尾部添加指定首部

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

在响应报文尾部添加指定首部

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

示例:rspadd X-Via:\ HAPorxy

从请求报文中删除匹配正则表达式的首部

reqdel <search> [{if | unless} <cond>]

reqidel <search> [{if | unless} <cond>] 不分大小写

从响应报文中删除匹配正则表达式的首部

rspdel <search> [{if | unless} <cond>]

rspidel <search> [{if | unless} <cond>] 不分大小写

示例: rspidel server.*


连接超时

timeout client <timeout>  客户端最长空闲连接超时时长 默认单位是毫秒

timeout server <timeout>  后端服务器最长空闲连接超时时长

timeout http-keep-alive <timeout>  持久连接的持久时长

timeout http-request <timeout>  一次完整的HTTP请求的最大等待时长

timeout connect <timeout>  成功连接后端服务器的最大等待时长

timeout client-fin <timeout>  客户端半连接的空闲时长

timeout server-fin <timeout>  后端服务器半连接的空闲时长



ACL

acl:访问控制列表(ACL)的使用提供了一个灵活的解决方案来执行内容交换,并且通

常基于从请求中提取的内容、响应或任何环境状态进行决策

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

<aclname>:ACL名称,可使用字母 数字 : . - _ ,区分字符大小写

<criterion>: 比较的标准和条件

<value>的类型:

- boolean

- integer or integer range

- IP address / network

- string (exact, substring, suffix, prefix, subdir, domain)

- regular expression

- hex block


<flags>

-i 不区分大小写

-m 使用指定的pattern匹配方法

-n 不做DNS解析

-u 强制每个ACL必须唯一ID,否则多个同名ACL或关系

-- 强制flag结束. 当字符串和某个flag相似时使用


[operator]

匹配整数值:eq、ge、gt、le、lt

匹配字符串:

- 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进行匹配


acl作为条件时的逻辑关系:

- 与:隐式(默认)使用

- 或:使用“or” 或 “||”表示

- 否定:使用“!“ 表示

示例:if invalid_src invalid_port 与关系

if invalid_src || invalid_port 或

if ! invalid_src 非

<criterion> :各种条件

dst 目标IP

dst_port 目标PORT

src 源IP

src_port 源PORT

示例:acl invalid_src src 172.16.100.200


base : string

返回第一个主机头和请求的路径部分的连接,该请求从第一个斜杠开始

并在问号之前结束,对虚拟主机有用

<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>

base : exact string match

base_beg: prefix match

base_dir: subdir match

base_dom: domain match

base_end: suffix match

base_len: length match

base_reg: regex match

base_sub: substring match


示例:

path_beg /images/

path_end .jpg .jpeg .png .gif

path_reg ^/images.*\.jpeg$

path_sub image

path_dir jpegs

path_dom winthcloud


/images/jpegs/20180123/logo.jpg


url : string

提取请求中的URL。一个典型的应用是具有预取能力的缓存,以及需要从数据库聚合多个

信息并将它们保存在缓存中的网页门户入口,推荐使用path

url :exact string match

url_beg : prefix match

url_dir : subdir match

url_dom : domain match

url_end : suffix match

url_len : length match

url_reg : regex match

url_sub : substring match


req.hdr([<name>[,<occ>]]) : string

提取在一个HTTP请求报文的首部


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

示例:

acl bad_agent hdr_sub(User-Agent) -i curl wget

block if bad_agent

status : integer

返回在响应报文中的状态码



预定义ACL

ACL名称等价于说明

TRUE always_true 总是匹配

FALSE always_false 从不匹配

HTTP req_proto_http 匹配HTTP协议

HTTP_1.0 req_ver 1.0 匹配HTTP协议1.0

HTTP_1.1 req_ver 1.1 匹配HTTP协议1.1

HTTP_CONTENT hdr_val(content-length) gt 0 匹配已存在内容长度

HTTP_URL_ABS url_reg ^[^/:]*:// 匹配URL绝对路径

HTTP_URL_SLASH url_beg / 匹配URL相对路径

HTTP_URL_STAR url * 匹配 URL 等于 "*"

LOCALHOST src 127.0.0.1/8 匹配从localhost来的连接

METH_CONNECT method CONNECT 匹配HTTP CONNECT方法

METH_GET method GET HEAD match HTTP GET or HEAD method

METH_HEADmethod HEAD match HTTP HEAD method

METH_OPTIONS method OPTIONS match HTTP OPTIONS method

METH_POST method POST match HTTP POST method

METH_TRACE method TRACE match HTTP TRACE method

RDP_COOKIE req_rdp_cookie_cnt gt 0 match presence of an RDP cookie

REQ_CONTENT req_len gt 0 match data in the request buffer

WAIT_END wait_end wait for end of content analysis


配置ACL

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

当if/unless一个基于ACL的条件匹配时切换指定backend

block { if | unless } <condition>

阻止7层请求if/unless一个条件匹配

示例:

acl invalid_src src 172.16.200.2

block if invalid_src

errorfile 403 /usr/share/haproxy/403.http

http-request { allow | deny |add-header <name> <fmt> |setheader

<name> <fmt> } [ { if | unless } <condition> ]

对7层请求的访问控制


基于ACL的动静分离示例


frontend web *:80

acl url_static path_beg -i /static /images /javascript /stylesheets

acl url_static path_end -i .jpg .gif .png .css .js .html .txt .htm

use_backend staticsrvs if url_static

default_backend appsrvs

backend staticsrvs

balance roundrobin

server staticsrv1 192.168.0.100:80 check

backend appsrvs

balance roundrobin

server app1 192.168.0.101:80 check

server app1 192.168.0.102:8080 check


配置4层转发

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

根据第4层条件对传入连接执行操作

示例:

listen ssh

bind :22222

mode tcp

balance leastconn

acl invalid_src src 172.16.0.200

tcp-request connection reject if invalid_src

server sshsrv1 192.168.1.101:22 check

server sshsrv2 192.168.1.102:22 check backup


配置HAProxy支持https协议

支持ssl会话;

bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE

crt 后证书文件为PEM格式,且同时包含证书和所有私钥

cat demo.crt demo.key > demo.pem

把80端口的请求重向定443

bind *:80

redirect scheme https if !{ ssl_fc }

向后端传递用户请求的协议和端口(frontend或backend)

http_request set-header X-Forwarded-Port %[dst_port]

http_request add-header X-Forwared-Proto https if { ssl_fc }



总结

1. 为什么建立连接协议三次握手,而关闭连接却是四次挥手

因为断开时客户端主动向服务器发送断开请求,服务器有可能还有数据未发送完

成所以只回复了一个确认包,等其发送完成后才发送了FIN=1所以就变成了4次

2. haproxy无法实现直接与动态服务器交互,中间必须有web-server,因为haproxy

其最主要的目标是实现后端代理,还有就是对http协议请求向后端代理时,更优化

向后端代理时调度更细化,不过越分析的细化,其消耗cpu计算能力也越多