Haproxy (企业级反向代理)
1、Haproxy基础概念
1.1 什么是Haproxy
haproxy 虽然名称中包含 HA ,但它不提供任何 HA 高可用的功能,它仅提供 proxy 代理的功能;
但是 haproxy 它提供对后端节点的状态进行检测,⼀但后端节点出现故障, haproxy 会将请求进行重新分发,这也是它将自⼰称为 haproxy 的原因。
1.2 Haproxy应用场景
Haproxy支持http、https协议的反向代理Haproxy支持动态程序的反向代理Haproxy支持基于 tcp 协议的反向代理(例如:代理MySQL、SSH、Redis)
1.3 Haproxy性能指标
衡量负载均衡性能,可以从三个因素来评估负载均衡器的性能:
会话率:会话建立的速率,在1秒内能建立多少连接
会话并发能⼒:整体服务器的会话并发能⼒,能同时支撑多少个并发的链接
数据率:在所有会话基础上,数据传输速率或数据传输效率
经过官方测试统计, haproxy 单位时间处理的最⼤请求数为 20000 个,可以同时维护 40000-50000 个并发连接,最⼤数据处理与数据交换能⼒为 10Gbps (那么 10Gbps 实际速率= 10/8=1.25GBps ,下载速率每秒 1.25GB )。综合上述, haproxy 是性能优越的负载均衡、反向代理服务器。
2、Haproxy服务部署
2.1 使用系统rpm安装
1、在Centos7系统中默认提供的 Haproxy 版本是 1.5.18 比较旧,很多新功能都不支持
[root@proxy ~]# yum install haproxy -y
# 验证haproxy版本
[root@proxy ~]# haproxy -v
HA-Proxy version 1.5.18 2016/05/10
Copyright 2000-2016 Willy Tarreau <willy@haproxy.org>2、在RockyLinux9系统默认提供的 Haproxy 的版本是 2.4 TLS
[root@proxy ~]# dnf install haproxy -y
# 验证haproxy版本
[root@proxy ~]# haproxy -v
HAProxy version 2.4.22-f8e3218 2023/02/14 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2026.
Known bugs: http://www.haproxy.org/bugs/bugs-2.4.22.html
Running on: Linux 5.14.0-427.13.1.el9_4.x86_64 #1 SMP PREEMPT_DYNAMIC Wed May 1 19:11:28 UTC 2024 x86_642.2 源码安装Haproxy
1、安装依赖环境
[root@proxy ~]# yum install lua gcc make readline-devel openssl-devel zlib-devel pcre-devel systemd-devel wget -y2、通过源码方式安装lua脚本[可选],下载地址: https://www.lua.org/download.html

[root@proxy ~]# wget https://www.lua.org/ftp/lua-5.4.6.tar.gz
[root@proxy ~]# tar xf lua-5.4.6.tar.gz -C /usr/local/
[root@proxy ~]# cd /usr/local/lua-5.4.6/
[root@haproxy lua-5.4.6]# make all test
[root@haproxy lua-5.4.6]# ln -s /usr/local/lua-5.4.6/ /usr/local/lua3、源码编译Haproxy
[root@proxy ~]# wget https://www.haproxy.org/download/2.8/src/haproxy-2.8.7.tar.gz
[root@proxy ~]# tar xf haproxy-2.8.7.tar.gz
[root@proxy ~]# cd haproxy-2.8.7/
[root@haproxy haproxy-2.8.7]# make ARCH=x86_64 TARGET=linux-glibc \
USE_PCRE=1 USE_OPENSSL=1 \
USE_ZLIB=1 USE_SYSTEMD=1 \
USE_LUA=1 LUA_INC=/usr/local/lua/src LUA_LIB=/usr/local/lua/src
[root@haproxy haproxy-2.8.7]# make install PREFIX=/usr/local/haproxy-2.8
[root@haproxy haproxy-2.8.7]# ln -s /usr/local/haproxy-2.8/ /usr/local/haproxy4、创建Haproxy启动文件
[root@proxy ~]# vim /usr/lib/systemd/system/haproxy28.service
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target
[Service]
ExecStartPre=/usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/haproxy.cfg -c -q
ExecStart=/usr/local/haproxy/sbin/haproxy -Ws -f /usr/local/haproxy/haproxy.cfg -p /var/lib/haproxy28/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target5、创建Haproxy配置文件
[root@proxy ~]# vim /usr/local/haproxy/haproxy.cfg
global
maxconn 100000
# uid 99
# gid 99
user haproxy
group haproxy
daemon
log 127.0.0.1 local2 info
pidfile /var/lib/haproxy28/haproxy.pid
stats socket /var/lib/haproxy28/haproxy.sock mode 600 level admin
defaults
option http-keep-alive
option forwardfor
maxconn 100000
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth admin:123456
listen web_port
bind *:8088
mode http
server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 56、根据配置文件,进行初始化操作
[root@proxy ~]# mkdir /var/lib/haproxy28
[root@proxy ~]# useradd -r -s /sbin/nologin haproxy7、启动Haproxy
[root@proxy ~]# systemctl enable haproxy28
[root@proxy ~]# systemctl start haproxy28
# 检查端口
[root@rocky9 ~]# ss -ntl
State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:9999 0.0.0.0:*
LISTEN 0 4096 0.0.0.0:8088 0.0.0.0:*
LISTEN 0 128 [::]:22 [::]:*
# 检查进程
[root@route ~]# ps -ef |grep haproxy
root 22565 1 0 21:24 ? 00:00:00 /usr/local/haproxy/sbin/haproxy -Ws -f /usr/local/haproxy/haproxy.cfg -p /var/lib/haproxy28/haproxy.pid
haproxy 22567 22565 0 21:24 ? 00:00:00 /usr/local/haproxy/sbin/haproxy -Ws -f /usr/local/haproxy/haproxy.cfg -p /var/lib/haproxy28/haproxy.pid
root 22571 12441 0 21:24 pts/1 00:00:00 grep --color=auto haproxy8、验证Haproxy,使用浏览器访问: http://haproxy-server:9999/haproxy-status

