前言

        HAProxy是法国人Willy Tarreau开发的一款可应对客户端10000以上的同时连接的高性能的TCP和

HTTP负载均衡器。由于其丰富强大的功能在国内备受推崇,是目前主流的负载均衡器。本文介绍其功能特性并结合配置实例演示,如有错误敬请赐教。

Haproxy主要工作位置:

Haproxy 使用攻略_第1张图片

1. 支持http反向代理

2. 支持动态程序的反向代理

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


Haproxy 程序组成:

程序环境:

    安装:yum install haproxy -y

    主程序: /usr/sbin/haproxy

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

    主配置文件主要结构:1. global 全局配置段 2. proxies代理配置段

索引


1. global:全局配置段配置

        1.1 全局日志配置

        1.2 性能调整常见参数

2.proxies:代理配置段结构

3.实现简单proxy配置实验

        3.1 方法1

        3.2 方法2

4.代理配置段常见配置参数

        4.1 Balance调度算法相关

        4.2 server:定义后端主机相关选项

        4.3 实现图形化配置页

        4.4 default默认配置中定义的内容

        4.5 forwardfor后端记录真实请求配置

        4.6 自定义错误页面

        4.7 自定义修改报文首部

        4.8 自定义连接超时相关配置

5. ACL灵活转发详解

        5.1 acl语法

        5.2 匹配条件进阶

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

        5.4 系统预定义ACL(部分)

        5.5 配置block拒绝访问

        5.6 指定backend组

        5.7 http 7层访问控制

        5.8 tcp 4层连接控制

        5.9 配置HAProxy支持https协议

6. 附实现动静分离实验示例



1. global:全局配置段


1.1 log:全局日志配置

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

(1) 系统默认:log         127.0.0.1 local2

发往远端可添加:log          远端IP  local2

(2) 修改本机日志配置文件:

vim  /etc/rsyslog.conf

$ModLoad imudp          #取消注释

$UDPServerRun 514    #取消注释

local2.*                                                /var/log/haproxy.log  #新增

(3) 远端日志配置(配合前端log配置)

vim  /etc/rsyslog.conf

local2.*                                                /var/log/haproxy.log  #新增


1.2 性能调整(依据生产环境适当调整):

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

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

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

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

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

2.proxies:代理配置段结构


    (1). defaults:为frontend, backend, listen提供默认配置

    (2). fronted:前端,指定接收客户端连接侦听套接字设置

    (3). backend:后端,指定将连接请求转发至后端服务器的相关设置

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

3.实现简单proxy配置:


实验拓扑:

3.1  方法一:

配置 /etc/haproxy/haproxy.cfg :

将frontend段、backend段注释,新建如下配置

frontend http *:80                #均衡器端采用http 协议,监听80端口

       default_backend websrvs   #引用后端自定义服务器组名websrvs

backend websrvs                   #设定默认后端,自定义名字为websrvs

       balance roundrobin        #轮询方式为加权轮询

       server web1 192.168.43.61:80 check    #设定后端服务器IP ,并引入健康检查

       server web2 192.168.43.63:80 check    #设定后端服务器IP ,并引入健康检查


service haproxy start

在浏览器访问http://172.18.43.62 刷新即可看到轮询效果

Haproxy 使用攻略_第2张图片

3.2 方法2:

上面两段配置也可以配置在一段实现相同功能,配置如下:

listen http

       bind :80

       balance roundrobin

       server web1 192.168.43.61:80 check

       server web2 192.168.43.63:80 check

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

语法: bind [

]: [, ...] [param*]

示例:

    listen http_proxy

    bind :80,:443

    bind 10.0.0.1:10080,10.0.0.1:10443

4.代理配置段常见配置参数


4.1Balance相关

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

语法: balance [ ]

           balance url_param [check_post]

调度算法:

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

    server options: weight #

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

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

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

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

例:hdr(host)     hdr(Cookie)

⑤ rdp-cookie 远程桌面相关

hash类算法:

需配合参数:hash-type

method:

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

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

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

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

://:@:/;?#

左半部分: /;

整个uri: /;?#

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


4.2 server:定义后端主机相关选项

语法:

server

[:[port]] [param*]

    :服务器在haproxy上的自定义名称;出现在日志及警告信息

    

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

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

[param*]:server后可加的参数

