Haproxy算法精简化理解及企业级高功能实战

文章目录

      • [4. Haproxy的算法](#4. Haproxy的算法)
        • [4.1 静态算法](#4.1 静态算法)
          • [4.1.1 static-rr:基于权重的轮询调度](#4.1.1 static-rr:基于权重的轮询调度)
            • [1. 示例:](#1. 示例:)
          • [4.1.2 first](#4.1.2 first)
            • [1. 示例](#1. 示例)
            • [2. 测试效果:](#2. 测试效果:)
        • [4.2 动态算法](#4.2 动态算法)
          • [4.2.1 roundrobin](#4.2.1 roundrobin)
            • [1. 示例](#1. 示例)
            • [2. 动态调整权重](#2. 动态调整权重)
          • [4.2.2 leastconn](#4.2.2 leastconn)
            • [1. 示例](#1. 示例)
        • [4.3 其他算法](#4.3 其他算法)
          • [4.3.1 source](#4.3.1 source)
            • [1. 示例](#1. 示例)
            • [2. 测试](#2. 测试)
          • [4.3.2 map-base 取模法](#4.3.2 map-base 取模法)
            • [1. 取模法配置示例](#1. 取模法配置示例)
          • [4.3.3 一致性hash](#4.3.3 一致性hash)
            • [1. 算法](#1. 算法)
            • [2. hash环偏斜问题](#2. hash环偏斜问题)
            • [3. hash对象](#3. hash对象)
            • [4. 一致性hash示意图](#4. 一致性hash示意图)
            • [5. 一致性hash配置示例](#5. 一致性hash配置示例)
          • [4.3.4 uri](#4.3.4 uri)
            • [1. uri 取模法配置示例](#1. uri 取模法配置示例)
            • [2. uri 一致性hash配置示例](#2. uri 一致性hash配置示例)
            • [3. 访问测试](#3. 访问测试)
          • [4.3.5 url_param](#4.3.5 url_param)
            • [1. url_param取模法配置示例](#1. url_param取模法配置示例)
            • [2. url_param一致性hash配置示例](#2. url_param一致性hash配置示例)
            • [3. 测试访问](#3. 测试访问)
          • [4.3.6 hdr](#4.3.6 hdr)
            • [1. hdr取模法配置示例](#1. hdr取模法配置示例)
            • [2. 一致性hash配置示例](#2. 一致性hash配置示例)
            • [3. 测试访问](#3. 测试访问)
        • [4.4 算法总结](#4.4 算法总结)
        • [4.5 各算法使用场景](#4.5 各算法使用场景)
        • [4.6 Haproxy算法大白话解析](#4.6 Haproxy算法大白话解析)
          • [4.6.1 first](#4.6.1 first)
          • [4.6.2 static-rr](#4.6.2 static-rr)
          • [4.6.3 roundrobin](#4.6.3 roundrobin)
          • [4.6.4 random](#4.6.4 random)
          • [4.6.5 leastconn](#4.6.5 leastconn)
          • [4.6.6 source](#4.6.6 source)
          • [4.6.7 uri](#4.6.7 uri)
          • [4.6.8 url_param](#4.6.8 url_param)
          • [4.6.9 hdr](#4.6.9 hdr)
        • [4.7 算法选择速查表](#4.7 算法选择速查表)
      • 5.高级功能及配置
        • [5.1 基于cookie的会话保持](#5.1 基于cookie的会话保持)
          • [5.1.1 配置选项](#5.1.1 配置选项)
          • [5.1.2 配置示例](#5.1.2 配置示例)
          • [5.1.3 验证cookie信息](#5.1.3 验证cookie信息)
            • [1. 通过命令行验证](#1. 通过命令行验证)
        • [5.2 Haproxy状态页--监控实现](#5.2 Haproxy状态页--监控实现)
          • [5.2.1 状态页配置项](#5.2.1 状态页配置项)
          • [5.2.2 启用状态页](#5.2.2 启用状态页)
          • [5.2.3 登录状态页](#5.2.3 登录状态页)
          • [5.2.4 backend server信息](#5.2.4 backend server信息)
            • [1. Session Rate & Sessions](#1. Session Rate & Sessions)
            • [2. Errors & Warnings](#2. Errors & Warnings)
            • [3. Bytes & Denied](#3. Bytes & Denied)
            • [4. Server 信息](#4. Server 信息)
        • [5.3 真实访问主机IP透传](#5.3 真实访问主机IP透传)
          • [5.3.1 七层IP透传](#5.3.1 七层IP透传)
            • [1. 未开启透传的七层代理](#1. 未开启透传的七层代理)
            • [2. 开启透传的七层代理](#2. 开启透传的七层代理)
          • [5.3.2 四层IP透传](#5.3.2 四层IP透传)
            • [1. 测试](#1. 测试)
            • [2. 解决步骤](#2. 解决步骤)
            • [3. 四层IP透传--Nginx完整配置详情](#3. 四层IP透传--Nginx完整配置详情)
            • [4. web服务器日志格式配置](#4. web服务器日志格式配置)
            • [5. 使用Apache将此实验进行完全完成](#5. 使用Apache将此实验进行完全完成)
        • [5.4 ACL--访问控制列表](#5.4 ACL--访问控制列表)
          • [5.4.0 ACL测试参数配置举例](#5.4.0 ACL测试参数配置举例)
            • [1. `acl test hdr_dom(host) www.ceshi.org`域名](#1. acl test hdr_dom(host) www.ceshi.org域名)
            • [2. `acl test hdr_end(host) .com`后缀](#2. acl test hdr_end(host) .com后缀)
            • [3. `acl test hdr_beg(host) bbs.`前缀](#3. acl test hdr_beg(host) bbs.前缀)
            • [4. `acl test base_sub -m sub org`](#4. acl test base_sub -m sub org)
            • [5. `acl test base_sub -m sub du`](#5. acl test base_sub -m sub du)
            • [6. `acl test path_sub -m sub ceshi`](#6. acl test path_sub -m sub ceshi)
          • [5.4.1 ACL配置选项](#5.4.1 ACL配置选项)
            • [1. ACL-Name 名称](#1. ACL-Name 名称)
            • [2. ACL-criterion 匹配规范](#2. ACL-criterion 匹配规范)
            • [3. ACL-flags 匹配模式](#3. ACL-flags 匹配模式)
            • [4. ACL-operator 具体操作符](#4. ACL-operator 具体操作符)
            • [5. ACL-value 操作对象](#5. ACL-value 操作对象)
          • [5.4.2 多个ACL的组合调用方式](#5.4.2 多个ACL的组合调用方式)
          • [5.4.3 基于域名匹配访问--ACL示例](#5.4.3 基于域名匹配访问--ACL示例)
          • [5.4.4 基于源IP或子网调度访问--ACL示例](#5.4.4 基于源IP或子网调度访问--ACL示例)
          • [5.4.5 基于源地址的访问控制--ACL示例](#5.4.5 基于源地址的访问控制--ACL示例)
          • [5.4.6 匹配浏览器类型--ACL示例](#5.4.6 匹配浏览器类型--ACL示例)
          • [5.4.7 基于文件后缀名实现动静分离--ACL示例](#5.4.7 基于文件后缀名实现动静分离--ACL示例)
          • [5.4.8 匹配访问路径实现动静分离--ACL示例](#5.4.8 匹配访问路径实现动静分离--ACL示例)
        • [5.5 自定义Haproxy错误界面](#5.5 自定义Haproxy错误界面)
          • [5.5.1 基于自定义的错误页面文件](#5.5.1 基于自定义的错误页面文件)
          • [5.5.2 基于http重定向错误页面](#5.5.2 基于http重定向错误页面)
        • [5.6 Haproxy四层负载--数据库示例](#5.6 Haproxy四层负载--数据库示例)
        • [5.7 Haproxy https实现](#5.7 Haproxy https实现)
          • [5.7.1 证书制作](#5.7.1 证书制作)
          • [5.7.2 https配置示例](#5.7.2 https配置示例)

4. Haproxy的算法

HAProxy通过固定参数 balance 指明对后端服务器的调度算法

balance参数可以配置在listen或backend选项中。

  • HAProxy的调度算法分为:
    • 静态调度算法
    • 动态调度算法
4.1 静态算法

按照事先定义好的规则轮询公平调度,不关心后端服务器的当前负载、连接数和响应速度等;

且无法实时修改权重(只能为0和1,不支持其它值),只能靠重启HAProxy生效。

4.1.1 static-rr:基于权重的轮询调度
  • 不支持运行时利用socat进行权重的动态调整(只支持0和1,不支持其它值)
  • 不支持端服务器慢启动
  • 其后端主机数量没有限制,相当于LVS中的 wrr

慢启动是指在服务器刚刚启动上不会把他所应该承担的访问压力全部给它,而是先给一部分,当没问题后在给一部分

1. 示例:
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance static-rr
    server webserver1 192.168.0.101:80 weight 2 check inter 3s fall 3 rise 5
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
4.1.2 first
  • 根据服务器在列表中的位置,自上而下进行调度
  • 其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务
  • 其会忽略服务器的权重设置
  • 不支持用socat进行动态修改权重,可以设置0和1,可以设置其它值但无效
1. 示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance first                 
    server webserver1 192.168.0.101:80 maxconn 3 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 check inter 3s fall 3 rise 5


...上面内容省略...
2. 测试效果:
bash 复制代码
 #在两台主机上分别执行此循环,可以观察是否102被调度到
 while true;do curl  172.25.254.100 ; sleep 0.1;done
4.2 动态算法
  • 基于后端服务器状态进行调度适当调整,
  • 新请求将优先调度至当前负载较低的服务器
  • 权重可以在haproxy运行时动态调整无需重启
4.2.1 roundrobin
  • 基于权重的轮询动态调度算法,

  • 支持权重的运行时调整,不同于lvs中的rr轮训模式,

  • HAProxy中的roundrobin支持慢启动(新加的服务器会逐渐增加转发数),

  • 其每个后端backend中最多支持4095个real server,

  • 支持对real server权重动态调整,

  • roundrobin为默认调度算法,此算法使用广泛

1. 示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance roundrobin                 
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5


...上面内容省略...
2. 动态调整权重
bash 复制代码
[root@haproxy ~]# echo "set  weight webserver_80/webserver1 2" | socat stdio  /var/lib/haproxy/haproxy.sock
4.2.2 leastconn
  • leastconn加权的最少连接的动态
  • 支持权重的运行时调整和慢启动,即:根据当前连接最少的后端服务器而非权重进行优先调度(新客户端连接)
  • 比较适合长连接的场景使用,比如:MySQL等场景。
1. 示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance leastconn
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
4.3 其他算法

其它算法即可作为静态算法,又可以通过选项成为动态算法

4.3.1 source

源地址hash,基于用户源地址hash并将请求转发到后端服务器,后续同一个源地址请求将被转发至同一个后端web服务器。

此方式当后端服务器数据量发生变化时,会导致很多用户的请求转发至新的后端服务器,默认为静态方式,

但是可以通过hash-type支持的选项更改这个算法

一般是在不插入Cookie的TCP模式下使用,也可给拒绝会话cookie的客户提供最好的会话粘性,

适用于session会话保持但不支持cookie和缓存的场景源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法和一致性hash

1. 示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance source
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
2. 测试
bash 复制代码
[root@node10 ~]# for N in  {1..6}; do curl 172.25.254.100; done
RS1 server - 192.168.0.101
RS1 server - 192.168.0.101
RS1 server - 192.168.0.101
RS1 server - 192.168.0.101
RS1 server - 192.168.0.101
RS1 server - 192.168.0.101

如果访问客户端时一个家庭,那么所有的家庭的访问流量都会被定向到一台服务器,这时source算法的缺陷

4.3.2 map-base 取模法

对source地址进行hash计算,再基于服务器总权重的取模,最终结果决定将此请求转发至对应的后端服务器。

此方法是静态的,即不支持在线调整权重,不支持慢启动,可实现对后端服务器均衡调度

缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因总权重发生变化而导致调度结果整体改变

hash-type 指定的默值为此算法

所谓取模运算,就是计算两个数相除之后的余数,10%7=3, 7%4=3

map-based算法:基于权重取模,hash(source_ip)%所有后端服务器相加的总权重
比如当源hash值时1111,1112,1113,三台服务器a b c的权重均为1,

即abc的调度标签分别会被设定为 0 1 2(1111%3=1,1112%3=2,1113%3=0)

1111 ----- > nodeb

1112 ------> nodec

1113 ------> nodea

如果a下线后,权重数量发生变化

1111%2=1,1112%2=0,1113%2=1

1112和1113被调度到的主机都发生变化,这样会导致会话丢失

1. 取模法配置示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance source
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...


#不支持动态调整权重值
[root@haproxy ~]# echo "set weight webserver_80/webserver1 2" | socat stdio /var/lib/haproxy/haproxy.sock
Backend is using a static LB algorithm and only accepts weights '0%' and '100%'.

#只能动态上线和下线
[root@haproxy ~]# echo "set weight webserver_80/webserver1 0" | socat stdio /var/lib/haproxy/haproxy.sock

[root@haproxy ~]# echo "get  weight webserver_80/webserver1" | socat stdio /var/lib/haproxy/haproxy.sock
0 (initial 1)
4.3.3 一致性hash

一致性哈希,当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动hash(o)mod n

该hash算法是动态的,支持使用 socat等工具进行在线权重调整,支持慢启动

1. 算法
bash 复制代码
1、后端服务器哈希环点keyA=hash(后端服务器虚拟ip)%(2^32)
2、客户机哈希环点key1=hash(client_ip)%(2^32) 		得到的值在[0---4294967295]之间,
3、将keyA和key1都放在hash环上,将用户请求调度到离key1最近的keyA对应的后端服务器
2. hash环偏斜问题
bash 复制代码
增加虚拟服务器IP数量,比如:一个后端服务器根据权重为1生成1000个虚拟IP,再hash。而后端服务器权
重为2则生成2000的虚拟IP,再bash,最终在hash环上生成3000个节点,从而解决hash环偏斜问题
3. hash对象
  • Hash对象到后端服务器的映射关系:
4. 一致性hash示意图
  • 后端服务器在线与离线的调度方式
5. 一致性hash配置示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance source
    hash-type consistent
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
4.3.4 uri

基于对用户请求的URI的左半部分或整个uri做hash,再将hash结果对总权重进行取模后

根据最终结果将请求转发到后端指定服务器

适用于后端是缓存服务器场景

默认是静态算法,也可以通过hash-type指定map-based和consistent,来定义使用取模法还是一致性hash

注意:此算法基于应用层,所以只支持 mode http ,不支持 mode tcp

bash 复制代码
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分:/<path>;<params>
整个uri:/<path>;<params>?<query>#<frag>
1. uri 取模法配置示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance uri
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
2. uri 一致性hash配置示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance uri
    hash-type consistent
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
3. 访问测试
  • 访问不同的uri,确认可以将用户同样的请求转发至相同的服务器
bash 复制代码
root@rs1 ~]# echo RS1  192.168.0.101 index1 > /var/www/html/index1.html
[root@rs1 ~]# echo RS1  192.168.0.101 index2 > /var/www/html/index2.html
[root@rs1 ~]# echo RS1  192.168.0.101 index3 > /var/www/html/index3.html
[root@rs2 ~]# echo RS1  192.168.0.102 index1 > /var/www/html/index1.html
[root@rs2 ~]# echo RS1  192.168.0.102 index2 > /var/www/html/index2.html
[root@rs2 ~]# echo RS1  192.168.0.102 index3 > /var/www/html/index3.html

[root@node10 ~]# curl  172.25.254.100/index.html
RS2 server - 192.168.0.102
[root@node10 ~]# curl  172.25.254.100/index1.html
RS1 192.168.0.101 index1
[root@node10 ~]# curl  172.25.254.100/index2.html
RS1 192.168.0.102 index2
[root@node10 ~]# curl  172.25.254.100/index3.html
RS1 192.168.0.101 index3
4.3.5 url_param

url_param对用户请求的url中的 params 部分中的一个参数key对应的value值作hash计算,并由服务器总权重相除以后派发至某挑出的服务器,后端搜索同一个数据会被调度到同一个服务器,多用与电商

通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server

如果无没key,将按roundrobin算法

bash 复制代码
#假设:
url = http://www.timinglee.com/foo/bar/index.php?key=value

#则:
host = "www.timinglee.com"
url_param = "key=value"
1. url_param取模法配置示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance url_param name,userid 		#支持对多个url_param hash
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
 
2. url_param一致性hash配置示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance url_param name,userid 		#支持对多个url_param hash
    hash-type consistent
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
3. 测试访问
bash 复制代码
[root@node10 ~]# curl  172.25.254.100/index3.html?userid=111
RS1 192.168.0.101 index3
[root@node10 ~]# curl  172.25.254.100/index3.html?userid=222
RS1 192.168.0.101 index3
[root@node10 ~]# curl  172.25.254.100/index3.html?userid=333
RS1 192.168.0.102 index3
[root@node10 ~]# curl  172.25.254.100/index3.html?userid=444
RS1 192.168.0.101 index3
4.3.6 hdr

针对用户每个http头部(header)请求中的指定信息做hash,

此处由 name 指定的http首部将会被取出并做hash计算,

然后由服务器总权重取模以后派发至某挑出的服务器,如果无有效值,则会使用默认的轮询调度。

1. hdr取模法配置示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance hdr(User-Agent)
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
2. 一致性hash配置示例
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...

listen webserver_80
    bind 172.25.254.100:80
    mode http
    balance hdr(User-Agent)
    hash-type consistent
    server webserver1 192.168.0.101:80 weight 1 check inter 3s fall 3 rise 5 
    server webserver2 192.168.0.102:80 weight 1 check inter 3s fall 3 rise 5

...上面内容省略...
3. 测试访问
bash 复制代码
[root@node10 ~]# curl  -v 172.25.254.100
[root@node10 ~]# curl  -vA "firefox" 172.25.254.100
[root@node10 ~]# curl  -vA "sougou" 172.25.254.100
4.4 算法总结
bash 复制代码
#静态
static-rr--------->tcp/http  
first------------->tcp/http  
#动态
roundrobin-------->tcp/http 
leastconn--------->tcp/http 
random------------>tcp/http

#以下静态和动态取决于hash_type是否consistent
source------------>tcp/http
Uri--------------->http
url_param--------->http     
hdr--------------->http
4.5 各算法使用场景
bash 复制代码
first 			#使用较少
static-rr		#做了session共享的web集群
roundrobin
random
leastconn		#数据库
source
 
#基于客户端公网IP的会话保持
Uri--------------->http		#缓存服务器,CDN服务商,蓝汛、百度、阿里云、腾讯
url_param--------->http		#可以实现session保持
hdr							#基于客户端请求报文头部做下一步处理
4.6 Haproxy算法大白话解析
4.6.1 first

官方 :按服务器声明顺序选择第一个可用服务器
大白话 :永远优先用名单里的第一个,除非它超过负载
配置

bash 复制代码
backend static_pool
    balance first
    server rs1 172.25.254.10:80 check
    server rs2 172.25.254.20:80 check

工作逻辑

所有请求都发给 rs1 (172.25.254.10) → 仅当rs1故障时切换至rs2


4.6.2 static-rr

官方 :静态加权轮询,运行时不可动态调整权重
大白话 :固定权重的轮流值班表
配置

bash 复制代码
backend weighted_app
    balance static-rr
    server rs1 172.25.254.10:80 weight 3  # 处理3/4请求
    server rs2 172.25.254.20:80 weight 1  # 处理1/4请求

工作逻辑

请求序列:rs1 → rs1 → rs1 → rs2 → rs1 → rs1 → rs1 → rs2...


4.6.3 roundrobin

官方 :动态加权轮询(默认算法),支持运行时调整权重
大白话 :智能版轮流值班,可随时调整工作量
配置

bash 复制代码
backend dynamic_pool
    balance roundrobin
    server rs1 172.25.254.10:80 weight 100
    server rs2 172.25.254.20:80 weight 50

工作逻辑

请求按 2:1 比例分配(100:50)→ rs1处理2次,rs2处理1次,循环往复


4.6.4 random

官方 :基于权重随机选择
大白话 :摇号分配服务器
配置

bash 复制代码
backend lottery
    balance random
    server rs1 172.25.254.10:80 weight 8
    server rs2 172.25.254.20:80 weight 2

工作逻辑

每请求独立抽签 → rs1命中率80%,rs2命中率20%


4.6.5 leastconn

官方 :优先选择当前连接数最少的服务器
大白话 :谁不忙就派活给谁
配置

bash 复制代码
backend db_pool
    balance leastconn
    server rs1 172.25.254.10:80
    server rs2 172.25.254.20:80

工作逻辑

  • 初始状态:请求1 → rs1(连接数0)
  • rs1有10个连接,rs2有5个连接 → 新请求发给rs2

4.6.6 source

官方 :基于客户端IP的哈希分派
大白话 :相同来源IP永远找同一台服务器
配置

bash 复制代码
backend sticky_pool
    balance source
    server rs1 172.25.254.10:80
    server rs2 172.25.254.20:80

工作逻辑
192.168.1.100的哈希值 → 固定分配给rs1
192.168.1.101的哈希值 → 固定分配给rs2


4.6.7 uri

官方 :基于完整URI的哈希分派
大白话 :相同文件永远从同一服务器获取
配置

bash 复制代码
backend cache_pool
    balance uri
    server rs1 172.25.254.10:80
    server rs2 172.25.254.20:80

工作逻辑

请求 /images/cat.jpg → 哈希值锁定rs1

请求 /videos/demo.mp4 → 哈希值锁定rs2


4.6.8 url_param

官方 :基于URL参数的哈希分派
大白话 :按指定参数值分配专属服务器
配置

bash 复制代码
backend api_pool
    balance url_param user_id
    server rs1 172.25.254.10:80
    server rs2 172.25.254.20:80

工作逻辑

请求 ?user_id=1001 → 参数哈希后固定分配rs2

请求 ?user_id=2002 → 参数哈希后固定分配rs1


4.6.9 hdr

官方 :基于HTTP头部值的哈希分派
大白话 :按报文头特征分配专属通道
配置

bash 复制代码
backend auth_pool
    balance hdr(Authorization)
    server rs1 172.25.254.10:80
    server rs2 172.25.254.20:80

工作逻辑

头部 Authorization: Bearer xyz → 哈希值锁定rs1

头部 Authorization: Basic abc → 哈希值锁定rs2


4.7 算法选择速查表
需求场景 推荐算法 示例
简单主备 first 主服务器优先
固定权重负载 static-rr 3:1固定流量比
动态权重负载 roundrobin 自动调整服务器流量
突发流量分散 random 秒杀请求随机分发
长连接服务 leastconn MySQL查询优化
IP会话保持 source 固定用户访问后端
资源缓存命中 uri 图片/视频缓存优化
参数化路由 url_param 按订单号分片处理
头部特征路由 hdr 按API密钥分配服务器

特殊说明

  • static-rr vs roundrobin:前者权重不可动态调整,后者支持dynamic权重
  • uri 计算整个URI,url_param 只计算指定参数值
  • hdr 需确保指定头部存在,否则回退到roundrobin

5.高级功能及配置

介绍HAProxy高级配置及实用案例

5.1 基于cookie的会话保持

cookie value:为当前server指定cookie值,实现基于cookie的会话黏性,相对于基于 source 地址hash 调度算法对客户端的粒度更精准,但同时也加大了haproxy负载,目前此模式使用较少, 已经被session共享服务器代替

注意:不支持 tcp mode,使用 http mode

5.1.1 配置选项
bash 复制代码
cookie name [ rewrite | insert | prefix ][ indirect ] [ nocache ][ postonly ] [ preserve ][ httponly ] [ secure ][ domain ]* [ maxidle <idle> ][ maxlife ]


name:		#cookie 的 key名称,用于实现持久连接
insert:		#插入新的cookie,默认不插入cookie
indirect:	#如果客户端已经有cookie,则不会再发送cookie信息
nocache:	#当client和hapoxy之间有缓存服务器(如:CDN)时,不允许中间缓存器缓存cookie,
		     #因为这会导致很多经过同一个CDN的请求都发送到同一台后端服务器
5.1.2 配置示例
bash 复制代码
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg

listen webcluster
        bind            *:80
        mode            http
        balance         roundrobin
        hash-type       consistent
        cookie  WEBCOOKIE       insert  nocache indirect
        server  web1 172.25.254.10:80   cookie  servera check inter 5s fall 3
        server  web2 172.25.254.20:80   cookie  serverb check inter 5s fall 3

[root@Haproxy ~]# systemctl restart haproxy.service

5.1.3 验证cookie信息
1. 通过命令行验证
bash 复制代码
curl -i 172.25.254.100
curl -i 172.25.254.100


curl -b WEBCOOKIE=servera 172.25.254.100
curl -b WEBCOOKIE=serverb 172.25.254.100

5.2 Haproxy状态页--监控实现

通过web界面,显示当前HAProxy的运行状态

5.2.1 状态页配置项
bash 复制代码
stats enable   						# 基于默认的参数启用stats page
stats hide-version   				# 将状态页中haproxy版本隐藏
stats refresh <delay> 				# 设定自动刷新时间间隔,默认不自动刷新
stats uri <prefix> 					# 自定义stats page uri,默认值:/haproxy?stats 
stats auth <user>:<passwd>  		# 认证时的账号和密码,可定义多个用户,每行指定一个用户
									# 默认:no authentication
stats admin { if | unless } <cond> 	# 启用stats page中的管理功能
5.2.2 启用状态页
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen stats
        mode            http
        bind            172.25.254.100:8888
        stats           enable
        stats           refresh         1s      #  自动刷新
        log             global
        stats           uri /status             # 自定义ststs page uri
        stats           auth    du:du           # 认证,此行可以出现多次

测试:
浏览器访问:172.25.254.100:8888/status

5.2.3 登录状态页
bash 复制代码
#pid为当前pid号,process为当前进程号,nbproc和nbthread为一共多少进程和每个进程多少个线程
pid = 27134 (process #1, nbproc = 1, nbthread = 1) 

#启动了多长时间
uptime = 0d 0h00m04s 

#系统资源限制:内存/最大打开文件数/
system limits: memmax = unlimited; ulimit-n = 200029 

#最大socket连接数/单进程最大连接数/最大管道数maxpipes
maxsock = 200029; maxconn = 100000; maxpipes = 0 

#当前连接数/当前管道数/当前连接速率
current conns = 2; current pipes = 0/0; conn rate = 2/sec; bit rate = 0.000 kbps 

#运行的任务/当前空闲率
Running tasks: 1/14; idle = 100 % 


active UP:				# 在线服务器
backup UP: 				# 标记为backup的服务器
active UP, going down:	# 监测未通过正在进入down过程
backup UP, going down:	# 备份服务器正在进入down过程
active DOWN, going up:	# down的服务器正在进入up过程
backup DOWN, going up:	# 备份服务器正在进入up过程
active or backup DOWN:	# 在线的服务器或者是backup的服务器已经转换成了down状态
not checked:			# 标记为不监测的服务器

#active或者backup服务器人为下线的
active or backup DOWN for maintenance (MAINT)

#active或者backup被人为软下线(人为将weight改成0)
active or backup SOFT STOPPED for maintenance 
5.2.4 backend server信息
1. Session Rate & Sessions
Session Rate 字段 含义 Sessions 字段 含义
cur 每秒当前会话数量 cur 当前会话总量
max 每秒新最大会话数量 max 最大会话量
limit 每秒新会话限制量 limit 限制会话量
Total 总共会话量
LBTot 选中服务器所用总时间
Last 服务器持续连接时间
Wght 权重
2. Errors & Warnings
Errors 字段 含义 Warnings 字段 含义
Req 错误请求量 Retr 重新尝试次数
conn 错误链接量 Redis 再次发送次数
Resp 错误响应量
3. Bytes & Denied
Bytes 字段 含义 Denied 字段 含义
In 网络字节输入总量 Req 拒绝请求量
Out 网络字节输出总量 Resp 拒绝回复量
4. Server 信息
Server 字段 含义
Status 后端服务器状态 (UP/DOWN)
LastChk 持续检查后端服务器的时间
Act 活动链接数量
Bck 备份服务器数量
Chk 心跳检测时间
Dwn 后端服务器 DOWN 数量
Dwntme 总 downtime 时间
Thrtle 服务器状态
5.3 真实访问主机IP透传

web服务器中需要记录客户端的真实IP地址,用于做访问统计、安全防护、行为分析、区域排行等场景。

5.3.1 七层IP透传

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

bash 复制代码
option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

[ except <network> ]:请求报请来自此处指定的网络时不予添加此首部,如haproxy自身所在网络
[ header <name> ]:	 使用自定义的首部名称,而非"X-Forwarded-For",示例:X-client
[ if-none ] 		  如果没有首部才添加首部,如果有使用默认值
1. 未开启透传的七层代理
bash 复制代码
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
defaults区:
# option forwardfor       except 127.0.0.0/8			# 此参数注释掉之后,IP透传功能即失效。

listen webcluster
        bind            *:80
        mode            http
        balance         roundrobin
        hash-type       consistent
        server  web1 172.25.254.10:80  check inter 5s fall 3
        server  web2 172.25.254.20:80  check inter 5s fall 3

[root@Haproxy ~]# systemctl restart haproxy.service

# 随后在客户端中进行访问,然后去被访问的RS中进行日志查看(是否能看到)
[root@RS-2 ~]# > /var/log/nginx/access.log			# 清空日志,方便观察

curl 172.25.254.100 								# 客户端访问

[root@RS-2 ~]# cat /var/log/nginx/access.log		# 查看日志,发现在此日志中是无法看到真实访问源地址的
172.25.254.100 - - [18/Jul/2025:18:05:13 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/8.12.1" "-"
2. 开启透传的七层代理
bash 复制代码
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
option forwardfor       except 127.0.0.0/8			# defaults中的关键参数


# 随后在客户端中进行访问,然后去被访问的RS中进行日志查看(是否能看到)
[root@RS-2 ~]# > /var/log/nginx/access.log			# 清空日志,方便观察

curl 172.25.254.100 								# 客户端访问

[root@RS-2 ~]# cat /var/log/nginx/access.log		# 查看日志,发现可以查看看源地址的访问
172.25.254.100 - - [18/Jul/2025:18:29:24 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/8.12.1" "172.25.254.1"
5.3.2 四层IP透传

四层对应TCP;七层对应HTTP

此时发现将Haproxy中的关键参数打开了之后发现也是不行,如下图所示。

1. 测试
bash 复制代码
1.测试
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
option forwardfor       except 127.0.0.0/8

listen webcluster
        bind            *:80
        mode            tcp			# 四层是tcp
        balance         roundrobin
        hash-type       consistent
        server  web1 172.25.254.10:80  check inter 5s fall 3
        server  web2 172.25.254.20:80  check inter 5s fall 3
        
[root@Haproxy ~]# systemctl restart haproxy.service

curl 172.25.254.100 								# 客户端访问

[root@RS-2 ~]# cat /var/log/nginx/access.log		# 查看日志,发现原先可以透过来的IP没了
172.25.254.100 - - [18/Jul/2025:18:41:02 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/8.12.1" "-"
2. 解决步骤
bash 复制代码
# Haproxy配置
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
option forwardfor       except 127.0.0.0/8
listen webcluster
        bind            *:80
        mode            tcp
        balance         roundrobin
        hash-type       consistent
        server  web1  172.25.254.10:80 send-proxy check inter 5s fall 3				# 在IP后添加send-proxy参数
        server  web2  172.25.254.20:80 send-proxy check inter 5s fall 3				# 在IP后添加send-proxy参数
        
[root@Haproxy ~]# systemctl restart haproxy.service
# 此时要是在客户端访问的话,会出现下图的此种情况!
bash 复制代码
# Nginx配置
# 在访问日志中通过变量$proxy_protocol_addr 记录透传过来的客户端IP
			
# 如果此时只在下方添加一个参数的话,此时可以访问,但是不能将IP透传过来
# 在80后面添加 proxy_protocol 参数
server {
        listen       80 proxy_protocol;        # 启用此项,将直接无法访问网站,只能通过四层代理的方式进行访问。
        listen       [::]:80;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        error_page 404 /404.html;
        location = /404.html {
        }

        error_page 500 502 503 504 /50x.html;
        location = /50x.html {
        }
    }
    
# 此时发现客户端可以访问,如下图:
curl 172.25.254.100 

[root@RS-2 ~]# > /var/log/nginx/access.log

# 但是发现IP并未被透传过来
[root@RS-2 ~]# cat /var/log/nginx/access.log
172.25.254.100 - - [18/Jul/2025:19:02:01 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/8.12.1" "-"
bash 复制代码
# nginx中还是缺少了一个关键的参数
[root@RS-2 ~]# vim /etc/nginx/nginx.conf
# 添加此参数:'"$proxy_protocol_addr"'
http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '"$proxy_protocol_addr"'			# 重要!!!!!!!!!!!!!!!!!!!
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';
[root@RS-2 ~]# systemctl restart nginx

curl 172.25.254.100

# 此时发现IP被透传过来了!
[root@RS-2 ~]# cat /var/log/nginx/access.log
172.25.254.100 - - [18/Jul/2025:19:07:54 +0800] "GET / HTTP/1.1" "172.25.254.1"200 20 "-" "curl/8.12.1" "-"
3. 四层IP透传--Nginx完整配置详情
4. web服务器日志格式配置

配置web服务器,记录负载均衡透传的客户端IP地址

bash 复制代码
#apache 配置(只适于七层,不适用与四层):
LogFormat "%{X-Forwarded-For}i %a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined

#nginx 日志格式:
$proxy_add_x_forwarded_for: 包括客户端IP和中间经过的所有代理的IP
$http_x_forwarded_For:		只有客户端IP

log_format main  '"$proxy_add_x_forwarded_for" - $remote_user [$time_local] 
					"$request" '
                      '$status $body_bytes_sent "$http_referer" '
					  '"$http_user_agent" $http_x_forwarded_For';
5. 使用Apache将此实验进行完全完成

将RS-1的web配置完成,使其客户端可以访问两台服务主机

bash 复制代码
# 上面的实验利用Nginx将RS-2完成IP透传之后,并未将RS-1设置好;这里使用Apache将RS-1同样可以利用IP透传技术

# 将先前的Nginx的服务关闭
[root@RS-1 ~]# systemctl stop nginx			
[root@RS-1 ~]# systemctl disable --now  nginx

# 下载Apache,并开启httpd的服务
[root@RS-1 ~]# yum install -y httpd

[root@RS-1 ~]# systemctl enable --now httpd

# 将RS-2的nginx页面文件copy一下给RS-1
# 注意:
# 		Nginx  里面的index.html路径为:/usr/share/nginx/html/index.html
# 		Apache 里面的index.html路径为:/var/www/html/index.html
[root@RS-2 ~]# cat /usr/share/nginx/html/index.html
RS-2:172.25.254.20
[root@RS-1 ~]# echo "RS-1:`hostname -I`" > /var/www/html/index.html
[root@RS-1 ~]# cat /var/www/html/index.html
RS-1:172.25.254.10

# 在httpd服务配置文件中添加重要参数,后期测试一下(虽然说在四层里面此参数不起作用....)
[root@RS-1 ~]# vim /etc/httpd/conf/httpd.conf
196 <IfModule log_config_module>
197     #
198     # The following directives define some format nicknames for use with
199     # a CustomLog directive (see below).
200     #
201     LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined	# {X-Forwarded-For}i 	重要参数
202     LogFormat "%h %l %u %t \"%r\" %>s %b" common

[root@RS-1 ~]# systemctl restart httpd

# 将Haproxy中的配置参数原本为nginx提供帮助的send-proxy删去(Apache中不需要此参数)
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen webcluster
        bind            *:80
        mode            tcp
        balance         roundrobin
        hash-type       consistent
        server  web1  172.25.254.10:80 check inter 5s fall 3				# 将此send-proxy参数删去
        server  web2  172.25.254.20:80 send-proxy check inter 5s fall 3		# 这个是RS-2的不用管

[root@Haproxy ~]# systemctl restart haproxy.service			# 修改完配置文件后,将服务重启即可

# 在客户端中进行测试,如下图
curl 172.25.254.100
RS-1:172.25.254.10

curl 172.25.254.100
RS-2:172.25.254.20

# 测试发现:四层的httpd并不能将IP透传过来,七层则可以!
[root@RS-1 ~]# tail -1 /etc/httpd/logs/access_log
- 172.25.254.100 - - [19/Jul/2025:16:27:16 +0800] "GET / HTTP/1.1" 200 20 "-" "curl/8.12.1"
5.4 ACL--访问控制列表

访问控制列表ACL,(Access Control Lists)

是一种基于包过滤的访问控制技术

它可以根据设定的条件对经过服务器传输的数据包进行过滤(条件匹配)即对接收到的报文进行匹配和过滤,基于请求报文头部中的源地址、源端口、目标地址、目标端口、请求方法、URL、文件后缀等信息内容进行匹配并执行进一步操作,比如允许其通过或丢弃。

bash 复制代码
#示例
frontend test_acl
    bind *:80
    mode http
    #acl bad_browers hdr_beg(User-Agent) -i curl
    #http-request deny  if bad_browers

    #acl test hdr_dom(host) -i www.timinglee.org
    #acl test hdr_end(host) -i .org
    #acl test base_sub -m sub  org
    #acl test path_sub -m sub  /a
    #acl test path_end -m sub  /a
    #acl test path_reg -i ^/t
    acl test url_sub -m sub lee
    acl  test path_dir -m sub a
    use_backend  test_web if test

    default_backend default_webserver


backend default_webserver
    mode http
    server web1 172.25.254.20:80 check inter 3 fall 3 rise 5

backend test_web
    mode http
    server web2 172.25.254.30:80 check inter 3 fall 3 rise 5
bash 复制代码
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg

frontend test_acl
        bind    *:80
        mode    http
        
# 记得在windows中将此文件(C:\Windows\System32\drivers\etc\hosts)添加域名解析
#       acl test hdr_dom(host)  -i      www.ceshi.org
#       acl test hdr_end(host)  .com
#       acl test hdr_beg(host)  bbs.
#       acl test base_sub       -m      sub     org
#       acl test base_sub       -m      sub     du
#       acl test path_sub       -m      sub     ceshi

        use_backend             test_web                if      test
        default_backend         default_webserver


backend default_webserver
        mode http
        server web1 172.25.254.10:80 check inter 3 fall 3 rise 5

backend test_web
        mode http
        server web2 172.25.254.20:80 check inter 3 fall 3 rise 5
        
        
[root@Haproxy ~]# systemctl restart haproxy.service			# 每次更改配置之后记得要进行服务重启!!!!!
5.4.0 ACL测试参数配置举例
1. acl test hdr_dom(host) www.ceshi.org域名
2. acl test hdr_end(host) .com后缀
3. acl test hdr_beg(host) bbs.前缀
4. acl test base_sub -m sub org
5. acl test base_sub -m sub du
bash 复制代码
[root@RS-2 ~]# mkdir -p /var/www/html/du

[root@RS-2 ~]# echo "172.25.254.20 du--> this is test" > /var/www/html/du/index.html
6. acl test path_sub -m sub ceshi
bash 复制代码
[root@RS-2 ~]# mkdir -p /var/www/html/ceshi

[root@RS-2 ~]# echo "RS-2:172.25.254.20 ceshi" > /var/www/html/ceshi/index.html

# 体验5,6的差别
# 6可以做动静分离(访问相同的网址,不同的路径,反馈的内容不相同)
5.4.1 ACL配置选项
bash 复制代码
#用acl来定义或声明一个acl
acl   <aclname> <criterion>   [flags]     [operator]   [<value>]
acl     名称      匹配规范       匹配模式      具体操作符    操作对象类型
1. ACL-Name 名称
bash 复制代码
acl 	test 	path_end 		-m 			sub  		/a

# ACL名称,可以使用大字母A-Z、小写字母a-z、数字0-9、冒号:、点.、中横线和下划线,并且严格区分大小写,比如:my_acl和My_Acl就是两个完全不同的acl5.8.1.2 ACL-criterion
2. ACL-criterion 匹配规范
  • 定义ACL匹配规范,即:判断条件
bash 复制代码
hdr string,提取在一个HTTP请求报文的首部
hdr([<name> [,<occ>]]):完全匹配字符串,header的指定信息,<occ> 表示在多值中使用的值的出现次数
hdr_beg([<name> [,<occ>]]):前缀匹配,header中指定匹配内容的begin
hdr_end([<name> [,<occ>]]):后缀匹配,header中指定匹配内容end
hdr_dom([<name> [,<occ>]]):域匹配,header中的dom(host)

hdr_dir([<name> [,<occ>]]):路径匹配,header的uri路径
hdr_len([<name> [,<occ>]]):长度匹配,header的长度匹配
hdr_reg([<name> [,<occ>]]):正则表达式匹配,自定义表达式(regex)模糊匹配
hdr_sub([<name> [,<occ>]]):子串匹配,header中的uri模糊匹配 模糊匹配c 报文中a/b/c也会匹配 

#示例:
hdr(<string>) 用于测试请求头部首部指定内容

hdr_dom(host) 请求的host名称,如 www.timinglee.org
hdr_beg(host) 请求的host开头,如 www.   img.   video.   download.   ftp.
hdr_end(host) 请求的host结尾,如 .com   .net   .cn

#示例:
acl bad_agent hdr_sub(User-Agent) -i curl wget
http-request deny  if bad_agent

#有些功能是类似的,比如以下几个都是匹配用户请求报文中host的开头是不是www
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.

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 : string
#提取请求的URL路径,该路径从第一个斜杠开始,并在问号之前结束(无主机部分)
<scheme>://<user>:<password>@<host>:<port>#/<path>;<params>#?<query>#<frag>
 path     : exact string match
 path_beg : prefix match  #请求的URL开头,如/static、/images、/img、/css
 path_end : suffix match  #请求的URL中资源的结尾,如 .gif .png .css .js .jpg  .jpeg
 path_dom : domain match
 path_dir : subdir match
 path_len : length match
 path_reg : regex match
 path_sub : substring match

#示例:
 path_beg -i /haproxy-status/ 
 path_end .jpg .jpeg .png .gif 
 path_reg ^/images.*\.jpeg$ 
 path_sub image  
 path_dir jpegs 
 path_dom timinglee

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

dst 	 #目标IP
dst_port #目标PORT

src   	 #源IP
src_port #源PORT

#示例:
acl invalid_src src 10.0.0.7 192.168.1.0/24
acl invalid_src src 172.16.0.0/24

acl invalid_port src_port 0:1023

status : integer  #返回在响应报文中的状态码

#七层协议
acl valid_method method GET HEAD
http-request deny if ! valid_method
3. ACL-flags 匹配模式
  • ACL匹配模式
bash 复制代码
-i 不区分大小写
-m 使用指定的正则表达式匹配方法
-n 不做DNS解析
-u 禁止acl重名,否则多个同名ACL匹配或关系
4. ACL-operator 具体操作符
  • ACL 操作符
bash 复制代码
整数比较: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进行匹配
5. ACL-value 操作对象
  • value的类型
bash 复制代码
The ACL engine can match these types against patterns of the following types :
- Boolean #布尔值
- integer or integer range 	#整数或整数范围,比如用于匹配端口范围
- IP address / network 		#IP地址或IP范围, 192.168.0.1 ,192.168.0.1/24
- string--> www.timinglee.org
  exact 		#精确比较
  substring 	#子串
  suffix 		#后缀比较
  prefix 		#前缀比较
  subdir 		#路径, /wp-includes/js/jquery/jquery.js
  domain 		#域名,www.timinglee.org
- regular expression 	#正则表达式
- hex block 			#16进制
5.4.2 多个ACL的组合调用方式
  • 多个ACL的逻辑处理
bash 复制代码
与:隐式(默认)使用
或:使用"or" 或 "||"表示
否定:使用 "!" 表示
  • 多个ACL调用方式:
bash 复制代码
#示例:
if valid_src valid_port 		#与关系,ACL中A和B都要满足为true,默认为与
if invalid_src || invalid_port  #或,ACL中A或者B满足一个为true
if ! invalid_src 				#非,取反,不满足ACL才为true
5.4.3 基于域名匹配访问--ACL示例
bash 复制代码
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg

################ 基于域名 ################
frontend test_acl
        bind    *:80
        mode    http

        acl     test    hdr_dom(host)   -i      www.yuming.com

        use_backend             test_web                if      test
        default_backend         default_webserver

backend default_webserver
       mode http
       server web1 172.25.254.10:80 check inter 3 fall 3 rise 5

backend test_web
       mode http
       server web2 172.25.254.20:80 check inter 3 fall 3 rise 5

[root@Haproxy ~]# systemctl restart haproxy.service

# 记得在windows中将此文件(C:\Windows\System32\drivers\etc\hosts)添加域名解析!
# 测试即可
5.4.4 基于源IP或子网调度访问--ACL示例

将指定的源地址调度至指定的web服务器组

bash 复制代码
# 更改配置文件
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
################ 基于源IP或子网调度访问 ################
frontend test_acl
        bind    *:80
        mode    http

        acl     ctrl_ip         src     172.25.254.20    192.168.0.0/24	 	# 这里表明只有172.25.254.20的IP和192.168.0.0的网段可以访问;其余都不可。

        use_backend             test_web                if      ctrl_ip
        default_backend         default_webserver

backend default_webserver
       mode http
       server web1 172.25.254.10:80 check inter 3 fall 3 rise 5

backend test_web
       mode http
       server web2 172.25.254.20:80 check inter 3 fall 3 rise 5
       
[root@Haproxy ~]# systemctl restart haproxy.service

# 在RS-1(172.25.254.10)、RS-2(172.25.254.20)与Haproxy(192.168.0.0)中进行测试,如下图:
[root@RS-1 ~]# curl 172.25.254.100
RS-1:172.25.254.10

[root@RS-2 ~]# curl 172.25.254.100			# 可以发现仅RS-2可以通过172.25.254.100访问到172.25.254.20
RS-2:172.25.254.20

[root@Haproxy ~]# curl 172.25.254.100
RS-1:172.25.254.10
5.4.5 基于源地址的访问控制--ACL示例

拒绝指定IP或者IP范围访问 http-request deny if xxx

bash 复制代码
# 更改配置文件
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
################ 基于源IP或子网调度访问 ################
frontend test_acl
        bind    *:80
        mode    http

#       acl     ctrl_ip         src     172.25.254.20    192.168.0.0/24
        acl     ctrl_ip         src     172.25.254.10						

#       use_backend             test_web                if      ctrl_ip
        http-request            deny                    if      ctrl_ip	# 使上面提出的172.25.254.10访问服务器时拒绝;其余都可以访问;类似于黑名单。
        default_backend         default_webserver

backend default_webserver
       mode http
       server web1 172.25.254.10:80 check inter 3 fall 3 rise 5

backend test_web
       mode http
       server web2 172.25.254.20:80 check inter 3 fall 3 rise 5

[root@Haproxy ~]# systemctl restart haproxy.service

[root@RS-1 ~]# curl 172.25.254.100
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
</body></html>

[root@RS-2 ~]# curl 172.25.254.100
RS-1:172.25.254.10

[root@Haproxy ~]# curl 172.25.254.100
RS-1:172.25.254.10
5.4.6 匹配浏览器类型--ACL示例

匹配客户端浏览器,将不同类型的浏览器调动至不同的服务器组、

范例: 拒绝curl和wget的访问

bash 复制代码
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
################ 匹配浏览器类型 ################
frontend test_acl
        bind    *:80
        mode    http

        acl             user_agent_block        hdr_sub(User-Agent)     -i      curl    wget			# curl与wget命令被禁用
        http-request    deny    if      user_agent_block												# 此处为禁用命令
        default_backend         default_webserver

backend default_webserver
       mode http
       server web1 172.25.254.10:80 check inter 3 fall 3 rise 5

backend test_web
       mode http
       server web2 172.25.254.20:80 check inter 3 fall 3 rise 5

[root@Haproxy ~]# systemctl restart haproxy.service

5.4.7 基于文件后缀名实现动静分离--ACL示例
bash 复制代码
1.先做php页面测试文件
# RS-2:Apache中的php测试文件做法
[root@RS-2 ~]# dnf install -y php

[root@RS-2 ~]# systemctl restart  httpd

[root@RS-2 ~]# vim /var/www/html/index.php
[root@RS-2 ~]# more /var/www/html/index.php
<?php
        phpinfo();
?>
# 去浏览器中测试一下172.25.254.20/index.php,测试图片如下:
bash 复制代码
2.Haproxy配置文件
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
############### 基于文件名后缀名实现动静分离  ################
frontend test_acl
        bind    *:80
        mode    http

        acl url_staic   path_end  -i  .html  .jpg  .png  .css  .js
        acl url_php     path_end  -i  .php

        use_backend             test_web        if      url_php
        default_backend         default_webserver

backend default_webserver
       mode http
       server web1 172.25.254.10:80 check inter 3 fall 3 rise 5

backend test_web
       mode http
       server web2 172.25.254.20:80 check inter 3 fall 3 rise 5

[root@Haproxy ~]# systemctl restart haproxy.service
# 浏览器中去测试172.25.254.100  172.25.254.100/index.html	172.25.254.100/index.php 如下图:
5.4.8 匹配访问路径实现动静分离--ACL示例
bash 复制代码
1.RS-1:创建测试目录与文件
[root@RS-2 ~]# mkdir -p /var/www/html/static

[root@RS-2 ~]# echo "static-172.25.254.20" > /var/www/html/static/index.html

[root@RS-2 ~]# curl 172.25.254.20/static/
static-172.25.254.20
[root@RS-2 ~]# curl 172.25.254.20/static/index.html
static-172.25.254.20

2.RS-2:创建测试目录与文件
[root@RS-1 ~]# mkdir -p /var/www/html/php

[root@RS-1 ~]# cat /var/www/html/index.php
<?php
        phpinfo();
?>
[root@RS-1 ~]# cp /var/www/html/index.php /var/www/html/php
bash 复制代码
2.Haproxy配置文件
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
############### 基于文件名后缀名实现动静分离  ################
frontend test_acl
        bind    *:80
        mode    http

        acl url_static   path_sub  -m  sub   /static  /php  /images  /javascript

        use_backend             test_web        if      url_static
        default_backend         default_webserver

backend default_webserver
       mode http
       server web1 172.25.254.10:80 check inter 3 fall 3 rise 5

backend test_web
       mode http
       server web2 172.25.254.20:80 check inter 3 fall 3 rise 5

[root@Haproxy ~]# systemctl restart haproxy.service
# 浏览器去搜索172.25.254.100/static
bash 复制代码
# 示例
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...
frontend testacl
    bind :80
    mode http

    ###########     ACL settings    #######################
    acl url_static  path_end -i .jpg .png .css .js .html
    acl url_static  path_end -m sub /static /images /javascript
    acl acl_app     path_beg -m sub /api



    ###########     host        ###########################
    use_backend static_host if url_static
    use_backend api_host if acl_app


    ###########     default server      ###################
    default_backend default_webserver


backend static_host
    mode http
    server web2 192.168.0.101:80 check weight 1 inter 3s fall 3 rise 5

backend api_host
    mode http
    server web1 192.168.0.102:80 check weight 1 inter 3s fall 3 rise 5

backend default_webserver
    mode http
    server web1 172.25.254.10:80 check weight 1 inter 3s fall 3 rise 5

#创建相关文件
[root@rs1 ~]# mkdir /usr/share/nginx/html/static
[root@rs1 ~]# echo static 192.168.0.101 > /usr/share/nginx/html/static/index.html
[root@rs2 ~]# mkdir  /var/www/html/api/
[root@rs2 ~]# echo api 192.168.0.102 > /var/www/html/api/index.html

#测试访问
[root@node10 ~]# curl 172.25.254.100/api/
api 192.168.0.102
[root@node10 ~]# curl 172.25.254.100/static/
static 192.168.0.101
5.5 自定义Haproxy错误界面

对指定的报错进行重定向,进行优雅的显示错误页面

使用errorfile和errorloc指令的两种方法,可以实现自定义各种错误页面

bash 复制代码
[root@RS-1 ~]# systemctl stop httpd
[root@RS-2 ~]# systemctl stop httpd

#  测试:去浏览器中访问172.25.254.100----> 会发现页面报错很简陋
bash 复制代码
#haproxy默认使用的错误错误页面
[root@Haproxy ~]# rpm -ql haproxy | grep http$
/usr/share/haproxy/400.http
/usr/share/haproxy/403.http
/usr/share/haproxy/408.http
/usr/share/haproxy/500.http
/usr/share/haproxy/502.http
/usr/share/haproxy/503.http
/usr/share/haproxy/504.http
5.5.1 基于自定义的错误页面文件
bash 复制代码
# 自定义错误页
errorfile <code> <file> 

<code> # HTTP status code.支持200, 400, 403, 405, 408, 425, 429, 500, 502,503,504

<file> # 包含完整HTTP响应头的错误页文件的绝对路径。 建议后缀".http",以和一般的html文件相区分


# 示例:
errorfile 503 /haproxy/errorpages/503page.http 
bash 复制代码
# 测试
[root@RS-1 ~]# systemctl stop httpd
[root@RS-2 ~]# systemctl stop httpd

[root@haproxy ~]# mkdir /haproxy/errorpages/  -p

[root@Haproxy ~]# vim /haproxy/errorpages/503mypage.http

HTTP/1.0 503 Service Unavailable
Cache-Control: no-cache
Connection: close
Content-Type: text/html;charset=UTF-8

<html><body><h1>什么动物生气最安静</h1>
大猩猩!!
</body></html>

[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
defaults
    mode                    http

	...内容省略...

    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 1000000

    errorfile 503 /haproxy/errorpages/503mypage.http
[root@Haproxy ~]# systemctl restart haproxy.service

# 浏览器访问172.25.254.100进行测试
5.5.2 基于http重定向错误页面
bash 复制代码
#错误页面重定向
errorloc <code> <url>
#相当于errorloc302 <code> <url>,利用302重定向至指URL

#示例:
errorloc 503 https://www.baidu.com
bash 复制代码
haproxy ~]# vim /etc/haproxy/haproxy.cfg
...上面内容省略...
defaults
    mode                    http

	...内容省略...

    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 1000000

    errorloc 503 https://www.baidu.com

#浏览器访问172.25.254.100 自动跳转到百度


5.6 Haproxy四层负载--数据库示例

针对除HTTP以外的TCP协议应用服务访问的应用场景

bash 复制代码
MySQL
Redis
Memcache
RabbitMQ
bash 复制代码
# 为两台主机安装mariadb服务
[root@RS-1 ~]# dnf install -y mariadb-server
[root@RS-2 ~]# dnf install -y mariadb-server

[root@RS-1 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
[root@RS-2 ~]# vim /etc/my.cnf.d/mariadb-server.cnf
# 进入配置文件,将添加一项参数:server-id
# 修改如下:
# 			server-id=1
#			server-id=2
bash 复制代码
[root@RS-1 ~]# systemctl start mariadb.service
[root@RS-1 ~]# mysql
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+

[root@RS-2 ~]# systemctl start mariadb.service
[root@RS-2 ~]# mysql
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           2 |
+-------------+
bash 复制代码
1.Haproxy增添配置
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
[root@Haproxy ~]# systemctl restart haproxy.service			# 推荐这一种
################ 四层负载均衡示例 ############
listen dbserver
        bind            *:3306
        mode            tcp
        balance         static-rr
        server    db1   172.25.254.10:3306      check   inter 2  fall 2  rise 5
        server    db2   172.25.254.20:3306      check   inter 2  fall 2  rise 5
        
        
# 或者使用frontend和backend实现
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend mysql_port
    bind :3306
    mode tcp
    use_backend mysql_rs

backend mysql_rs
    mode tcp
    balance static-rr
    server db1 172.25.254.10:3306      check   inter 2  fall 2  rise 5
    server db2 172.25.254.20:3306      check   inter 2  fall 2  rise 5
mysql 复制代码
2.测试
# RS-1:
[root@RS-1 ~]# mysql -udu -p -h 172.25.254.100
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           2 |
+-------------+

[root@RS-1 ~]# mysql -udu -p -h 172.25.254.100
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+

# RS-2:
[root@RS-2 ~]# mysql -udu -p -h 172.25.254.100
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           1 |
+-------------+

[root@RS-2 ~]# mysql -udu -p -h 172.25.254.100
MariaDB [(none)]> select @@server_id;
+-------------+
| @@server_id |
+-------------+
|           2 |
+-------------+

5.7 Haproxy https实现

haproxy可以实现https的证书安全,从用户到haproxy为https,从haproxy到后端服务器用http通信

但基于性能考虑,生产中证书都是在后端服务器比如Nginx上实现

bash 复制代码
#配置HAProxy支持https协议,支持ssl会话;
 bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE 

#指令 crt 后证书文件为PEM格式,需要同时包含证书和所有私钥
 cat demo.key demo.crt > demo.pem 

#把80端口的请求重向定443
 bind *:80
 redirect scheme https if !{ ssl_fc } 
5.7.1 证书制作
bash 复制代码
[root@Haproxy ~]# mkdir /etc/haproxy/certs/

[root@Haproxy ~]# openssl req  -newkey rsa:2048 -nodes  -sha256 -keyout /etc/haproxy/certs/timinglee.org.key -x509 -days 365 -out /etc/haproxy/certs/timinglee.org.crt

[root@Haproxy ~]# cd /etc/haproxy/certs/

[root@Haproxy certs]# cat timinglee.org.key timinglee.org.crt > timinglee.pem
5.7.2 https配置示例
bash 复制代码
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg

frontend  webcluster-80
        bind            *:80
        mode            http
        balance         roundrobin
        redirect        scheme  https   if !{ ssl_fc }          # 全栈加密
        use_backend     webserver

frontend  webcluster-443
        bind            *:443   ssl     crt     /etc/haproxy/certs/timinglee.pem
        mode            http
        balance         roundrobin
        use_backend     webserver

backend  webserver
        server web1 172.25.254.10:80 check  inter 3 fall 3 rise 2
        server web2 172.25.254.20:80 check  inter 3 fall 3 rise 2

[root@Haproxy ~]# systemctl restart haproxy.service
bash 复制代码
[root@Client ~]# curl -IkL http://172.25.254.100
HTTP/1.1 302 Found
content-length: 0
location: https://172.25.254.100/
cache-control: no-cache

HTTP/1.1 200 OK
date: Sun, 20 Jul 2025 08:25:21 GMT
server: Apache/2.4.57 (Red Hat Enterprise Linux)
last-modified: Sat, 19 Jul 2025 08:02:27 GMT
etag: "14-63a43a9da2ccf"
accept-ranges: bytes
content-length: 20
content-type: text/html; charset=UTF-8
相关推荐
cherishSpring6 分钟前
Eureka服务端启动
云原生·eureka
慢慢慢时光1 小时前
本地k8s集群的搭建
云原生·容器·kubernetes
橘子编程1 小时前
Kubernetes (K8S)知识详解
云原生·容器·kubernetes
观无4 小时前
基于Eureka和restTemple的负载均衡
云原生·eureka·负载均衡
跑不完的脚本4 小时前
基于K8s ingress灰度发布配置
docker·云原生·容器·kubernetes
阿里云云原生6 小时前
百万 TPS 服务发布无感知!详解轻量消息队列无损发布实践
云原生·消息队列
SilentCodeY11 小时前
Docker 数据目录迁移完整流程
docker·云原生·linux系统·迁移
ZZZKKKRTSAE11 小时前
秒赤Haproxy配置&算法
linux·运维·服务器·网络·haproxy
来自于狂人12 小时前
基于大模型打造故障预警服务器巡检机器人
运维·服务器·人工智能·云原生·机器人