HAProxy代理

---------------------------------------------------------------------------------------------------------------------------------------------

一、介绍

1、应对客户端c10k以上同时连接的高性能的TCP和HTTP负载均衡器,其功能是用来提供基于cookie的持久性,基于内容的交换,过载保护的高级流浪管制,自动故障切换,以正则表达式为基础的控制运行时间,基于web的报表,高级日志记录以帮助排除故障的应用或网络及其他功能

2、LB Cluster

四层:lvs,nginx(stream),haproxy(mode tcp)

七层:http:ngxin(http),haproxy(mode httpd),httpd

3、

官网:www.haproxy.org,www.haproxy.com

文档:https://cbonte.github.io/haproxy-dconv/

二、功能

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

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

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

支持基于cookie进行调度

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

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

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

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

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

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

支持http反向代理

支持动态程序的反向代理

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

三、haparoxy组成

1、光盘base源有安装包,安装好后服务名称叫haproxy,systemctl start haproxy打开5000端口

2、程序环境:

主程序:/usr/sbin/haproxy

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

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

3、配置段:

(1)global:全局配置段

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

性能调整相关参数

Debug参数

(2)proxies:代理配置段

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

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

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

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

配置文件 vim /etc/haproxy/haproxy

代理设置,一端面对客户端,一面面对服务器端

4、配置示例

简单的配置示例:

frontend web     发布到外网的应用

bind *:80     请求到本机器的端口

default_backend websrvs 这个请求就会调度到后端的某个名叫websrvs的backend服务器上

backend websrvs

balance roundrobin      轮询算法

server srv1 192.168.0.101:80 check  健康性检查

server srv2 192.168.0.102:80 check  健康性检查

此时已经简单实现调度

当关闭一台设备时,有现象

四、global配置

1、global配置参数:

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

nbproc 要启动的haproxy的进程数量,系统默认单进程,要求使用daemon模式,一般而言,几个cpu就建立几个进程

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

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

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

log

[len ] [max level [min level]]

address: rsyslog服务器地址

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

2、log:

log global

log

[len ] [ []]

length 日志行的长度,默认1024

no log

注意:

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

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

(2) $ModLoad imudp

$UDPServerRun 514

3、log-format:自定义log格式,https://cbonte.github.io/haproxy-dconv/1.9/configuration.html#8.2.4

4、演示打开log方式

vim /etc/rsyslog.cfg

启用514端口

并在此处

已打开进程

日志已经生成

5、日志管理

将特定信息记录在日志中

(1)capture cookie len

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

(2)capture request header len

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

示例:

capture request header X-Forwarded-For len 15

(3)capture response header len

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

示例:

capture response header Content-length len 9

capture response header Location len 15

五、性能调整

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

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

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

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

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

六、配置段

1、代理配置段:

- defaults

- frontend

- backend

- listen

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

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

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

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

6、配置参数:

bind:指定一个或多个前端侦听地址和端口,只能放在frontend和listen

