HAProxy
总所周知,lvs是一个高性能的四层代理,而Nginx则是一个四七层都可以干,顺带还可以做web服务的多面手。而HAProxy则是有点像两者的结合体:能干四七层代理,但不能当web服务器使用
虽然名字有个HA但不代表自带高可用,想要还得自己去拿keepalived配。HA的含义是自带对后端节点的检测,一旦故障可以自动将请求重新分发(支持检测端口或检测http服务是否正常,不只是检测后端服务器是否能ping通)
HAProxy的应用场景
HAProxy支持http、https协议的反向代理HAProxy支持动态程序的反向代理HAProxy支持基于 tcp 协议的反向代理(例如:MySQL、SSH、Redis)
HAProxy性能指标
衡量负载均衡性能,可以从三个因素来评估负载均衡器的性能:
- 会话率:会话建立的速率,在1秒内能建立多少连接
- 会话并发能力:整体服务器的会话并发能力,能同时支撑多少个并发的链接
- 数据率:在所有会话基础上,数据传输速率或数据传输效率
经过官方测试统计,haproxy单位时间处理的最⼤请求数为 20000 个,可以同时维护 40000-50000 个并发连接,最⼤数据处理与数据交换能⼒为 10Gbps (那么 10Gbps 实际速率= 10/8=1.25GBps ,下载速率每秒 1.25GB )。综合上述, haproxy 是性能优越的负载均衡、反向代理服务器。
(但肯定是得留余量,别官方说啥信啥)
HAProxy服务部署
1、Centos7
yum install -y haproxy
# 版本较老,可能在1.5左右
2、Rocky9
dnf install -y haproxy
# 版本较新,2.4-2.8之间
源码安装
源码安装时会稍微麻烦一些,需要安装Lua插件和必须包
# 必须的包
yum install lua gcc make readline-devel openssl-devel zlib-devel pcre-devel systemd-devel wget -y
# 安装lua脚本 lua:https://www.lua.org/download.html
wget https://www.lua.org/ftp/lua-5.4.6.tar.gz
tar xf lua-5.4.6.tar.gz -C /usr/local/
cd /usr/local/lua-5.4.6/
make all test
ln -s /usr/local/lua-5.4.6/ /usr/local/lua
# 源码编译haproxy
wget https://www.haproxy.org/download/2.8/src/haproxy-2.8.7.tar.gz
tar xf haproxy-2.8.7.tar.gz
cd 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
make install PREFIX=/usr/local/haproxy-2.8
ln -s /usr/local/haproxy-2.8/ /usr/local/haproxy
mkdir /var/lib/haproxy28
useradd -r -s /sbin/nologin haproxy
# 编写启动文件,让haproxy被系统systemctl代理
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.target
# 需要创建一个配置文件
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 5
HAProxy示例配置
对于HAProxy来说,其实配置起来与Nginx有很多相似之处
#----------------------------------------------------------------
# nginx
#----------------------------------------------------------------
server {} # 前端监听对外端口
proxy_pass # 将前端与后端建立关系
upstream{} # 后端资源池
#----------------------------------------------------------------
# haproxy
#----------------------------------------------------------------
frontend # 前端监听对外端口
use_backend # 将前端与后端建立关系,带条件的 location ~ \.php$ )
default_backend # 默认建立关系 ( location / )
backend # 后端资源池
listen # frontend和backend的组合体 ( 直接将前后端建立起来 )
default # 提供统⼀的默认参数,如果定义了则使用自⼰的,没有定义则使用default的
示例一 简单七层代理
场景描述:
- 将请求本机 80 端口的服务,都转发至
webservers后端集群组。 - 后端
webservers资源池定义了172.16.1.7:80、172.16.1.8:80两台节点。 - 调度方式采用轮询调度。
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)
注:对于haproxy来说,前端就是haproxy监听的端口,后端就是向后转发的后端服务器
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:端口] 检查
示例二 动静分离的七层代理
场景描述:
- 将请求本机 80 端口的服务,
uri为 /的默认转发至webservers后端集群组。 - 将请求本机 80 端口的服务,
uri为 /1.png|/2.gif的转发至static后端集群组。 - 后端
webservers资源池定义了172.16.1.7:80、172.16.1.8:80两台节点。 - 后端
static资源池定义了172.16.1.9:80、172.16.1.10:80两台节点。 - 调度方式采用轮询调度。
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 check
示例三 只做简单转发
场景描述:
- 将请求本机 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;
官方示例
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
场景实践
- 配置两个后端节点,监听在
8888端口,域名是 proxy.ops.net - 配置
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 nginx
2、配置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
HAProxy Global配置
global配置参数
Global settings 全局配置,用于设定全局配置参数
1、基本配置选项:
| 选项 | 作用 | 配置示例 |
|---|---|---|
| daemon | 以守护进程模式运行,在后台运行 | |
| chroot | 锁定运行目录 | chroot /var/lib/haproxy |
| user | 运行haproxy进程用户身份 | user haproxy |
| group | 运行haproxy进程用户组身份 | group haproxy |
| maxconn | 设定haproxy每个进程所接受的最⼤连接数 | maxconn 4000 |
| log 127.0.0.1 local2 | 通过本地rsyslog的local2设备写⼊日志 | local2.* /var/log/haproxy.log |
| stats socket /var/lib/haproxy/stats | 基于socket方式与Haproxy通信,可实现动态配置变更 | |
| spread-checks <0.50> | 在 HAProxy 中,当后端配置了众多节点时,如果所有健康检查同时进行,将会对 HAProxy 造成较⼤的性能影响。spread-checks 选项用于随机分散执行健康检查的时间,防⽌这些检查在同⼀时刻集中发⽣。官方推荐设置此值在 20% 至 50% 之间,以减少健康检查带来的性能开销。 |
2、进程与线程相关选项
| 选项 | 作用 | 配置示例 |
|---|---|---|
| nbproc |
haproxy进程的最⼤数量,默认启动⼀个进程 | nbproc 4 |
| nbthread |
haproxy线程的最⼤数量,默认启动⼀个线程,不能和nbproc同时使用 | nbproc 4 |
| cpu-map |
cpu亲和配置,第⼀个参数是进程编号,第⼆个参数是cpu序号 | cpu-map 1 0 |
配置多进程运行
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 haproxy
2、检查多进程详情
[root@proxy ~]# pstree -p haproxy
haproxy(15295)
haproxy(15296)
haproxy(15297)
haproxy(15298)
配置多线程运行
因为每个进程都是独立的,且资源不可共享。而⼀个进程多个线程的资源是可以共享的,因此多线程的方式要比多进程的方式性能好
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 admin
2、检查结果,{}表示线程
[root@proxy ~]# pstree -p haproxy
haproxy(11799)─┬─{haproxy}(11800)
├─{haproxy}(11801)
└─{haproxy}(11802)
配置访问日志
1、修改 haproxy 配置
[root@lb01 ~]# vim /etc/haproxy/haproxy.cfg
global
log 127.0.0.1 local2
2、修改 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.log
3、重启 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"
HAProxy defaults配置
option选项
option 选项用来启用或禁用特定的功能。以下是⼀些常用的 option 参数及其简单描述:
| 选项 | 作用 | 配置示例 |
|---|---|---|
| httplog | 启用 HTTP 日志格式,主要记录HTTP 请求的详细日志。 | option httplog |
| tcplog | 启用 TCP 日志格式,主要记录TCP 连接的基本信息,比如连接时长、发送的字节数等。 | option tcplog |
| dontlognull | 不要记录空连接的日志。所谓的空连接指的是没有数据传输的连接,通常是健康检查或者非活动连接。 | option dontlognull |
| http-server-close | 每个 HTTP 请求完成后关闭客户端连接,同时尝试保持与后端服务器的连接复用,减少服务器负载。 | option http-server-close |
| http-keep-alive | 启用 HTTP 长连接,允许在同⼀连接上进行多个请求与响应,减少连接的建立和关闭的开销。 | option http-keep-alive |
| redispatch | 当找不到cookie对应的节点时,重新将请求分配给新的节点(Cookies植⼊时演示) | option redispatch |
| forwardfor | 向后端服务器添加 X-Forwarded-For 头信息,包含了客户端的真实 IP 地址。 | option forwardfor except 127.0.0.0/8 |
在 HAProxy 配置中,如果想要关闭某些选项时,除了注释,也可以在相应的配置段前⾯添加 no 前缀来禁用它们,例如: no option httplog
timeout选项
timeout 选项主要是用来设定超时时间的,以下是⼀些常用的 timeout 参数及其简单描述:
| 选项 | 作用 | 配置示例 |
|---|---|---|
| queue | 当请求超过服务器最⼤连接数,多余的请求会进⼊队列中,如果请求在队列中等待超过了1分钟,则该请求被丢弃 | timeout queue 1m |
| http-request | 等待客户端发送完整的 HTTP 请求头的时间限制。若超过10秒则断开连接。 | timeout http-request 10s |
| client | 客户端空闲连接的最⼤持续时间。如果客户端在1分钟内没有数据传输,连接将被关闭。 | timeout client 1m |
| server | 服务器端空闲连接的最⼤持续时间。如果后端服务器在1分钟内没有数据传输,连接将被关闭。 | timeout server 1m |
| connect | HAProxy与后端服务建立 TCP 连接的最⼤时间。如果在10秒内连接没有成功建立,请求将被视为失败。 | timeout connect 10s |
| http-keep-alive | 当启用keep-alive 后,此设置决定了客户端在连续两次 HTTP 请求之间,保持空闲状态的最⼤时间。如果在10秒内没有新的请求,连接将被关闭。 | timeout http-keep-alive 10s |
| check | 设置了健康检查连接的超时时间。如果在10秒内健康检查没有完成,后端服务器可能被标记为不健康。 | timeout check 10s |
HAProxy Proxies配置
代理相关配置:
frontend <name>:用于定义⼀系列监听的端口(前端端口),这些端口可接受客户端请求并与之建立连接backend <name>:用于定义⼀系列后端服务器,代理将会将对应客户端(前端接收)的请求转发至这些服务器listen <name>:通过关联“前端”和“后端”定义了⼀个完整的代理
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 webcluster
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 webcluster
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 2000
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:80
2、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 80
3、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 3000
4、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 2
5、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 3
6、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 3000
7、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 200
8、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 2
使用子配置管理
- 当业务众多时,将所有配置都放在⼀个配置文件中,会造成维护困难
- 可以考虑按业务分类,将配置拆分,放在不同的配置文件中,从而达到方便维护的目的