weight :权重,默认为1

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

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

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

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

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

        addr :检测时使用的IP地址(检测的不一定是vip)

        port :针对此端口进行检测

        inter :连续两次检测之间的时间间隔,默认单位为毫秒,默认为2000ms

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

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

disabled:标记为不可用

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

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

基于cookie的session sticky的实现:

frontend http

bind 172.18.43.62:80              

       default_backend websrvs  

backend websrvs                  

       balance roundrobin

cookie SRV insert nocache

#自定义会话添加cookie信息SRV,insert:插入 nocache:不缓存增加保密性    

       server web1 192.168.43.61:80 check   weight 2 cookie srv1 #自定义该server添加cookie信息为srv1

       server web2 192.168.43.63:80 check   maxconn 5000 cookie srv2 #自定义该server添加cookie信息为srv2

server sorroyserver 192.168.43.62:80 backup

4.3 实现图形化配置页面

stats enable 添加这条参数后会在web页面启用统计页;参数可放置位置。

我们在frontend段添加stats enable ,重启haproxy。浏览器访问172.18.43.62/haproxy?stats即可

Haproxy 使用攻略_第3张图片

相关参数:

① stats refresh 设定自动刷新时间间隔

若服务器出现故障,默认手动刷新才能才能看到状态的变化,可设置自动刷新

    例:添加stats refresh 2s

② stats uri 自定义stats page uri

默认为/haproxy?stats 可自定义uri

    例:stats uri  /hastas

重启后访问http://172.18.43.62/hastas即可

③ stats hide-version

如上图所示界面会显示haproxy版本信息,若想隐藏版本加上此参数即可

④ stats auth : 认证时的账号和密码,可使用多次。如多个用户定义多行即可,例:

    stats auth ha1:centos1

    stats auth ha2:centos2

⑤ stats realm 认证时浏览器弹出对话框的提示信息

    例:stats realm "haproxy info"

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

    例:stats  admin  if TRUE

将stats分离出单独语句块,采用内网的6666端口提高访问安全性示例:

listen admin

       bind 192.168.43.62:6666

       stats enable

       stats uri /status

       stats realm "haproxy info"

       stats auth ha1:centos

       stats hide-version

       stats refresh 5s

       stats admin if TRUE

从内网访问界面:

Haproxy 使用攻略_第4张图片


4.4 default中定义的内容

可以在frontend、backend、listen中分别进行定义,如没有指定将默认default中设置,如:

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

    mode { tcp|http|health } 定义haproxy的工作模式(默认http)

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

        http:仅当代理协议为http时使用,centos实际默认模式

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

TCP模式的健康状态检测示例:


listen ssh

        bind :22022

        balance leastconn

        mode tcp

        server sshsrv1 172.16.100.6:22 check

        server sshsrv2 172.16.100.7:22 check


4.5 forwardfor配置

语法 :option forwardfor [ except ] [ header ] [ if-none ]

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

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

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

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

默认defaults中有一条配置option forwardfor       except 127.0.0.0/8

若想后端日志记录真实请求客户端IP,需更改后端两台服务器配置文件:

vim /etc/httpd/conf/httpd.conf

LogFormat "%{x-forwarded-for}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" haformat

#添加日志格式

CustomLog logs/access_log haformat #修改记录日志

重载客户端httpd服务,浏览器刷新请求。在客户端观看日志即可看到真实请求服务器

tail -f /var/log/httpd/access_log


4.6 自定义错误页面

① errorfile 自定义错误页

        : HTTP status code.  支持200, 400, 403, 408, 500, 502, 503, 504.

        :错误页文件路径

    例:errorfile 400 /etc/haproxy/errorfiles/400badreq.http

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

    例:errorloc 503 http://www.magedu.com/error_pages/503.html

4.7修改报文首部

① reqadd [{if | unless} ]    在请求报文尾部添加指定首部(用于web端区分从哪个调度器发来请求)

例:在frontend中添加  reqadd  X-via:\  haproxy1

后端修改httpd.conf中logformat添加%{X-via}i

再次访问日志就会看到是通过哪个调度器调度到本机

② rspadd [{if | unless} ]  在响应报文尾部添加指定首部 (用于haproxy之前的调度器查看用于排错)

示例: rspadd X-Via:\ HAPorxy

③ reqdel [{if | unless} ]

reqidel [{if | unless} ] (ignore case) 不分大小写

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

④ rspdel [{if | unless} ]

rspidel [{if | unless} ] (ignore case) 不分大小写

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