3、Haproxy示例配置
我们⾸先回顾 Nginx 负载均衡语法,然后对比 Haproxy 负载均衡语法,这样便于我们更好学习 Haproxy
#----------------------------------------------------------------
# nginx
#----------------------------------------------------------------
server {} # 前端监听对外端口
proxy_pass # 将前端与后端建立关系
upstream{} # 后端资源池
#----------------------------------------------------------------
# haproxy
#----------------------------------------------------------------
frontend # 前端监听对外端口
use_backend # 将前端与后端建立关系,带条件的 location ~ \.php$ )
default_backend # 默认建立关系 ( location / )
backend # 后端资源池
listen # frontend和backend的组合体 ( 直接将前后端建立起来 )
default # 提供统⼀的默认参数,如果定义了则使用自⼰的,没有定义则使用default的3.1 场景示例配置1
场景描述:
1、将请求本机 80 端口的服务,都转发至
webservers后端集群组。2、后端
webservers资源池定义了172.16.1.7:80、172.16.1.8:80两台节点。3、调度方式采用轮询调度。
1、Nginx实现配置,需要使用到 (server、location、proxy_pass、upstream)
upstream webservers {
server 172.16.1.7:80;
server 172.16.1.8:80;
}
server {
listen 80;
server_name proxy.ops.com;
location / {
proxy_pass http://webservers;
}
}2、haproxy实现配置,需要使用到 (frontend、default_backend、backend)
frontend web # 定义前端名称
bind *:80 # 定义前端监听的端口
default_backend webservers # 所有请求调度至 webservers集群
backend webservers # 定义webservers集群名称
balance roundrobin # 采用轮询调度算法
server web1 172.16.1.7:80 check # 定义节点信息 [名称 IP:端口] 检查
server web2 172.16.1.8:80 check # 定义节点信息 [名称 IP:端口] 检查3.2 场景示例配置2
1、将请求本机 80 端口的服务,
uri为 /的默认转发至webservers后端集群组。2、将请求本机 80 端口的服务,
uri为 /1.png|/2.gif的转发至static后端集群组。3、后端
webservers资源池定义了172.16.1.7:80、172.16.1.8:80两台节点。4、后端
static资源池定义了172.16.1.9:80、172.16.1.10:80两台节点。5、调度方式采用轮询调度。
1、Nginx实现配置,需要使用到 (server、location、proxy_pass、upstream)
upstream webservers {
server 172.16.1.7:80;
server 172.16.1.8:80;
}
upstream static {
server 172.16.1.9:80;
server 172.16.1.10:80;
}
server {
listen 80;
server_name proxy.ops.com;
location / {
proxy_pass http://webservers;
}
location ~ \.(png|gif)$ {
proxy_pass http://static;
}
}2、haproxy实现配置,需要使用到 (frontend、default_backend、backend)
frontend web
bind *:80
# 默认所有请求都调度到webservers集群,类似于nginx的locatiton / {}
default_backend webservers
# 如果请求的url是.png | .gif结尾的,则调度到static集群,类似于nginx的location~ \.{gif|png}$ {}
acl url_static path_end -i .gif .png
use_backend static if url_static
backend webservers
balance roundrobin
server web1 172.16.1.7:80 check
server web2 172.16.1.8:80 check
backend static
balance roundrobin
server static1 172.16.1.9:80 check
server static1 172.16.1.10:80 check3.3 场景示例配置3
请求本机 80 端口的服务,直接代理至后端的 172.16.1.11:80 节点。
也就是配置代理模式,并非负载均衡;
1、Nginx实现配置,需要使用到 (server、location、proxy_pass)
server {
listen 80;
server_name proxy.ops.com;
location / {
proxy_pass http://172.16.1.11:80;
}
}2、haproxy实现配置,需要使用到 (listen)
listen web
bind *:80
server web1 172.16.1.11:80;3.4 Haproxy官方示例
frontend main
bind *:5000
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .gif .png .css .js
use_backend static if url_static
default_backend app
backend static
balance roundrobin
server static 127.0.0.1:4331 check
backend app
balance roundrobin
server app1 127.0.0.1:5001 check
server app2 127.0.0.1:5002 check
server app3 127.0.0.1:5003 check
server app4 127.0.0.1:5004 check.5 Haproxy场景实践
1、配置两个后端节点,监听在
8888端口,域名是 proxy.ops.net;2、配置
Haproxy代理两个节点,监听在80端口;
1、准备后端节点 172.16.1.7、172.16.1.8
[root@web01 ~]# vim /etc/nginx/conf.d/proxy.ops.net.conf
server {
listen 8888;
server_name proxy.ops.net;
root /opt;
location / {
index index.html;
}
}
[root@web01 ~]# echo "haproxy--web01" > /opt/index.html
[root@web01 ~]# systemctl reload nginx2、配置Haproxy的负载均衡功能
[root@proxy01 ~]# vim /etc/haproxy/haproxy.cfg
frontend proxy
bind *:80
mode http
# 将请求调度到proxyservers这个资源池
use_backend proxyservers
backend proxyservers
balance roundrobin
server web01 172.16.1.7:8888 check
server web02 172.16.1.8:8888 check
4、Haproxy Global配置
4.1 global配置参数
Global settings 全局配置,用于设定全局配置参数;
1、基本配置选项:
2、进程与线程相关选项:
4.2 配置多进程运行
1、配置haproxy以多进程方式运行
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# 配置haproxy为多进程
nbproc 4
# 配置CPU亲和,将1234进程,绑定至0123的cpu核⼼
cpu-map 1 0
cpu-map 2 1
cpu-map 3 2
cpu-map 4 3
stats socket /var/lib/haproxy/haproxy.sock1 mode 600 level admin
[root@proxy ~]# systemctl restart haproxy2、检查多进程详情
[root@proxy ~]# pstree -p haproxy
haproxy(15295)
haproxy(15296)
haproxy(15297)
haproxy(15298)4.3 配置多线程运行
因为每个进程都是独立的,且资源不可共享。而⼀个进程多个线程的资源是可以共享的,因此多线程的方式要比多进程的方式性能好;
1、配置Haproxy以多线程方式运行
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# 配置Haproxy为多线程
nbthread 4
# turn on stats unix socket
stats socket /var/lib/haproxy/stats mode 600 level admin2、检查结果,{}表示线程
[root@proxy ~]# pstree -p haproxy
haproxy(11799)─┬─{haproxy}(11800)
├─{haproxy}(11801)
└─{haproxy}(11802)4.4 配置访问日志
1、修改 haproxy 配置
[root@lb01 ~]# vim /etc/haproxy/haproxy.cfg
global
log 127.0.0.1 local22.修改 rsyslog 配置
[root@lb01 ~]# vim /etc/rsyslog.conf
# 启用rsyslog的udp
module(load="imudp") # needs to be done just once
input(type="imudp" port="514")
#启用级别为local2的设备,将该设备的所有级别的日志全部输出到/var/log/haproxy.log下
local2.* /var/log/haproxy.log3.重启 haproxy 以及 rsyslog 服务
[root@lb01 ~]# systemctl restart rsyslog haproxy
# 记得访问⼀下⽹站,产生日志信息
[root@lb01 ~]# tail -f /var/log/haproxy.log
haproxy[188268]: 10.0.0.1:65082 [21/Mar/2024:11:45:24.990] proxy proxyservers/web01 0/0/0/1/1 200 213 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1"5、Haproxy defaults配置
5.1 option选项
option 选项用来启用或禁用特定的功能。以下是⼀些常用的 option 参数及其简单描述:
在 HAProxy 配置中,如果想要关闭某些选项时,可以在相应的配置段前⾯添加 no 前缀来禁用它们,例如: no option httplog
5.2 timeout选项
timeout 选项主要是用来设定超时时间的,以下是⼀些常用的 timeout 参数及其简单描述:
6、Haproxy Proxies配置
代理相关配置:
frontend <name>:用于定义⼀系列监听的端口,这些端口可接受客户端请求并与之建立连接;backend <name>:用于定义⼀系列后端服务器,代理将会将对应客户端的请求转发至这些服务器;listen <name>:通过关联“前端”和“后端”定义了⼀个完整的代理;
(frontend:负责监听客户端请求的端口,建立连接。
backend:负责定义要转发请求的后端服务器。
listen:负责关联 frontend 和 backend,组成完整代理。)
6.1 mode参数
mode 概念:设置 Haproxy 运行的协议。
mode 语法: mode { tcp|http }
tcp: 实例运行于TCP模式,不对7层报文做任何检查;通常用于SSL、SSH、MySQL等应用http: 实例运行于HTTP模式,客户端请求服务端,服务端重新封装请求报文,请求后端真实节点
mode 示例:
#----------------------------------------------------------------
# listen 中定义mode
#----------------------------------------------------------------
listen www
bind *:8089
mode tcp
server web1 172.16.1.7:8080
#----------------------------------------------------------------
# frontend 中定义mode
#----------------------------------------------------------------
frontend shop *:80
mode http
use_backend webcluster6.2 bind参数
bind 概念:设置 Haproxy 实例运行的端口
bind 语法: bind [<address>]:<port_range> [, ...] interface<interface>
<address>:可选选项,其可以为主机名、IPv4地址、IPv6地址或*;将其指定为*或0.0.0.0时,将监听当前系统的所有IPv4地址;<port_range>:可以是⼀个特定的TCP端口,也可是⼀个端口范围,如8080-9090;<interface>:指定物理接口名称,仅能在Linux系统上使用;其不能使用接口别名,只有管理有权限指定绑定的物理接口;
bind 示例:
#----------------------------------------------------------------
# listen 中定义 bind
#----------------------------------------------------------------
listen proxy.ops.com
bind *:80 # 单个端口
mode tcp
server web1 172.16.1.7:8080
#----------------------------------------------------------------
# frontend 中定义 bind
#----------------------------------------------------------------
frontend proxy.ops.com
bind *:8899-9090 # 连续端口
mode http
use_backend webcluster6.3 maxconn参数
maxconn 概念:设定最⼤的连接数,对于⼤型站点来说,应该尽可能提高此值,从而避免 haproxy ⽆法应答用户请求。当然,此值最⼤值不能超出 global 段中的定义。
maxconn 语法: maxconn <number>
在 HAProxy 中,每个连接通常会使用两个8KB的缓冲区,加上其他管理开销,⼤约占用17KB的内存。因此,在适当优化配置后,1GB的RAM 可以支持⼤约40,000到50,000个并发连接。
但也不要设置过高的连接数,以免超出服务器的内存容量,建议根据服务器的实际连接数,配置合理的连接数上限。
maxconn 示例:
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
#----------------------------------------------------------------
# Global settings (定义全局,最⼤不能超过4000并发连接数)
#----------------------------------------------------------------
global
maxconn 4000
#----------------------------------------------------------------
# defaults settings (当frontend没定义则使用默认,最⼤不能超过3000并发连接数)
#----------------------------------------------------------------
defaults
maxconn 3000
#----------------------------------------------------------------
# frontend settings (定义每个站点的最⼤连接数,所有站点并发值加起来不能超过Global中的设定)
#----------------------------------------------------------------
frontend web
bind *:80
mode http
maxconn 2000
frontend java
bind *:80
mode http
maxconn 20006.4 server参数
为后端声明⼀个 server 节点信息。不能用于 defaults 和 frontend 区段,只能使用在 backend 区段和 listen 区段。
server 语法: server <name> <address>[:port] [param*]
<name>:为此服务器指定标识名称,会出现在日志文件中;<address>:填写节点的IPv4地址,也支持使用可解析的主机名称;[:port]:指定将连接所发往节点的目标端口,如未设定,则使用客户端请求的端口;[param*]:为此服务器设定的⼀系参数;其可用的参数非常多,下⾯仅说明几个常用的参数;
1、 backup :当所有的正常 server 均不可用时,此 backup 节点则会顶替提供服务;
backend webcluster
server web1 172.16.1.7:80 backup # 当8与9都节点异常,则启用7节点
server web2 172.16.1.8:80
server web3 172.16.1.9:802、 check <port> :对此节点进行 TCP 的健康状态检查;
backend webcluster
server web1 172.16.1.7:80 backup # 当8与9都节点异常,则启用7节点
server web2 172.16.1.8:80 check port 80 # 检测tcp的80端口
server web3 172.16.1.9:80 check port 803、 inter <delay> :设定健康状态检查的时间间隔,单位为毫秒,默认为 2000 毫秒;
backend webcluster
server web1 172.16.1.7:80 backup
server web2 172.16.1.8:80 check inter 3000
server web3 172.16.1.9:80 check inter 30004、 rise <count> :设置 "离线状态" 转换至 "正常状态" 需要成功检查的次数;
backend webcluster
server web1 172.16.1.7:80 backup
server web2 172.16.1.8:80 check inter 3000 rise 2
server web3 172.16.1.9:80 check inter 3000 rise 25、 fall <count> :设置 "正常状态" 转换为 "不可用状态",需要检查的次数;
backend webcluster
server web1 172.16.1.7:80 backup
server web2 172.16.1.8:80 check inter 3000 rise 2 fall 3
server web3 172.16.1.9:80 check inter 3000 rise 2 fall 36、 maxconn <maxconn> :设定当前服务器能接受的最⼤连接数,如果此服务器的连接数高于指定的值,则将其放置请求队列中,以等待其它连接被释放;
# 所有节点加起来的连接之和不能超过global设定的maxconn
backend webcluster
server web1 172.16.1.7:80 backup
server web2 172.16.1.8:80 check inter 3000 rise 2 fall 3 maxconn 2000
server web3 172.16.1.9:80 check inter 3000 rise 2 fall 3 maxconn 30007、 maxqueue <maxqueue> :设定请求队列的最⼤长度,当请求超过 maxconn 设定的数值,剩余请求进⼊队列中,而队列的最⼤长度由 maxqueue 决定,队列的超时时间由 timeout queue 1m 选项决定。
backend webcluster
balance roundrobin
server web1 172.16.1.7:80 check maxconn 2000 maxqueue 200
server web2 172.16.1.8:80 check maxconn 2000 maxqueue 2008、 weight <weight> :服务器节点权重,默认为1,最⼤值为256,0表示不参与负载均衡,等同于将该节点进行下线处理
backend webcluster
server web1 172.16.1.7:80 backup
server web2 172.16.1.8:80 check inter 3000 rise 2 fall 3 maxconn 2000 max queue 200 weight 2
server web3 172.16.1.9:80 check inter 3000 rise 2 fall 3 maxconn 3000 max queue 200 weight 27、使用子配置管理
当业务众多时,将所有配置都放在⼀个配置文件中,会造成维护困难。
可以考虑按业务分类,将配置拆分,放在不同的配置文件中,从而达到方便维护的目的。
7.1 创建子配置文件
# 创建子配置文件,注意:必须为 cfg 后缀
[root@haproxy ~]# mkdir /etc/haproxy/conf.d
[root@haproxy ~]# vim /etc/haproxy/conf.d/app.ops.net.cfg
frontend app_web
bind *:80
mode http
use_backend app_servers
backend app_servers
balance roundrobin
server web1 172.16.1.7:81 check inter 3000 fall 2 rise 5
server web2 172.16.1.8:81 check inter 3000 fall 2 rise 57.2 修改启动文件(rpm安装不需要调整)
# 添加子配置目录到 unit 文件中,使其能加载子目录配置
[root@haproxy ~]# cat /usr/lib/systemd/system/haproxy.service
[Unit]
Description=HAProxy Load Balancer
After=network-online.target
Wants=network-online.target
[Service]
EnvironmentFile=-/etc/sysconfig/haproxy
Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/run/haproxy.pid"
##定义配置文件路径变量
Environment="CONFIG_D=/etc/haproxy/conf.d/"
# 启动或停⽌使用 -f 调用CONFIG_D变量
ExecStartPre=/usr/sbin/haproxy -f $CONFIG -f $CONFIG_D -c -q $OPTIONS
ExecStart=/usr/sbin/haproxy -Ws -f $CONFIG -f $CONFIG_D -p $PIDFILE $OPTIONS
ExecReload=/usr/sbin/haproxy -f $CONFIG -f $CONFIG_D -c -q $OPTIONS
ExecReload=/bin/kill -USR2 $MAINPID
KillMode=mixed
SuccessExitStatus=143
Type=notify
[Install]
WantedBy=multi-user.target7.3 重载服务
[root@haproxy ~]# systemctl daemon-reload
[root@haproxy ~]# systemctl restart haproxy
02 Haproxy高级功能
1、基于cookie会话保持
1.1 Cookie植⼊介绍
在 HAProxy 中,可以基于 cookie 的功能来确保同⼀用户始终与同⼀个后端服务器连续交互,从而保持会话的⼀致性。这是如何⼯作的:
1、当用户第⼀次访问通过 HAProxy 负载均衡的应用时,HAProxy 选择⼀个后端服务器来处理请求,并在响应的中包含⼀个特殊的 cookie。(通常是节点名称或ID,自行指定)
2、用户的浏览器存储这个 cookie,并在随后的请求中将它发送给
HAProxy。3、当
HAProxy收到带有此cookie的请求时,它会读取cookie的值,并将请求直接发送到之前选定的那台后端节点。
这样,即使有多个请求,用户的会话都会与最初选定的后端服务器保持⼀致性。
要启用这个功能,需要在 HAProxy 配置文件的 backend 部分进行设置。设置⼀个 cookie 名称,并在 server 指令中为每台服务器的指定 cookie 的值。
1.2 配置示例
1.配置 haproxy 基于 cookie 实现会话绑定。
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
#----------------------------------------------------------------
# main frontend which proxys to the backends
#----------------------------------------------------------------
frontend proxy.ops.com
bind *:80
mode http
use_backend webcluster
#----------------------------------------------------------------
# round robin balancing between the various backends
#----------------------------------------------------------------
backend webcluster
balance roundrobin
# 回传数据时添加Set-Cookie,Key为SERVERID,Value为节点定义cookie值
cookie SERVERID insert nocache
server web1 172.16.1.7:80 check cookie web1 # 为每个服务器定义⼀个cookie名称标识
server web2 172.16.1.8:80 check cookie web21.3 验证session
1、客户端第⼀次请求。 haproxy 会挑选⼀个节点响应,并会通过 Set-Cookies 返回该响应的是哪台后端节点