bind [

]: [, ...] [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  ---->对本地的用户root,用套接字提供服务,权限是600

注意:listen只能实现一对一的方式,一对多,多对多还是用frontend和backend,但在一对一的方式中推荐还是用frontend和backend方式,便于修改和拓展

七、调度算法

1、balance:后端服务器组内的服务器调度算法,不能放在frontend,可放在defaults、listen和 backend

balance [ ]

balance url_param [check_post]

2、调度算法:

(1)roundrobin:基于权重轮询,动态算法,支持权重的运行时调整,支持慢启动;每个后端backend中最多支持4095个server

server options: weight #

(2)static-rr:基于权重轮询,静态算法,不支持权重的运行时调整及慢启动;后端主机数量无上限

(3)leastconn:加权最少连接,动态算法,最少连接的后端服务器优先分配接收新连接,相同连接时轮询,推荐在较长会话的场景使用,例如MySQL,LDAP等,不适合http

(4)first:根据服务器在列表中的位置,自上而下进行调度;前面服务器的连接数达到上限,新请求才会分配给下一台服务,不支持权重

(5)source:源地址hash,新连接先按权重分配,后续连接按source分配请求,实现会话绑定

举例:除权取余法说明,对ip做哈希运算并对3进行取模,值只会出现0、1、2,当三台设备权重一样时,就可以将取模值为0的调入rs1,取模为1时调入rs2,取模为2时调入rs3

hash(ip1)%3  0  rs1  1

hash(ip2)%3  1 rs2 1

hash(ip3)%3  2 rs3 1

当权重不一样时,对于取模的值进行权重的累加,计算后按比例分配,取模值为0时调入rs1,取模为1、2 时调入rs2,取模为3、4、5时调入rs3

hash(ip1)%6  0   rs1  1

hash(ip2)%6  1,2  rs2 2

hash(ip3)%6  3,4,5 rs3 3

优点:会话绑定,同一个ip调入同一个rs服务器

缺点:增加rs服务器后一切都需要重新计算;也有可能一个外网ip后面有很多私网ip设备,造成设备分配很粗糙

(6)uri:对URI的左半部分或整个uri做hash计算,并除以服务器总权重取模,以后派发至某挑出的服务器,适用于后端缓存服务器,一般配合varnish缓存服务器

://:@:/;?#

左半部分:/;

整个uri:/;?#

(7)url_param:对用户请求的uri中的部分中的参数的值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个Backend Server

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

(8)hdr():根据主机头调度,对于每个http请求,此处由指定的http首部将会被取出做hash计算; 并由服务器总权重相除以后派发至某挑出的服务器;无有效值的会被轮询调度

根据浏览器类型调度

curl -A,模仿哪种浏览器进行访问

(9)hdr(Cookie),根据cookie调度

(10)rdp-cookie 远程桌面相关

rdp-cookie()

八、哈希算法

1、hash-type:哈希算法

hash-type

method:

map-based:除权取余法,哈希数据结构是静态数组,刚才上述的举例已说明

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

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

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

2、default_backend

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

3、default-server [param*]

为backend中的各server设定默认选项,为后端服务器定义默认值

一致性哈希算法说明:在除权取余法的例子中,如果3台服务器突然故障一台变成2台或者3台服务器不够用需要增加1台,之前该服务器上的文件的缓存位置必定发生改变,以前缓存的图片也失去缓存的作用和意义。如果是服务器故障,由于大量缓存同一时间失效,造成了缓存的雪崩,此时前端缓存已经无法起到承担部分压力的作用,后端服务器将会承受巨大压力,整个系统也很有可能崩溃。该种情况是无法避免,一致性哈希算法就是来解决这种问题的。

一致性哈希还是取余的做法,只不过是对ip进行hash后,再对2^32进行取余,如果有3台服务器,我们将这3台服务器映射到hash环上,当某个缓存服务器的缓存文件被访问时,该文件也是经过了hash后对2^32取余

      被访问的文件经过hash取余运算后,从被缓存对象的位置出发,沿顺时针方向遇到的第一个服务器,将会是该文件将要缓存与服务器,在服务器不变情况下,一个文件必定会被 缓存到固定的服务器上,当下次想要访问这个文件时,再次使用相同的算法即可算出这个图片被缓存在哪个服务器上,图中所示file将被缓存到B上

假如B和C之间也有个file2,file2将会缓存到C上,当B被移除,file2的缓存不变,file1缓存将会移动至C,服务器数量发生改变,并不是所有缓存都失效,而是只有部分会失效,前端仍然能分担整个系统的压力

由于实际情况不可能说三台设备均匀分布在环上,所以引入虚拟节点,虚拟节点越多缓存被均匀分布的概率越大

九、配置

server

[:[port]] [param*]

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

server

[:port] [settings ...]

default-server [settings ...]

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

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

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

[param*]:参数

weight :权重,默认为1

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

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

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

示例:在haproxy中建立sorry server

1、安装httpd或者nginx

在配置文件中更改监听端口,80被haproxy监听,需要更改不被监听的端口

2、更改haproxy配置文件

3、测试

十、健康状态监测

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

注意:httpchk,“smtpchk”, “mysql-check”, “pgsql-check” and “ssl-hello-chk” 用于定义应用层检测方法

addr :检测时使用的IP地址

port :针对此端口进行检测

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

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

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

2、disabled:标记为不可用,加入此项后将不往标记该台的后端设备调度

3、redir :将发往此server的所有GET和HEAD类的请求重定向至指定的URL,用户发请求,发到其它服务器,后面的地址必须是外网ip地址

十一、cookie配置

1、cookie :为当前server指定cookie值,实现基于cookie的会话黏性

cookie [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain ]* [ maxidle ] [ maxlife ]

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

rewrite:重写

insert:插入

prefix:前缀

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

2、基于cookie的session sticky的实现

backend websrvs

cookie WEBSRV insert nocache

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

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

十二、统计接口启用相关的参数

1、stats enable

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

之后访问http://ip/haproxy?stats,即出现

2、stats hide-version 隐藏版本

3、stats refresh

设定自动刷新时间间隔

4、stats uri

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

5、stats realm

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

6、stats auth :

认证时的账号和密码,可使用多次,默认:no authentication

7、stats admin { if | unless }

启用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

drain:排干,将服务器上的用户踢掉,之后逐渐下线

十三、工作模式

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

2、mode { tcp|http|health }

定义haproxy的工作模式

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

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

health:工作为健康状态检查的响应模式,当连接请求到达时回应“OK”后即断开连接,较少使用

3、示例

listen ssh

bind :22022

balance leastconn

mode tcp

server sshsrv1 172.16.0.6:22 check

server sshsrv2 172.16.0.7:22 check

ssh IP -p 22022,即可ssh登录

十四、健康状态检测,应用层检查

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

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

option httpchk

option httpchk

option httpchk

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

http-check expect [!]

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

十五、forwardfor配置

1、option forwardfor [ except ] [ header ] [ if-none ]

在由haproxy发往后端主机的请求报文中添加“X-Forwarded-For”首部,其值为前端客户端的地址;用于向后端主发送真实的客户端IP

在后端RS服务器上/etc/httpd/conf/httpd.conf中,添加X-Forwarded-For

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

如haproxy自身所在网络

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

示例:在haproxy主机上

在RS服务器上改

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

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

compression algo ...:启用http协议的压缩机制,指明压缩算法gzip, deflate

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

十六、错误页配置

1、errorfile 自定义错误页

:HTTP status code.

支持200, 400, 403, 408, 500, 502, 503, 504.

:错误页文件路径

2、示例:

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

3、errorloc

相当于errorloc302 ,利用302重定向至指URL

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

十七、修改报文首部

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

reqadd [{if | unless} ]

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

rspadd [{if | unless} ]

示例:rspadd X-Via:\ HAPorxy

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

reqdel [{if | unless} ]

reqidel [{if | unless} ] 不分大小写

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

rspdel [{if | unless} ]

rspidel [{if | unless} ] 不分大小写

示例: rspidel server.*

十八、连接超时

1、timeout client

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

2、timeout server

后端服务器最长空闲连接超时时长

3、timeout http-keep-alive

持久连接的持久时长

4、timeout http-request

一次完整的HTTP请求的最大等待时长

5、timeout connect

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

6、timeout client-fin

客户端半连接的空闲时长

7、timeout server-fin

后端服务器半连接的空闲时长

十九、ACL

1、acl:访问控制列表(ACL)的使用提供了一个灵活的解决方案来执行内容交换,并且通常基于从请求中提取的内容、响应或任何环境状态进行决策

2、acl [flags] [operator] [] ...

acl acl名称 参数 [选项] 匹配 [值]

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

: 比较的标准和条件

(1)的类型:

- boolean

- integer or integer range

- IP address / network

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

- regular expression

- hex block

(2)

-i 不区分大小写

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

-n 不做DNS解析

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

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

(3)[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进行匹配

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

- 与:隐式(默认)使用

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

- 否定:使用“!“ 表示

示例:if invalid_src invalid_port 与关系

if invalid_src || invalid_port 或

if ! invalid_src 非

(5) :各种条件

dst 目标IP

dst_port 目标PORT

src 源IP

src_port 源PORT

示例:acl invalid_src src 172.16.100.200

演示1

演示2

结果

(6)base : string

返回第一个主机头和请求的路径部分的连接,该请求从第一个斜杠开始,并在问号之前结束,对虚拟主机有用

://:@:/;?#

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

(7)path : string,官方建议最好用path,比url好用

提取请求的URL路径,该路径从第一个斜杠开始,并在问号之前结束(无主机部分) ://:@:/;?#

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

示例:

path_beg /images/

path_end .jpg .jpeg .png .gif

path_reg ^/images.*\.jpeg$

path_sub image

path_dir jpegs

path_dom magedu

/images/jpegs/20180123/logo.jpg

(8)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

(9)req.hdr([[,]]) : string

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

hdr([[,]]) : exact string match

hdr_beg([[,]]) : prefix match

hdr_dir([[,]]) : subdir match

hdr_dom([[,]]) : domain match

hdr_end([[,]]) : suffix match

hdr_len([[,]]) : length match

hdr_reg([[,]]) : regex match

hdr_sub([[,]]) : substring match

示例:

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

block if bad_agent

可引申出:

(10)status : integer

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

(11)预定义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_HEAD

method HEAD

match HTTP GET 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

3、配置

(1)use_backend [{if | unless} ]

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

(2)block { if | unless }

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

示例:

acl invalid_src src 172.16.200.2

block if invalid_src

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

(3)http-request { allow | deny |add-header |set-header } [ { if | unless } ]

对7层请求的访问控制

(4)tcp-request connection {accept|reject} [{if | unless} ]

根据第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

二十、基于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

二十一、支持https协议

1、配置HAProxy支持https协议:

2、支持ssl会话;

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

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

cat demo.crt demo.key > demo.pem

3、把80端口的请求重向定443

bind *:80

redirect scheme https if !{ ssl_fc }

4、向后端传递用户请求的协议和端口(frontend或backend),加入此项意义在于抓取log时便于查看

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

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

实现过程:该模式需要在http模式下进行

1、cd /etc/pki/tls/certs/

make a.pem

注意:如果按照以往方法是生成a.key和a.crt,将它们用cat a.key a.crt > a.pem就可以合到一起,a.pem里面包含证书和私钥

cp a.pem /etc/haproxy

2、更改haproxy配置文件,此时curl -k http和https都能通,但curl -k http时没有实现跳转

3、继续改配置文件,重启后完成