示例: rspidel Server.*  用于隐藏web服务器版本信息

rspadd Server:\ Apache 15.1 结合上例可伪造server信息

4.8 定义连接超时

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

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

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

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

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

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

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

5. ACL灵活转发详解


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

5.1 语法

acl [flags] [operator] []...

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

: 比较的标准和条件

        dst 目标IP

        dst_port 目标PORT

        src 源IP

        src_port 源PORT

        示例: acl invalid_src src 172.16.100.200

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

的类型:

    - boolean

    - integer or integer range

    - IP address / network

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

    - regular expression

    - hex block

5.2 匹配条件进阶:

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

(2)path : string

提取请求的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

例:acl adminpath path_beg  -i  /admin

acl p_w_picpathfile  path_end  .jpg  .png   .bmp

(3)url : string

提取请求中的URL。 一个典型的应用是具有预取能力的缓存,以及需要从数据库聚合多个信息并将它们保存在缓存中的网页门户入口

    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

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

(5)status : integer

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

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

    - 与:隐式(默认)使用

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

    - 否定:使用“!“ 表示

    同一个组名可定义多次

示例: if invalid_src invalid_port 与关系

    if invalid_src || invalid_port 或

    if ! invalid_src 非

5.4 预定义ACL(部分)


ACL名称


等价于


说明

TRUE

always_true

总是匹配

FALSE

always_false

从不匹配

HTTP_1.1

req_ver 1.1

匹配HTTP协议1.1

HTTP

req_proto_http

匹配HTTP协议


LOCALHOST


src 127.0.0.1/8


匹配从localhost来的连接


METH_CONNECT


method CONNECT


匹配HTTP CONNECT方法


5.5 配置block拒绝访问

语法:block { if | unless }   阻止7层请求if/unless一个条件匹配

例1:

frontend http

acl deny_src src 172.18.0.108

#自定义源地址为172.18.0.108的acl组deny_src

acl deny_port dst_port 80:100

#自定义目标端口为80到100的acl组deny_port

block if deny_src || deny_port

#如果属于deny_src组或deny_port组则拒绝访问

block unless deny_src #如果不属于acl组deny_src则拒绝访问

例2(阻止curl访问):

acl bad_curl hdr_sub(User-Agent) -i curl

block if bad_curl

5.6 指定backend组

语法:use_backend [{if | unless} ]

当if/unless一个基于ACL的条件匹配时切换指定backend(可实现动静分离)

例1:

acl p_w_picpathfile path_end .jpg .png .bmp

acl appfile path_end .php

use_backend websrvs1 if p_w_picpathfile

use_backend websrvs2 if appfile

例2:

Haproxy 使用攻略_第5张图片

例3:

acl webhost hdr(host) web.51cto.com

acl apphost hdr(host) app.51cto.com

use_backend websrvs if webhost

use_backend appsrvs if apphost

5.7 http 7层访问控制

语法:http-request { allow | deny |add-header |set-header } [ { if | unless } ]

对7层请求的访问控制

5.8 tcp4层连接控制

语法:tcp-request connection {accept|reject} [{if | unless} ]

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

例:

listen ssh

bind :22022

balance leastconn

acl invalid_src src 172.16.200.2

tcp-request connection reject if invalid_src

mode tcp

server sshsrv1 172.16.100.6:22 check

server sshsrv2 172.16.100.7:22 check backup

5.9 配置HAProxy支持https协议:

① 支持ssl会话;

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

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

为实验方便自签证书方法:

在etc/pki/tls/certs/目录下执行make命令可获得同时包含证书和所有私钥的证书

cd /etc/pki/tls/certs/

make /etc/haproxy/haproxy.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 }

例:

Haproxy 使用攻略_第6张图片

测试:

Haproxy 使用攻略_第7张图片

向后端传递用户请求:

Haproxy 使用攻略_第8张图片

修改后端httpd.conf中日志格式即可

004ef390aaebed03cbd503241ae56f6f.png

6. 附基于ACL的动静分离示例

frontend web *:80

       acl url_static path_beg -i /static /p_w_picpaths /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 stcsrv1 172.16.100.6:80 check

backend appsrvs

       balance roundrobin

       server app1 172.16.100.7:80 check

       server app1 172.16.100.7:8080 check

listen stats

      bind :9091

      stats enable

      stats auth admin:admin

      stats admin if TRUE