2、客户端第二次请求,此时客户端会通过 Request 携带 对应的Cookie

3、如果此时将服务端分配给客户端的节点关闭,则会造成客户端请求失败,那么该如何实现故障转移;
1.3 redispatch参数
当使用了cookie持久化连接时, haproxy将会将其请求的后端服务器定义的serverID插入到客户端的cookie中,以保证会话的持久性;如果后端的节点出现了宕掉,但是客户端的cookie是不会刷新的,如果设置此参数,将会将客户的请求强制定向到另外一个正常的后端server上,以保证服务的正常。

cookie植入实现会话保持,完整配置示例
[root@lb01 ~]# vim /etc/haproxy/haproxy.cfg
#----------------------------------------------------------------
# main frontend which proxys to the backends
#----------------------------------------------------------------
frontend proxy.ops.com
bind *:88
mode http
option forwardfor except 127.0.0.1
option redispatch # 启动redispatch
maxconn 10000
use_backend webcluster
#----------------------------------------------------------------
# round robin balancing between the various backends
#----------------------------------------------------------------
backend webcluster
balance roundrobin
cookie SERVERID insert nocache
server web1 172.16.1.7:80 check cookie web01
server web2 172.16.1.8:80 check cookie web022、基于web管理haproxy
HAProxy 有统计报告功能,可以让使用者通过 web页面概览后端服务器的概况,甚至更改它们的状态。
2.1 状态页配置
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
#----------------------------------------------------------------
# Stats settings
#----------------------------------------------------------------
listen haproxy-stats
mode http
bind *:9999
stats enable # 启用stats功能
stats refresh 5s # 设定自动刷新时间间隔
stats hide-version # 隐藏haproxy版本
stats uri /haproxy-stats # stats页面的访问路径
stats realm "HAProxy stats" # 认证提示信息
stats auth ops:123456 # 认证的账号和密码
stats admin if TRUE # 启用管理功能
#http-request user-service prometheus-exporter if { path /metrics }2.2 状态页登陆
通过http://IP:port/haproxy?stats访问该页面


1. 标题与基础标识
•
HAProxy:表明这是 HAProxy 负载均衡器的统计界面。•
Statistics Report for pid 1943:该报告对应 进程 ID 为 1943 的 HAProxy 实例。
2. 常规进程信息(General process information)
这部分展示 HAProxy 进程的核心运行参数:
3. 右侧「状态图例」解析
界面右侧的颜色标识用于区分 前端(Frontend)或后端(Backend)中服务器的状态,关键状态含义如下:
3、基于socat管理haproxy
3.1 安装socat
[root@haproxy ~]# yum install socat -y3.2 修改配置文件
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
global
# turn on stats unix socket
stats socket /var/lib/haproxy/stats level admin
[root@haproxy ~]# systemctl restart haproxy3.3 实现主机动态下上线
# 获取详情
[root@haproxy ~]# echo "show info" | socat stdio /var/lib/haproxy/stats
# 获取当前的统计信息
[root@haproxy ~]# echo "show stat" | socat stdio /var/lib/haproxy/stats
# 动态下线主机
[root@haproxy ~]# echo "disable server app_servers/web1" | socat stdio /var/lib/haproxy/stats
# 动态上线主机
[root@haproxy ~]# echo "enable server app_servers/web1" | socat stdio /var/lib/haproxy/stats
3.4 Shell脚本实现代码滚动升级
[root@proxy /etc/haproxy/conf.d]# cat app.cfg
frontend app_web
bind *:81
mode http
use_backend app_servers
backend app_servers
balance roundrobin
server 10.0.0.39 10.0.0.39:81 weight 2 check inter 3000 fall 2 rise 5
server 10.0.0.49 10.0.0.49:81 weight 2 check inter 3000 fall 2 rise 5
[root@manager ~]# echo "New Deploy Haproxy 10.0.0.39" > index.html.10.0.0.39
[root@manager ~]# echo "New Deploy Haproxy 10.0.0.49" > index.html.10.0.0.49[root@manager ~]# cat deploy.sh
#!/usr/bin/bash
# 集群节点
web_cluster="10.0.0.39 10.0.0.49"
# lb节点IP
lb_server="10.0.0.29"
# 集群资源池名称
cluster="webservers"
# 节点的代码路径
webdir=/proxy
for host in ${web_cluster}
do
# 1.登录负载均衡,动态摘掉节点
ssh root@${lb_server} "echo 'disable server ${cluster}/${host}' | socat stdio /var/lib/haproxy/stats"
# 2.更新节点的代码
scp ./index.html.${host} root@${host}:${webdir}/index.html
sleep 2
# 3.登录负载均衡,动态加入节点
ssh root@${lb_server} "echo 'enable server ${cluster}/${host}' | socat stdio /var/lib/haproxy/stats"
# 4.等待一会在继续下一台
sleep 5
done
[root@manager ~]# chmod +x deploy.sh
[root@manager ~]# while true ; do curl http://10.0.0.29:81 ; sleep 1 ; done
4、后端节点状态监测
对于Haproxy后端节点的状态检测有如下三种方式:
1、基于端口做状态监测,此为默认方式
2、基于指定
URI做状态监测3、基于指定
URI的request请求头部内容做状态监测;
4.1 基于端口监测
检查后端server的TCP端口是否正常,但不能保证该端口上运行的业务是否正常工作。
[root@proxy ~]# vim /etc/haproxy/haproxy.cfg
listen http_proxy
bind *:80
mode http
balance roundrobin
server web1 172.16.1.7:80 check 80 # 基于tcp检测端口
server web2 172.16.1.8:80 check4.2 httpchk参数
option httpchk指令基于http协议来做健康检查,只有返回状态码为2xx或3xx的才认为是健康,其余所有状态码都认为不健康。如果不设置该选项时,默认采用 tcp做健康检查,只要能建立 tcp就表示健康。
option httpchk语法:
option httpchkoption httpchk <uri>:检查的uri路径,默认为/。接受带有查询参数的urioption httpchk <method> <uri>:http检查使用的方法。建议采用HEAD方法。option httpchk <method> <uri> <version>:检查的HTTP协议版本,默认为HTTP/1.0,如果修改为HTTP/1.1,还强制要求指定Host,中间使用\r\n隔离。
4.3 基于URI检测
通过GET方法获取后端节点的资源,基本上可以判断后端服务是否正常工作。
[root@lb01 ~]# vim /etc/haproxy/haproxy.cfg
listen http_proxy
bind *:80
mode http
balance roundrobin
option httpchk GET /index.html # 基于URI,会消耗网络带宽
server web1 172.16.1.7:80 check port 80
server web2 172.16.1.7:80 check port 80
4.3 基于URI头检测
通过request获取的头部信息进行匹配,然后进行健康检测。
将检查的请求发送至后端节点的80端口,然后与Host进行匹配,用来确定该后端节点是否正常。
[root@lb01 ~]# vim /etc/haproxy/haproxy.cfg
listen http_proxy
bind *:80
mode http
balance roundrobin
option httpchk HEAD / HTTP/1.1\r\nHost:\ app.ops.net # head减少网络消耗
server web1 172.16.1.7:80 check port 80
server web2 172.16.1.8:80 check port 80
5、IP地址透传
web服务器中记录客户端的真实IP地址,主要用于访问统计、安全防护、行为分析、区域排行等场景。
5.1 七层负载地址透传
Haproxy工作于反向代理模式,其发往服务器的请求中的客户端 IP 均为Haproxy 主机的地址而非真正客户端的地址,这会使得服务器端的日志信息记录不了真正的请求来源,X-Forwarded-For 首部则可用于解决此问题。
HAProxy可以向每个发往的后端节点添加此首部,并以客户端IP为其value。option forwardfor语法:option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
<network>:可选参数,当指定时,源地址为匹配至此网络中的请求都禁用此功能;<name>:可选参数,可自定义一个首部,如X-Client来替代X-Forwarded-For;if-none:仅在此首部不存在时才将其添加至请求报文中;
option forwardfor示例:
[root@lb01 ~]# vim /etc/haproxy/haproxy.cfg
defaults
option forwardfor # 此为默认值,首部字段默为:X-Forwarded-For
frontend main
bind *:80
mode http
default_backend app
backend app
balance roundrobin
server web 172.16.1.7:80 check
server web 172.16.1.8:80 check检查后端 nginx 日志
172.16.1.5 - - [25/Dec/2020:11:18:36] "GET / HTTP/1.1" 200 18 "-" "curl/7.29.0" "10.0.0.1"
5.2 四层负载地址透传
1、配置Haproxy基于TCP协议访问
[root@proxy /etc/haproxy/conf.d]# vim app.cfg
frontend app_web
bind *:81
mode http
use_backend app_servers
backend app_servers
balance roundrobin
option httpchk HEAD / HTTP/1.1\r\nHost:\ app.ops.net
server 10.0.0.39 10.0.0.39:81 weight 2 check inter 3000 fall 2 rise 5
server 10.0.0.49 10.0.0.49:81 weight 2 check inter 3000 fall 2 rise 5
frontend main
bind *:899
mode tcp
default_backend app
backend app
balance roundrobin
mode tcp
server web 10.0.0.39:889 check send-proxy2、配置后端web节点
[root@web1 ~]# vi /etc/nginx/nginx.conf
http {
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$proxy_protocol_addr"';
#nginx配置:变量$proxy_protocol_addr 记录透传过来的客户端IP
[root@web1 ~]# cat /etc/nginx/conf.d/main.ops.net.conf
server {
listen 889 proxy_protocol;
server_name main.ops.net;
location / {
root /web;
index index.html;
}
}3、检查后端节点日志
[root@lb01 ~]# tail -f /var/log/nginx/access.log
172.16.1.3 - - [25/Dec/2020:11:18:36] "GET / HTTP/1.1" 200 18 "-" "curl/7.29.0" "10.0.0.1"
6、自定义Haproxy日志
在 HAProxy 中,可以使用 capture来捕获 HTTP 请求或响应的头部(Header)信息。然后将这些捕获的信息写入日志文件中。
1、可以选择记录请求头部(
request header)或响应头部(response header)中的特定信息;2、例如捕获
Host,Content-length,User-agent,X-Forwarded-For等;3、最后还需要指定对应
Header的值保留的长度;
在日志中,这些头部信息被括在花括号 {} 中,如果有多个捕获的头部,它们会按照顺序出现,彼此之间用竖线 | 分隔。如果请求或响应中不存在指定的头部,日志将会记录一个空字符串代表这个头部的值。
capture语法: capture [request|response] header <name> len <length>
<name>:要捕获的名称,不区分大小写。注意:记录在日志中是首部对应的值,而非首部名称。<length>:指定记录首部值的字符长度,超出的部分将会被忽略。
6.1 配置示例
1、捕获Request中的Host、User-Agent、以及response中的Server
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
capture request header Host len 40 # 捕捉请求的域名
capture request header User-Agent len 16 # 捕捉请求的设备
capture response header Server len 40 # 捕捉响应的Server是什么
use_backend webcluster
backend webcluster
balance roundrobin
server web1 172.16.1.7:80 check
server web2 172.16.1.8:80 check6.2 验证日志
日志文件中,关注{}中内容,第一个{}是request,第二个{}是response
haproxy: 10.0.0.100:48132 main webcluster/web2 {proxy.ops.net|curl/7.29.0}
haproxy: 10.0.0.100:48132 main webcluster/web2 {proxy.ops.net|curl/7.29.0} {nginx/1.18.0}
Nov 16 10:29:00 localhost haproxy[991]: 10.0.0.244:55896 [16/Nov/2025:10:29:00.574] proxy proxyservers/web02 0/0/0/1/1 200 202 - - ---- 2/2/0/0/0 0/0 {10.0.0.9|Mozilla/5.0 (Win} {nginx/1.20.1} "GET / HTTP/1.1"7、自定义错误页面
Haprony自定义错误页面有两种方式
第一种:由
haproxy本机提供错误页面,通过errorfile参数来设定。第二种:将错误转到一个指定的
url地址,通过errorcode参数来设定。
7.1 errorfile
1、通过errorfile将错误交给本机haproxy处理,修改haproxy配置
[root@haproxy ~]# cat /etc/haproxy/haproxy.cfg
defaults
...
errorfile 503 /opt/503.http2、准备503对应的错误页面,需要添加头部信息;
[root@haproxy ~]# vim /opt/503.http
HTTP/1.1 503
Content-Type:text/html;charset=utf-8
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>报错页面</title>
</head>
<body>
<center><h1>网站维护中........请稍候再试</h1></center>
<center><h2>联系 haoge 处理解决</h2></center>
<center><h3>503 Service Unavailable</h3></center>
</body>
</html>3、测试将后端的web服务器停止后测试

7.2 errorloc
1、使用 errorloc 选项来捕捉错误状态码,然后将其重定向到其他url
[root@haproxy ~]# cat /etc/haproxy/haproxy.cfg
defaults
...
errorloc 503 http://10.0.0.19/error/2、测试页面代码
[root@web1 /usr/share/nginx/html/error]# cat index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>404 Not Found</title>
<style>
/* 全局样式重置(可选) */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #fff; /* 页面背景色 */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh; /* 让页面垂直居中 */
}
/* 容器:控制整体布局 */
.container {
width: 80%;
max-width: 1000px;
display: flex;
flex-direction: row; /* 横向排列左中右 */
align-items: center;
justify-content: space-between;
padding: 20px;
}
/* 左侧/右侧区域:表情+文字 */
.left-section,
.right-section {
display: flex;
flex-direction: column;
align-items: center;
}
.left-section img,
.right-section img {
width: 150px; /* 表情宽度,可自定义 */
height: 150px; /* 表情高度,可自定义 */
object-fit: contain; /* 保持比例 */
margin-bottom: 10px;
}
.left-text,
.right-text {
font-size: 18px;
color: #333; /* 文字颜色 */
line-height: 1.5;
}
/* 中间区域:错误标题+按钮 */
.middle-section {
text-align: center;
}
.error-title {
font-size: 20px;
color: #333;
margin-bottom: 20px;
}
.btn-group {
display: flex;
gap: 10px; /* 按钮间距 */
}
.btn {
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
text-decoration: none;
font-size: 14px;
border: 1px solid transparent;
}
/* 主按钮(返回首页)样式 */
.btn-primary {
background-color: #ff5722; /* 橙色,可自定义 */
color: #fff;
border-color: #ff5722;
}
/* 辅助按钮(保证不打死管理员)样式 */
.btn-default {
background-color: #fff;
color: #333;
border-color: #ccc;
}
/* 响应式:手机端自动切换为纵向布局 */
@media (max-width: 768px) {
.container {
flex-direction: column;
width: 90%;
}
.left-section,
.middle-section,
.right-section {
margin-bottom: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<!-- 左侧:表情+文字 -->
<div class="left-section">
<!-- 替换为你自己的表情包地址 -->
<img src="./images/2.gif" alt="左侧表情" />
<p class="left-text">卧槽!页面不见了!</p>
</div>
<!-- 中间:错误标题+按钮 -->
<div class="middle-section">
<h2 class="error-title">404错误!抱歉您要找的页面不存在</h2>
<div class="btn-group">
<a href="#" class="btn btn-primary">返回首页</a>
<a href="#" class="btn btn-default">保证不打死管理员</a>
</div>
</div>
<!-- 右侧:表情+文字 -->
<div class="right-section">
<!-- 替换为你自己的表情包地址 -->
<img src="./images/1.gif" alt="右侧表情" />
<p class="right-text">兄弟<br>莫激动</p>
</div>
</div>
</body>
</html>
[root@web1 /usr/share/nginx/html/error]# ls
images index.html
[root@web1 /usr/share/nginx/html/error]# ls images/
1.gif 2.gif3、测试访问haproxy,会发现请求被重定向到新的uri

8、自定义HTTP报文
8.1 http-request
使用 http-request add-header 可以在请求报文中添加一个Header,实现原理client-->haproxy(添加请求Header)--> web
1、在 frontend 中使用 http-request add-header,给后端节点发送一个X-via的Header
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:88
mode http
http-request add-header X-via Haproxy-Node1 # HeaderName HeaderValue
use_backend webcluster
[root@lb01 ~]# systemctl reload haproxy2、修改后端 nginx.conf 中 logformat 添加 "$http_x_via"
[root@web ~]# vim /etc/nginx/nginx.conf
http {
...
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for" "$http_x_via"';
...
}
[root@web ~]# systemctl reload nginx3、再次访问,检查后端 Nginx 日志,此时就能会看到是通过哪个调度器,调度到本机
10.0.0.9 - - [16/Nov/2025:10:54:31 +0800] "GET / HTTP/1.1" 200 5 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" "10.0.0.244" "Haproxy-Node1"
10.0.0.9 - - [16/Nov/2025:10:54:35 +0800] "GET / HTTP/1.1" 200 5 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36" "10.0.0.244" "Haproxy-Node1"8.2 http-response
使用 http-response add-header 可以在响应报文中添加一个Header,实现原理web-->haproxy--(添加响应Header)-->client
1、在 frontend 中使用 http-response add-header,告诉客户端资源经过了哪个代理服务。
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
http-response add-header Res-Server Haproxy-3.0
use_backend webcluster
[root@lb01 ~]# systemctl reload haproxy2、客户端访问测试,然后检查响应 Header

8.3 http-response del
使用 http-response del-header 可以在响应报文中删除一个Header,实现原理web-->haproxy--(删除Header)-->client
1、在 frontend 中使用 http-response del-header,删除后端Server的版本信息。
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
http-response add-header Res-Server Haproxy-3.0
http-response del-header Server # 删除返回给客户端的Header字段
use_backend webcluster
[root@lb01 ~]# systemctl reload haproxy2、客户端访问测试,然后检查响应 Header

03 Haproxy调度算法
1、调度算法介绍
Haproxy 根据后端服务器的负载,或其他的计算的标准,判断挑选哪台 RS来进行请求处理。
Haproxy 调度算法语法,可用于 defaults、listen、backend ;
balance <algorithm|算法> [ <arguments> ]
balance url_param <param> [check_post [<max_wait>]]2、roundrobin
roundrobin :基于权重进行轮询,保持均匀分布,这是最平衡、最公平的算法。
此算法是动态的,表示其权重可以在运行时通过socat方式进行动态调整,不过,在设计上,每个后端服务器仅能最多接受 4128 个连接;
2.1 配置示例
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
use_backend webcluster
backend webcluster
balance roundrobin
server web1 172.16.1.7:80 check
server web2 172.16.1.8:80 check2.2 调度测试
[root@client ~]# curl -HHost:proxy.ops.net http://10.0.0.5:80
Web Page RS-Node1
[root@client ~]# curl -HHost:proxy.ops.net http://10.0.0.5:80
Web Page RS-Node22.3 动态调整
通过 socat 命令动态调整权重,将 web1 节点的权重调整为 3
# 查看当前权重
[root@proxy /etc/haproxy]# echo "get weight proxyservers/web01" | socat stdio /var/lib/haproxy/stats
1 (initial 1)
[root@proxy /etc/haproxy]# echo "get weight proxyservers/web02" | socat stdio /var/lib/haproxy/stats
1 (initial 1)
# 调整web1权限为3,调整后测试,会发现立即⽣效
[root@proxy /etc/haproxy]# grep socket haproxy.cfg
stats socket /var/lib/haproxy/stats mode 600 level admin
[root@proxy /etc/haproxy]# echo "set weight proxyservers/web01 2" | socat stdio /var/lib/haproxy/stats
[root@proxy /etc/haproxy]# echo "get weight proxyservers/web01" | socat stdio /var/lib/haproxy/stats
2 (initial 1)3、static-rr
static-rr :轮询调度算法,此算法是静态的,表示其权重不可以在运行时进行调整;
3.1 配置示例
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
use_backend webcluster
backend webcluster
balance static-rr
server web1 172.16.1.7:80 check weight 2
server web2 172.16.1.8:80 check weight 13.2 调度示例
[root@client ~]# curl -HHost:proxy.ops.com http://10.0.0.5:80
Web Page RS-Node1
[root@client ~]# curl -HHost:proxy.ops.com http://10.0.0.5:80
Web Page RS-Node1
[root@client ~]# curl -HHost:proxy.ops.com http://10.0.0.5:80
Web Page RS-Node24、leastconn
leastconn :新的连接请求被派发至具有最少连接数目的后端服务器;
此算法是动态的,可以在运行时调整其权重;
4.1 配置示例
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
use_backend webcluster
backend webcluster
balance leastconn
server web1 172.16.1.7:80 check
server web2 172.16.1.8:80 check4.2 调度测试
5、source
source :源地址 hash 调度算法,将请求的源地址进行 hash 运算,得到⼀个具体的数值,同时对后端服务器进行编号,按照运算结果将请求分发到对应编号的服务器上。
这可对不同源 IP 的访问进行负载分发,对同⼀个客户端 IP 的请求始终被派发至某特定的服务器。
注意:如某服务器宕机或新添加了服务器,许多客户端的请求可能会被派发至与此前请求不同的服务器;不过也可以使用 hash-type 修改此特性;
5.1 配置示例
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
use_backend webcluster
backend webcluster
balance source
# hash-type { map-based | consistent }
server web1 172.16.1.7:80 check
server web2 172.16.1.8:80 check5.2 调度测试
[root@client ~]# curl -HHost:proxy.ops.com http://10.0.0.5:80
Web Page RS-Node1
[root@client ~]# curl -HHost:proxy.ops.com http://10.0.0.5:80
Web Page RS-Node16、uri
uri :基于对用户请求的 uri 做 hash 并将请求转发到后端指定服务器。
理解:同⼀个节点访问不同的 uri 可能会被调度到不同的后端服务器处理,但是不同的节点访问相同的 uri 则会被调度到同⼀台服务器处理,因为基于uri 调度是在服务端完成的而非客户端。
这种调度算法多用在缓存场景,能有效提高命中率。
注意,此算法仅应用于 HTTP 后端服务器场景;其默认为静态算法,不过也可以使用 hash-type 修改此特性;
6.1 ⻚⾯准备
后端集群 uri ⻚⾯准备
# web1
[root@web01 ~]# mkdir /opt/{app1,app2} -p
[root@web01 ~]# echo "web1 app1" > /opt/app1/index.html
[root@web01 ~]# echo "web1 app2" > /opt/app2/index.html
# web2
[root@web02 ~]# mkdir /opt/{app1,app2} -p
[root@web02 ~]# echo "web2 app1" > /opt/app1/index.html
[root@web02 ~]# echo "web2 app2" > /opt/app2/index.html6.2 配置示例
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
use_backend webcluster
backend webcluster
balance uri
# hash-type { map-based | consistent }
server web1 172.16.1.7:80 check
server web2 172.16.1.8:80 check6.3 调度测试
client 测试,访问不同 url 测试,不同 uri 会被调度到不同的后端节点处理;
# 请求app1资源,发现是web2提供
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80/app1/index.html
web2 app1
# 请求app2资源,发现是web1提供
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80/app2/index.html
web1 app2更换其他 Client 测试,使用不同的节点,但请求相同 uri 会调度到同⼀后端服务器处理;
[root@route ~]# curl -HHost:proxy.ops.com http://10.0.0.5:80/app1/index.html
web2 app1
[root@route ~]# curl -HHost:proxy.ops.com http://10.0.0.5:80/app2/index.html
web1 app27、url
url_param ,它允许根据请求 URL 中指定的查询参数的值来进行哈希计算。例如,使用 user 参数来进行哈希,那么 user 参数值相同的请求,都会被路由到同⼀台后端服务器。这样,即便是分布在多个请求中,用户的会话也能保持⼀致性。
url_params 调度算法配置示例,(基于用户请求中携带的 user 做 hash)
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
use_backend webcluster
backend webcluster
balance url_param user
# hash-type { map-based | consistent }
server web1 172.16.1.7:80 check
server web2 172.16.1.8:80 check7.1 调度测试
Client 测试,不带参数请求,默认为轮询调度
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80
Web Page RS-Node1
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80
Web Page RS-Node2Client 测试,携带相同的 User 参数请求,会发现始终定向到同⼀台后端节点
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80?user=ops
Web Page RS-Node1
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80?user=ops
Web Page RS-Node1
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80?user=ops
Web Page RS-Node1Client 测试,携带不同的 User 参数请求,发现可能会调度到不同的节点
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80?user=jason
Web Page RS-Node2
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80?user=jack
Web Page RS-Node2
[root@client ~]# curl -HHost:proxy.ops.com 172.16.1.5:80?user=it
Web Page RS-Node18、hdr
hdr(<name>) :针对用户发起 HTTP 请求中 Header 中的 <name> 关键字进行 hash 计算,如⽆有效的值,则会被轮询调度;
此算法默认为静态的,不过其也可以使用 hash-type 修改此特性;(使用较少)
8.1 配置示例
hdr(<name>) 调度算法配置示例(基于客户端浏览器来调度)
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend main
bind *:80
mode http
use_backend webcluster
backend webcluster
balance hdr(User-Agent)
# hash-type { map-based | consistent }
server web1 172.16.1.7:80 check
server web2 172.16.1.8:80 check8.2 调度测试
client 测试,置空 User-Agent 字段,会发现进⼊了轮询。
[root@client ~]# curl -A '' -HHost:proxy.ops.com 172.16.1.5:80
Web Page RS-Node1
[root@client ~]# curl -A '' -HHost:proxy.ops.com 172.16.1.5:80
Web Page RS-Node2client 测试,通过 curl 命令模拟⾕歌,发现调度到 web2 节点。
[root@client ~]# curl -A 'Chrome' -H Host:proxy.ops.com 172.16.1.5:80
web14.使用 Chrome 浏览器测试访问,经过 hash 取模后发现依然会调度到 web1 节点。

9、hash_type
hash-type <method> 用于将 hash 映射至后端服务器的方法;
可用方法有 map-based|consistent ;
⼤多数场景下使用默认 map-based 方法;
9.1 map-based
map-based 算法实现公式: hash(ip) % node_counts = index

map-based 算法问题:如果下线⼀台节点,会出现重新计算 hash 值,造成⼤规模变化。

9.2 consistent
consistent :⼀致性哈希,该 hash 是动态的,当服务器节点下线,或新增⼀台节点,对调度结果影响是局部的,不会引起⼤的变动。
⼀致性 Hash 算法也是使用取模的方法,但不是对服务器节点数量进行取模,而是对 2的32方 取模。即,⼀致性 Hash 算法将整个 Hash 空间组织成⼀个虚拟的圆环, Hash 函数值的空间为 0 ~ 2^32 - 1 ,整个哈希环如下:
一致性Hash文档 → 📎consistent.pdf
Hash算法原理
Hash算法增加节点
Hash算法减少节点
Hash算法数据倾斜问题
backend proxyservers
balance source
hash-type consistent04 Haproxy ACL实践
1、ACL基本概述
1.1 什么是ACL
ACL 在 HAProxy 中是用来决定请求如何被处理的⼀种规则。我们可以将其想象成⼀个检查站,每个过往的请求都要经过这个检查站,而 ACL 就是检查员,根据⼀些特定的标准来判断请求是否符合某种条件。在 HAProxy 中使用 ACL,通常涉及以下两个步骤:
1、定义ACL 规则: 即定义⼀个测试条件,条件可以是请求报文中的源地址、源端口、目标地址、目标端口、请求方法、 URL 、文件后缀等;这些条件是我们用来识别和分类流量的依据。
举个例子,如果我们想识别所有请求 /admin 管理⻚⾯的流量,我们可以定义如下这样ACL规则
acl is_admin_page path_beg /admin
# is_admin_page 是我们给这个条件起的名字、path_beg 指的是请求的路径开头部分、/admin 则是路径的具体内容2、 定义好条件后,我们要告诉 HAProxy 当条件满足时应该做什么。这个“做什么”可以是将流量引导到特定的服务器,也可以是拒绝请求。例如:当请求满足is_admin_page 这个条件时,把请求发送到名叫 admin_servers 的服务器组。
use_backend admin_servers if is_admin_page总的来说,ACL 就是设置的⼀系列规则,这些规则基于请求的信息来决定应该采取什么行动。
整个流程就像是:请求来了 -> ACL 检查请求 -> 根据规则执行相应的动作。
这样我们就可以根据请求的特征来决定如何处理它们。
1.2 ACL定义方法
# ACL语法
acl <aclname> <criterion> [flags] [operator] [<value>] ...
#acl 名称 条件 条件标记位 具体操作符 操作对象类型
# ACL示例
acl my_chrome hdr(User-Agent) -i -m sub Chrome<aclname> : ACL 名称,可使用字⺟ 数字 : . - _ 区分字符⼤⼩写<criterion> : 比较的标准和条件
基于源地址、源端口、目标地址、目标端口: src、src_port、dst、dst_port
基于 Header 信息比对: hdr、hdr_beg、hdr_end、hdr_dom
基于路径或后缀比对: path_beg、path_end
基于请求的方法比对: method
<flags> :条件标记
-i 不区分⼤⼩写
-m 使用 pattern 匹配方法
-n 不做 DNS 解析
-u 禁⽌ acl 重名,否则多个同名的 ACL 为或的关系
[operator] :条件筛选
-eq(等于)、-ne(不等于)、-ge(⼤于或等于)、-le(⼩于或等于)、gt(⼤于)、lt(⼩于)
(-m str) :字符串必须完全匹配模式
(-m sub) :在提取的字符串中查找,如果其中任何⼀个被发现, ACL 将匹配
(-m beg) :在提取的字符串⾸部中查找,如果其中任何⼀个被发现, ACL 将匹配
(-m end) :在提取的字符串尾部中查找,如果其中任何⼀个匹配,则 ACL 进行匹配
(-m dir) :提取用斜线 / 分隔的字符串,如果其中任何⼀个匹配,则 ACL 进行匹配
(-m dom) :提取用点的 . 分隔字符串,如果其中任何⼀个匹配,则 ACL 进行匹配
<value> :条件目标
布尔值:比如, false,true
整数或整数范围,比如用于匹配端口范围: 1024~32768
IP 地址或 IP 范围: 192.168.0.1 ~ 192.168.0.1/24
字符串:比如匹配 URL 路径, /static、/images
1.3 ACL基于路径匹配示例
1、 path_beg <string> :用于测试请求的 URL 是否以 <string> 指定的字符串开头。
# 匹配URL以/static、/images、/javascript开头的
acl url_static path_beg -i /static /images /javascript2、 path_end <string> :用于测试请求的 URL 是否以 <string> 指定的字符串结尾。
# 示例:下⾯的例子用户测试URL是否以jpg、gif、png、css或js结尾。
acl url_static path_end -i .jpg .gif .png .css .js1.4 ACL基于域名匹配示例
1、 hdr_beg 用于测试请求报文指定的header字段,开头部分是否符合给定的字符串模式。
# 示例:测试请求的host开头是否为,img、video、static
acl host_img hdr_beg(host) -i img.
acl host_video hdr_beg(host) -i video.
acl host_static hdr_beg(host) -i static.2、 hdr_end 用于测试请求报文指定的Header字段,结尾部分是否符合给定的字符串模式。
# 示例:测试请求的host的结尾是否为,.com .net .cn
acl host_com hdr_end(host) -i .com
acl host_net hdr_end(host) -i .net
acl host_cn hdr_end(host) -i .cn3、 hdr_dom(host) 用于匹配请求的 host 头部字段是否包含指定的域名。
# 示例:测试请求的host是否为 www.ops.com
acl my_www_host hdr_dom(host) -i www.ops.net4、 hdr 用于匹配指定的请求Header字段,是否包含特定的字符串。
# 示例:请求的User-Agent是否为Chrome
acl my_chhrome hdr(User-Agent) -m sub -i Chrome2、ACL逻辑关系
在配置 HAProxy 时,可能会遇到需要基于“多个条件”来控制流量的情况。为了灵活地实现这些条件,HAProxy 允许组合使用多个 ACL。这些 ACL 之间可以通过逻辑运算符 and、or 和 not 来组合。
2.1 与(AND)关系示例
当希望⼀个动作只在多个条件“同时满足”时才执行时,可以使用逻辑“与”。默认情况下多个 ACL 它们之间就是逻辑“与”的关系。
示例:只有当 acl1 和 acl2 同时满足时,相关的操作才会执行。
1、定义了两个 ACL:acl1 检查请求的 host 是否为 www.ops.com;acl2检查请求的路径是否以 /admin 开头。
2、当这两个条件都满足时(即请求来自 www.ops.net 且以 /admin 开头),流量才会被发送到 backend_admin。
acl acl1 hdr_dom(host) -i www.ops.net
acl acl2 path_beg -i /admin
use_backend backend_admin if acl1 acl22.2 或(OR)关系示例
有时候希望当多个条件中的任意⼀个满足时就执行某个动作。在这种情况下可以使用逻辑“或”。使用运算符 or 或 || 来表示。
示例,只要 acl1 或 acl2 中的任意⼀个满足,相关的操作就会执行。
1、定义了两个 ACL:acl1 检查请求的 host 是否为 www.ops.net;acl2 检查请求的 host 是否为 api.ops.net。
2、在 use_backend 指令中,如果请求的 host 是 www.ops.net 或者api.ops.com 中的任意⼀个,流量将被发送到 webservers。
acl acl1 hdr_dom(host) -i www.ops.net
acl acl2 hdr_dom(host) -i api.ops.net
use_backend webservers if acl1 || acl22.3 非(NOT)关系示例
如果想要在某个条件“不满足”时执行动作,可以使用逻辑“非”。在 ACL 前⾯加上 ! 代表取反。
示例,如果 acl1 不满足,相关的操作才会执行。
1、定义了⼀个 ACL:acl1 检查请求的 host 是否为 www.ops.net
2、如果请求不是来自 www.ops.net,流量将被发送到 backend_other
acl acl1 hdr_dom(host) -i www.ops.net
use_backend backend_other if ! acl13、ACL实现访问控制
3.1 基于HTTP访问控制
配置七层的请求访问控制;只能用在 mode http 中;
http-request { allow | deny } [ { if | unless } <condition> ]
示例:仅允许 10.0.0.1 访问 haproxy 的 stats
listen haproxy-stats
bind *:9999
stats enable
stats hide-version
stats uri /haproxy-stats
stats realm "HAProxy statistics"
stats auth admin:123456
stats admin if TRUE
# 除 10.0.0.244 以外的用户全部拒绝
acl all_ip src 10.0.0.244
http-request deny if ! all_ip
# 拒绝使用curl
acl method_curl hdr(User-Agent) -m sub -i curl
http-request deny if method_curl
[root@rocky9 ~]# curl http://10.0.0.9:9999
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
</body></html>3.2 基于TCP访问控制
配置四层的请求访问控制;只能用在 mode tcp 中;
tcp-request connection {accept|reject} [{if | unless} <condition>]
示例:拒绝来源 tcp 应用,比如 SSH
listen ssh
bind *:2222
mode tcp
balance roundrobin
server web01 10.0.0.19:22 check
server web02 10.0.0.29:22 check
acl invalid_src src 10.0.0.49 #定义acl匹配规则
tcp-request connection reject if invalid_src #在四层拒绝满足名为invalid_src的acl匹配规则
4、ACL案例-基于域名调度
根据用户请求不同的域名,调度到不同的后端集群。
用户请求 www.ops.net 调度到 172.16.1.7:80,172.16.1.8:80
用户请求 m.ops.net 调度到 172.16.1.7:8080,172.16.1.8:8080
4.1 配置后端节点
# www站点定义(所有web节点配置⼀致)
[root@web01 ~]# vi /etc/nginx/conf.d/www.ops.net.conf
server {
listen 80;
server_name www.ops.net;
root /opt;
location / {
index index.html;
}
}
[root@web01 ~]# echo "www.ops.com-->web1" > /opt/index.html
[root@web01 ~]# echo "www.ops.com-->web2" > /opt/index.html
# m站点定义所有web节点配置⼀致)
[root@web01 ~]# vi /etc/nginx/conf.d/m.ops.net.conf
server {
listen 8080;
server_name m.ops.net;
root /mnt;
location / {
index index.html;
}
}
[root@web01 ~]# echo "m.ops.net-->web1" > /mnt/index.html
[root@web01 ~]# echo "m.ops.net-->web2" > /mnt/index.html4.2 配置Haproxy
[root@lb01 ~]# cat cat/etc/haproxy/haproxy.cfg
#----------------------------------------------------------------
# main frontend which proxys to the backends
#----------------------------------------------------------------
frontend main
bind *:80
mode http
# 定义ACL规则(请求www,则被my_www规则匹配,请求m,则被my_m⻤规则匹配)
acl my_www hdr(host) -i www.ops.net
acl my_m hdr(host) -i m.ops.net
# 调用ACL规则(如果来源www则调度至www_site集群处理,如果请求来源m,则调度至m_site集群处理)
use_backend www_site if my_www
use_backend m_site if my_m
# 如果ACL都没有匹配成功,则默认调度www站点
use_backend my_www
#----------------------------------------------------------------
# round robin balancing between the various backends
#----------------------------------------------------------------
backend www_site
balance roundrobin
server web1 172.16.1.7:80 check port 80
server web2 172.16.1.8:80 check port 80
backend m_site
balance roundrobin
server web1 172.16.1.7:8080 check port 8080
server web2 172.16.1.8:8080 check port 8080
backend my_www
balance roundrobin
server web1 172.16.1.7:88 check4.3 客户端测试
Client 客户端测试访问,请求 www 站点测试
[root@client ~]# curl -HHost:www.ops.net http://10.0.0.5:80
www.ops.com-->web1
[root@client ~]# curl -HHost:www.ops.net http://10.0.0.5:80
www.ops.com-->web2Client 客户端测试访问,请求 m 站点测试
[root@client ~]# curl -HHost:m.ops.net http://10.0.0.5:80
www.ops.com-->web1
[root@client ~]# curl -HHost:m.ops.net http://10.0.0.5:80
www.ops.com-->web25、ACL案例-基于设备调度
根据用户请求的 User-Agent ,调度到不同的后端集群。
用户通过 Chrome 调度到 172.16.1.7:80
用户请求 Firefox 调度到 172.16.1.8:80
5.1 配置后端节点
# web1:Chrome站点定义
[root@web01 ~]# cat /etc/nginx/conf.d/www.ops.net.conf
server {
listen 80;
server_name www.ops.net;
root /opt;
location / {
index index.html;
}
}
[root@web01 ~]# echo "Chrome-->web1" > /opt/index.html
# web2:Firefox站点定义
[root@web01 ~]# cat /etc/nginx/conf.d/www.ops.net.conf
server {
listen 80;
server_name www.ops.net;
root /opt;
location / {
index index.html;
}
}
[root@web01 ~]# echo "Firefox-->web2" > /opt/index.html5.2 配置Haproxy
编辑 Haproxy 配置文件 (注释之前的ACL规则)
[root@lb01 ~]# cat cat/etc/haproxy/haproxy.cfg
#----------------------------------------------------------------
# main frontend which proxys to the backends
#----------------------------------------------------------------
frontend main
bind *:80
mode http
# 定义ACL规则
# 浏览器为Chrome,则被my_chrome规则匹配
# 浏览器为Firefox,则被my_firefox规则匹配
acl my_chrome hdr(User-Agent) -m sub -i Chrome
acl my_firefox hdr(User-Agent) -m sub -i Firefox
# 调用ACL规则
# 如果来源设备为Chrome则调度至www_site集群处理
# 如果来源设备为Firefox则调度至m_site集群处理
use_backend chrome_site if my_chrome
use_backend firefox_site if my_firefox
# 如果ACL都没有匹配成功,则默认调度chrome_site站点
use_backend chrome_site
#----------------------------------------------------------------
# round robin balancing between the various backends
#----------------------------------------------------------------
backend chrome_site
balance roundrobin
server web1 172.16.1.7:80 check port 80
backend firefox_site
balance roundrobin
server web2 172.16.1.8:80 check port 805.3 客户端测试
Client 客户端测试访问,使用 Chrome 和 Firefox 浏览器进行测试
[root@client ~]# curl -A "Chrome" -HHost:www.ops.net http://10.0.0.5:80
Chrome-->web1
[root@client ~]# curl -A "Firefox" -HHost:www.ops.net http://10.0.0.5:80
Firefox-->web26、ACL案例-基于路径调度
根据用户请求的 URL ,调度到不同的后端集群。
用户通过 /static 调度到 172.16.1.7:80
用户请求 /user 调度到 172.16.1.8:80
6.1 配置后端节点
# web1:/static站点定义
[root@web01 ~]# cat /etc/nginx/conf.d/www.ops.net.conf
server {
listen 80;
server_name www.ops.net;
root /opt;
location / {
index index.html;
}
}
[root@web01 ~]# mkdir /opt/static
[root@web01 ~]# echo "static-web1" > /opt/static/index.html
# web2:/user站点定义
[root@web01 ~]# cat /etc/nginx/conf.d/www.ops.net.conf
server {
listen 80;
server_name www.ops.net;
root /opt;
location / {
index index.html;
}
}
[root@web02 conf.d]# mkdir /opt/user
[root@web02 conf.d]# echo "user-web2" > /opt/user/index.html6.2 配置Haproxy
[root@lb01 ~]# cat cat/etc/haproxy/haproxy.cfg
#----------------------------------------------------------------
# main frontend which proxys to the backends
#----------------------------------------------------------------
frontend main
bind *:80
mode http
# 定义ACL规则
# 请求url为/static,则被path_static规则匹配
# 请求url为/user,则被path_user规则匹配
acl path_static path_beg -i /static /images
acl path_user path_beg -i /user
# 调用ACL规则
# 如果来源URL为/static则调度至static_site集群处理
# 如果来源URL为/user则调度至user_site集群处理
use_backend static_site if path_static
use_backend user_site if path_user
# 如果ACL都没有匹配成功,则默认调度user_site站点
use_backend user_site
#----------------------------------------------------------------
# round robin balancing between the various backends
#----------------------------------------------------------------
backend static_site
balance roundrobin
server web1 172.16.1.7:80 check port 80
backend user_site
balance roundrobin
server web2 172.16.1.8:80 check port 806.3 客户端访问
Client 客户端测试访问,请求不同的 URL 测试调度效果
[root@client ~]# curl -HHost:www.ops.com http://10.0.0.5:80/static/
static-web1
[root@client ~]# curl -HHost:www.ops.com http://10.0.0.5:80/user/
user-web27、ACL案例-基于后缀调度
根据用户请求的后缀,调度到不同的后端集群。
用户通过 .txt 调度到 172.16.1.7:80
用户请求 .pdf 调度到 172.16.1.8:80
7.1 配置后端节点
# web1:.txt站点定义
[root@web01 ~]# cat /etc/nginx/conf.d/www.ops.net.conf
server {
listen 80;
server_name www.ops.net;
root /opt;
location / {
index index.html;
}
}
[root@web01 ~]# echo ".txt--web1" > /opt/web.txt
# web2:.pdf站点定义
[root@web01 ~]# cat /etc/nginx/conf.d/www.ops.net.conf
server {
listen 80;
server_name www.ops.net;
root /opt;
location / {
index index.html;
}
}
[root@web02 conf.d]# echo ".pdf--web2" > /opt/web.pdf7.2 配置Haproxy
[root@lb01 ~]# cat cat/etc/haproxy/haproxy.cfg
#----------------------------------------------------------------
# main frontend which proxys to the backends
#----------------------------------------------------------------
frontend main
bind *:80
mode http
# 定义ACL规则
# 请求文件为.txt,则被path_txt规则匹配
# 请求文件为.pdf,则被path_pdf规则匹配
acl path_txt path_end -i .txt
acl path_pdf path_end -i .pdf
# 调用ACL规则
# 如果请求文件为.txt 则调度至txt_site集群处理
# 如果来源文件为.pdf 则调度至pdf_site集群处理
use_backend txt_site if path_txt
use_backend pdf_site if path_pdf
# 如果ACL都没有匹配成功,则默认调度txt_site站点
use_backend txt_site
#----------------------------------------------------------------
# round robin balancing between the various backends
#----------------------------------------------------------------
backend txt_site
balance roundrobin
server web1 172.16.1.7:80 check port 80
backend pdf_site
balance roundrobin
server web2 172.16.1.8:80 check port 807.3 客户端访问
Client 客户端测试访问,请求不同类型文件测试调度效果
[root@client ~]# curl -HHost:www.ops.net http://10.0.0.5:80/web.txt
.txt--web1
[root@client ~]# curl -HHost:www.ops.net http://10.0.0.5:80/web.pdf
.pdf--web28、ACL案例-实现动静分离
动静分离示例:
global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon
# turn on stats unix socket
stats socket /var/lib/haproxy/stats
defaults
mode http
log global
option httplog
option dontlognull
option http-server-close
option forwardfor except 127.0.0.0/8
option redispatch
retries 3
timeout http-request 10s
timeout queue 1m
timeout connect 10s
timeout client 1m
timeout server 1m
timeout http-keep-alive 10s
timeout check 10s
maxconn 30000
listen stats
mode http
bind 0.0.0.0:1080
stats enable
stats hide-version
stats uri /haproxyadmin?stats
stats realm Haproxy\ Statistics
stats auth admin:admin
stats admin if TRUE
frontend http-in
bind *:80
mode http
log global
capture request header Host len 20
capture request header Referer len 60
acl url_static path_beg -i /static /images /javascript /stylesheets
acl url_static path_end -i .jpg .jpeg .gif .png .css .js
use_backend static_servers if url_static
default_backend dynamic_servers
backend static_servers
balance roundrobin
server imgsrv1 172.16.200.7:80 check maxconn 6000
server imgsrv2 172.16.200.8:80 check maxconn 6000
backend dynamic_servers
cookie srv insert nocache
balance roundrobin
server websrv1 172.16.200.7:80 check maxconn 1000 cookie websrv1
server websrv2 172.16.200.8:80 check maxconn 1000 cookie websrv2
server websrv3 172.16.200.9:80 check maxconn 1000 cookie websrv305 Haproxy场景实践
1.配置MySQL负载均衡
用户请求 3366 端口,调度到 172.16.1.7:3306、172.16.1.8:3306
1.1 配置MySQL
1.后端节点 MySQL 配置如下
[root@web01 ~]# yum install mysql mysql-server -y
[root@web01 ~]# systemctl start mysqld
# 用户all、密码xx
mysql> create user proxy@'%' identified by 'proxy.net';
mysql> grant all privileges on *.* to proxy@'%';1.2 配置Haproxy
配置 Haproxy 为 TCP 模式,代理 MySQL
[root@lb01 ~]# cat /etc/haproxy/conf.d/mysql.cfg
frontend mysql
bind *:3366
mode tcp
use_backend mysql_servers
backend mysql_servers
mode tcp
balance roundrobin
server node1 172.16.1.7:3306 check port 3306
server node2 172.16.1.8:3306 check port 33061.3 客户端测试
Client 客户端测试
[root@client ~]# yum install mysql -y
# 第⼀次登陆测试
[root@client ~]# mysql -h10.0.0.200 -uall -p123456 -P3366
mysql> select @@hostname;
+------------+
| @@hostname |
+------------+
| web01 |
+------------+
1 row in set (0.01 sec)
# 第⼆次登陆测试
[root@client ~]# mysql -h10.0.0.200 -uall -p123456 -P3366
mysql> select @@hostname;
+------------+
| @@hostname |
+------------+
| web02 |
+------------+
1 row in set (0.01 sec)2.配置HTTP负载均衡
用户请求 www.ops.net 调度到 172.16.1.7:80,172.16.1.8:80
2.1 配置web节点
2.2 配置Haproxy
[root@lb01 ~]# cat /etc/haproxy/haproxy.cfg
frontend www
bind *:80
mode http
acl my_www hdr(host) -i www.ops.net
use_backend www_site if my_www
backend www_site
balance roundrobin
server web1 172.16.1.7:80 check port 80
server web2 172.16.1.8:80 check port 802.3 客户端测试
[root@client ~]# curl -HHost:www.ops.net http://10.0.0.200:80/
RealServer Node1
[root@client ~]# curl -HHost:www.ops.net http://10.0.0.200:80/
RealServer Node23.配置HTTPS负载均衡
3.1 签发证书
# 创建自签证书文件
[root@lb01 ~]# cd /opt
[root@lb01 opt]# openssl genrsa -idea -out server.key 2048
[root@lb01 opt]# openssl req -days 36500 -x509 -sha256 \
-nodes -newkey rsa:2048 -keyout server.key -out server.crt
# 合并证书
[root@lb01 opt]# cat server.crt > ha_ssl.pem
[root@lb01 opt]# cat server.key >> ha_ssl.pem3.2 配置单域名https
📎21214937_www.zhouhaoit.com_nginx.zip
[root@proxy01 ~]# cat /etc/haproxy/haproxy.cfg
frontend blog
bind *:80
bind *:443 ssl crt /ssl/blog_key.pem # pem+key的合并结果文件
mode http
# 当请求域名为blog.ops.net 则重定向到https协议,并调度到后端blog_cluster集群处理
acl blog_domain hdr_dom(host) -i blog.ops.net
redirect scheme https code 301 if !{ ssl_fc } blog_domain
use_backend blog_cluster if blog_domain
# 域名匹配zh.ops.net
acl zh_domain hdr_dom(host) -i zh.ops.net
use_backend zh_cluster if zh_domain
###################################################
backend blog_cluster
balance roundrobin
server blog01 10.0.0.100:8081 check
server blog02 10.0.0.100:8082 check
backend zh_cluster
balance roundrobin
server web3 172.16.1.7:80 check port 80
server web4 172.16.1.8:80 check port 80
3.3 配置多域名单证书https
[root@proxy01 ~]# cat /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend blog
bind *:80
bind *:443 ssl crt /ssl/blog_key.pem
mode http
# 域名匹配blog.ops.net
acl blog_domain hdr_dom(host) -i blog.ops.net
use_backend zh_cluster if blog_domain
# 域名匹配zh.ops.net
acl zh_domain hdr_dom(host) -i zh.ops.net
use_backend zh_cluster if zh_domain
# 开启全站https
redirect scheme https if !{ ssl_fc }
###################################################
backend blog_cluster
balance roundrobin
server web1 172.16.1.7:80 check port 80
server web2 172.16.1.8:80 check port 80
backend zh_cluster
balance roundrobin
server web3 172.16.1.7:80 check port 80
server web4 172.16.1.8:80 check port 803.4 配置多域名多证书https
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend blog
bind *:80
# 如果每个域名证书都是独立,就都引用,haproxy会自行识别并匹配
# 示例:bind :443 ssl crt $filepath crt $file2path crt $file3path
bind *:443 ssl crt /ssl/blog_key.pem crt /ssl/zh_key.pem
mode http
# 域名匹配blog.ops.net
acl blog_domain hdr_dom(host) -i blog.ops.net
use_backend zh_cluster if blog_domain
# 域名匹配zh.ops.net
acl zh_domain hdr_dom(host) -i zh.ops.net
use_backend zh_cluster if zh_domain
# 开启全站https
redirect scheme https if !{ ssl_fc }
###################################################
backend blog_cluster
balance roundrobin
server web1 172.16.1.7:80 check port 80
server web2 172.16.1.8:80 check port 80
backend zh_cluster
balance roundrobin
server web3 172.16.1.7:80 check port 80
server web4 172.16.1.8:80 check port 803.5 配置多域名部分uri走https
[root@proxy01 ~]# cat /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
frontend blog
bind *:80
bind *:443 ssl crt /ssl/blog_key.pem crt /ssl/zh_key.pem
mode http
# 开启全站https
# redirect scheme https if !{ ssl_fc }
# blog.ops.net域名走http,碰到/login /pay走https
acl blog_domain hdr_dom(host) -i blog.ops.net
use_backend blog_cluster if blog_domain
acl blog_ssl_path path_beg -i /login /pay
redirect scheme https code 301 if !{ ssl_fc } blog_domain blog_ssl_path
redirect scheme http code 301 if { ssl_fc } blog_domain !blog_ssl_path
# 域名匹配zh.ops.net,所有uri都走https
acl zh_domain hdr_dom(host) -i zh.ops.net
redirect scheme https code 301 if !{ ssl_fc } zh_domain
use_backend zh_cluster if zh_domain
###################################################
backend blog_cluster
balance roundrobin
server web1 172.16.1.7:80 check port 80
server web2 172.16.1.8:80 check port 80
backend zh_cluster
balance roundrobin
server web3 172.16.1.7:80 check port 80
server web4 172.16.1.8:80 check port 803.6 客户端测试
[root@client ~]# curl -k -HHost:www.ops.net https://10.0.0.200
RealServer Node1
[root@client ~]# curl -k -HHost:www.ops.net https://10.0.0.200
RealServer Node24.配置高可用负载均衡
4.1 环境准备
1.基于 Keepalived 实现 Haproxy 高可用。
2.在 Master 与 backup 上分别安装 keepalived
[root@lb01 ~]# yum install keepalived -y
[root@lb02 ~]# yum install keepalived -y4.2 配置Master
配置 Master 节点
[root@lb01 ~]# cat /etc/keepalived/keepalived.conf
global_defs {
router_id lb01
}
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 50
priority 150
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.10
}
}4.3 配置Backup
配置 Backup 节点
[root@lb02 ~]# cat /etc/keepalived/keepalived.conf
global_defs {
router_id lb02
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 50
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.3
}
}4.4 高可用测试验证
启动 Master 与 Backup 节点的 keepalived
#lb01
[root@lb01 ~]# systemctl enable keepalived
[root@lb01 ~]# systemctl start keepalived
#lb02
[root@lb02 ~]# systemctl enable keepalived
[root@lb02 ~]# systemctl start keepalived