HAProxy 技术详解
1. HAProxy 简介
1.1 什么是 HAProxy?
HAProxy(High Availability Proxy)是一款免费、开源的负载均衡器和代理服务器软件,基于时间驱动,单进程模型设计的四层与七层负载均衡器,它能够在TCP/UDP层面以及HTTP等应用层协议上实现高效的流量分发,并且提供了高可用性、负载均衡以及基于虚拟主机的代理功能。HAProxy 特别适用于那些负载特大的 web 站点,这些站点通常需要会话保持或七层处理。Haproxy还能应用于数据库,邮件服务器,缓存服务器等多种场景。支持数百万级的并发连接,并具有极低的延迟。
负载均衡:Load Balance,简称LB,是一种服务或基于硬件设备等实现的高可用反向代理技术,负载均衡将特定的业务(web服务、网络流量等)分担给指定的一个或多个后端特定的服务器或设备,从而提高了公司业务的高并发处理能力、保证了业务的高可用性、方便了业务后期的水平动态扩展
HAProxy拥有强大的功能性
- 支持功能
- TCP 和 HTTP 反向代理
- SSL/TSL服务器
- 可以针对HTTP请求添加 cookie,进行路由后端服务器
- 可平衡负载至后端服务器,并支持持久连接
- 支持所有主服务器故障切换至备用服务器 keepalive
- 支持专用端口实现监控服务
- 支持停止接受新连接请求,而不影响现有连接
- 可以在双向添加,修改或删除HTTP报文首部字段
- 响应报文压缩
- 支持基于 pattern 实现连接请求的访问控制
- 通过特定的 URI(url)为授权用户提供详细的状态信息
1.2 HAProxy 的优势
- 高性能:采用事件驱动模型,能够处理大量并发连接。
- 灵活性:支持多种负载均衡算法和调度策略,适应不同的应用场景。
- 高可用性:通过健康检查和故障转移机制,确保服务的连续性。
- 安全性:可以保护后端服务器不被暴露在网络上,提高系统的整体安全性。
- 易用性:配置简单,支持丰富的配置选项。
1.3 LVS与HAProxy的区别
LVS也是负载均衡或者说负载调度器之中不可避免的一大部分,也能够解决高并发的问题,那么lvs同haproxy有什么分别呢?
- LVS基于Linux操作系统实现软负载均衡,而HAProxy和Nginx是基于第三方应用实现的软负载均衡
- LVS是可实现4层的IP负载均衡技术,无法实现基于目录、URL的转发。而HAProxy和Nginx都可以实现4层和7层代理,HAProxy可提供TCP和HTTP应用的负载均衡综合解决方案
- LVS工作在TCP模型的第四层,其状态监测功能单一,而HAProxy在状态监测方面功能更强大,可支持端口、URI等多种状态检测方式
- HAProxy功能强大,但整体性能低于4层模式的IVS负载均衡,相比lvs,harpoxy本身更容易成为性能瓶颈
- Nginx主要用于web服务器或缓存服务器。Nginx的upstream模块虽然也支持群集功能,但是对群集节点健康检查功能不强,性能没有Haproxy好
四层负载均衡
- 通过ip+port决定负载均衡的去向
- 对流量进行NAT处理,转发至后台服务器
- 记录tcp,udp流量分别由哪台服务器处理,后续该连接都通过该服务器处理
七层负载均衡
- 通过虚拟url或主机ip进行流量识别,根据应用层信息进行解析,决定是否需要进行负载均衡。
- 代理后台服务器与客户端建立连接,如nginx可代理前后端,与前端客户端tcp连接,与后端服务器建立tcp连接,
- 七层负载均衡是在四层的基础上再考虑应用层的特征,比如URL,浏览类别进行负载均衡。
2. HAProxy 的工作原理
HAProxy 的工作原理涉及到多个层面,包括其架构、如何处理连接请求、负载均衡算法的选择、以及如何维护后端服务器的健康状态等。
2.1. 架构概述
HAProxy 的架构设计是为了处理大量并发连接而优化的。它采用了单一进程模型,其中使用事件驱动的 I/O 模型来处理连接。这意味着 HAProxy 能够在一个进程中处理成千上万的并发连接,而不是为每个连接创建一个新的进程或线程。
2.2. 工作流程
2.2.1 监听端口
HAProxy 通过在指定的端口上监听客户端请求,等待客户端的连接请求。这些端口通常被称为前端端口,它们负责接收来自外部客户端的流量。
2.2.2 接受请求
一旦客户端请求到达,HAProxy 会根据预先定义的前端配置信息对请求进行解析,包括协议类型、请求头等,并根据相应的规则进行分发。
2.2.3 路由请求
根据前端配置和负载均衡算法,HAProxy 将请求分发到相应的后端服务器。HAProxy 支持多种负载均衡算法,例如轮询、加权轮询、源 IP 哈希等。
2.3. 负载均衡算法
HAProxy 支持多种负载均衡算法,常见的包括:
- 轮询(Round Robin):按照顺序将请求分发给后端服务器。
- 最小连接(Least Connections):将新的请求分发给当前连接数最少的后端服务器。
- 源 IP 哈希(Source IP Hash):基于客户端 IP 地址进行哈希计算,将来自同一 IP 的请求定向到同一个后端服务器。
- 加权轮询(Weighted Round Robin):给每个后端服务器分配一个权重值,权重越高的服务器被选中的概率越大。
2.4. 会话保持
为了确保来自同一客户端的请求被发送到相同的后端服务器,HAProxy 提供了会话保持的功能。会话保持可以通过多种方式实现,例如:
- 基于 Cookie 的会话保持:HAProxy 可以插入一个特殊的 Cookie 到响应头部,客户端会在后续请求中携带这个 Cookie,HAProxy 会根据这个 Cookie 将请求定向到同一台后端服务器。
- 源 IP 哈希:如上所述,这是一种简单的会话保持方法,特别适用于不需要持久会话的应用场景。
2.5. 健康检查
HAProxy 具有强大的健康检查功能,可以定期向后端服务器发送测试请求以确认其是否处于正常工作状态。如果检测到某台服务器出现故障,HAProxy 会暂时将其从轮换列表中移除,直到它恢复正常。
2.6. 配置与管理
HAProxy 的配置文件haproxy.cfg由两大部分组成,分别是:
global:全局配置段
- 进程及安全配置相关的参数
- 性能调整相关参数
- Debug参数
proxies:代理配置段
- defaults:为frontend, backend, listen提供默认配置
- frontend:前端,相当于nginx中的server {}
- backend:后端,相当于nginx中的upstream {}
- listen:同时拥有前端和后端配置,配置简单,生产推荐使用
2.7. 高级特性
除了基本的负载均衡功能之外,HAProxy 还支持一些高级特性,如:
- SSL/TLS 终结:可以在 HAProxy 层面终止 SSL/TLS 连接,减轻后端服务器的负担。
- HTTP 压缩:可以启用 HTTP 压缩来减少带宽使用。
- 请求和响应修改:可以修改 HTTP 请求和响应头,实现更复杂的代理行为。
haproxy实例
实验环境
实例在下表所述的环境之中运行
功能 | IP |
客户端 | 172.25.254.10 |
haproxy | 172.25.254.100,192.168.0.100 |
rs1 | 192.168.0.10 |
rs2 | 192.168.0.20 |
软件包下载-rhel9
配置haproxy实现rs1,2的简单负载均衡
配置haproxy.cfg
vim /etc/haproxy/haproxy.cfg
listen webcluster
bind *:80
mode http
balance static-rr
server web1 192.168.0.10:80
server web2 192.168.0.20:80
为什么是listen?前端与后端呢?
这其中就涉及到proxies(代理服务器)与haproxy的内容了,如下
在 HAProxy 的上下文中,“proxies”一词通常指的是 HAProxy 所提供的代理服务功能。HAProxy 本质上就是一个代理服务器,它能够代理客户端与后端服务器之间的通信。
HAProxy 的代理服务主要涉及两个方面:前端(Frontend)和后端(Backend)。
前端(Frontend)
前端是 HAProxy 中用于接收客户端请求的部分。每个前端都绑定了一个或多个监听端口,这些端口用于接收来自客户端的连接请求。前端配置定义了如何处理这些请求,并决定了将请求转发给哪个后端。
frontend http-in
bind *:80
mode http
default_backend servers
在这个例子中,`http-in` 是前端的名称,它绑定到了 `*:80`,即所有接口上的 80 端口。`mode http` 表示这个前端处理 HTTP 请求,‘default_backend servers’指定所有来自该前端的请求都应该转发到名为 `servers` 的后端。
后端(Backend)
后端是 HAProxy 中定义的一组后端服务器集合。后端配置指定了如何将前端接收到的请求分发到这些服务器。后端还可以定义负载均衡算法、健康检查机制等。
backend servers
balance roundrobin
server server1 192.168.1.10:80 check
server server2 192.168.1.11:80 check
在这个例子中,`servers` 是后端的名称,`balance roundrobin` 指定使用轮询算法来分发请求。两台服务器 `server1` 和 `server2` 被定义为后端服务器,并启用了健康检查。
代理服务配置选项
HAProxy 提供了许多配置选项来控制代理服务的行为。以下是一些常见的配置选项:
- 负载均衡算法:例如 `roundrobin`、`leastconn` 等。
- 会话保持:通过 `appsession` 或 `stick-table` 实现。
- 健康检查:通过 `check` 关键字配置。
- SSL/TLS 终结:通过 `ssl` 和 `bind` 选项配置 SSL/TLS 支持。
- HTTP 压缩:可以启用 HTTP 压缩来减少带宽使用。
- 请求和响应修改:可以修改 HTTP 请求和响应头,实现更复杂的代理行为。
proxies:代理配置段
defaults:为frontend, backend, listen提供默认配置
frontend:前端,相当于nginx中的server {}
backend:后端,相当于nginx中的upstream {}
listen:同时拥有前端和后端配置,配置简单,生产推荐使用
proxies配置-defaults
mode http # HAProxy 实例使用的连接协议
log global # 指定日志地址和记录日志条目的
syslog/rsyslog 日志设备 #此处的 global 表示使用 global 配置段中设定的log 值。
option httplog # 日志记录选项, httplog 表示记录与 HTTP会话相关的各种属性值
# 包括 HTTP 请求、会话状态、连接数、源地 址以及连接时间等
option dontlognull #dontlognull 表示不记录空会话连接日志
option http-server-close # 等待客户端完整 HTTP 请求的时间,此处为等待10s
option forwardfor except 127 .0.0.0/8 # 透传客户端真实 IP 至后端 web 服务器
# 在 apache 配置文件中加入 :<br>%{XForwarded-For}i
# 后在 webserer 中看日志即可看到地址透传信息
option redispatch # 当 server Id 对应的服务器挂掉后,强制定向到其他健康的服务器,重新派发
option http-keep-alive # 开启与客户端的会话保持
retries 3 # 连接后端服务器失败次数
timeout http-request 1000s # 等待客户端请求完全被接收和处理的最长时间
timeout queue 60s# 设置删除连接和客户端收到 503 或服务不可用等提示信息前的等待时间
timeout connect 120s # 设置等待服务器连接成功的时间
timeout client 600s# 设置允许客户端处于非活动状态,即既不发送数据也不接收数据的时间
timeout server 600s
# 设置服务器超时时间,即允许服务器处于既不接收也不发送数据的非活动时间
timeout http-keep-alive 60s
#session 会话保持超时时间,此时间段内会转发到相同的后端服务器
timeout check 10s
# 指定后端服务器健康检查的超时时间
maxconn 3000
default-server inter 1000 weight 3 指定后端服务器默认设置
proxies配置-frontend
bind :指定 HAProxy 的监听地址,可以是 IPV4 或 IPV6 ,可以同时监听多个 IP 或端口,可同时用于 listen 字段中
# 格式:
bind [<address>]:<port_range> [, ...] [param*]
# 注意:如果需要绑定在非本机的 IP ,需要开启内核参数: net.ipv4.ip_nonlocal_bind=1
backlog <backlog> # 针对所有 server 配置 , 当前端服务器的连接数达到上限后的后延队列长度
proxies配置-backend
定义一组后端服务器,backend服务器将被frontend进行调用。
backend 的名称唯一,且须在listen或frontend中事先定义才可以使用,否则服务无法启动
mode http|tcp # 指定负载协议类型 , 和对应的 frontend 必须一致
option # 配置选项
server # 定义后端 real server, 必须指定 IP 和端口
使用listen替换frontend与backend能够极大程度的简化配置,但listen通常只用于tcp协议的应用,配置实例如图所示:
重启服务
systemctl restart haproxy.service
测试
如此,haproxy最简单的负载均衡就配置完成
配置haproxy的状态页面
# vim /etc/haproxy/haproxy.cfg
listen stats
mode http #页面开关
bind *:8080 #监听的ip端口
stats enable
log global
stats uri /haproxy-status #访问的url
stats auth zheng:zheng #认证用户名与密码
stats refresh 30s #统计页面自动刷新时间
stats realm haproxy
stats hide-version #隐藏HAProxy的版本号
stats admin if TRUE #管理界面,如果认证成功了,可通过webui管理节点
重启服务
浏览器访问
socat工具
socat是linux下的一个多功能网络工具,能够在两个数据流之间建立双向通道,利用socat我们能够对服务器进行动态权重调整。
修改配置文件
#修改配置文件
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
stats socket /var/lib/haproxy/stats mode 600 level admin
#查看帮助
haproxy ~]# socat -h
haproxy ~]# echo "help" | socat stdio /var/lib/haproxy/stats
The following commands are valid at this level:
help : this message
prompt : toggle interactive mode with prompt
quit : disconnect
。。。省略 。。。
enable server : enable a disabled server (use 'set server' instead) #启用服务器
set maxconn server : change a server's maxconn setting
set server : change a server's state, weight or address #设置服务器
get weight : report a server's current weight #查看权重
set weight : change a server's weight (deprecated) #设置权重
show startup-logs : report logs emitted during HAProxy startup
how peers [peers section]: dump some information about all the peers or this
peers section
set maxconn global : change the per-process maxconn setting
set rate-limit : change a rate limiting value
set severity-output [none|number|string] : set presence of severity level in
feedback information
set timeout : change a timeout setting
show env [var] : dump environment variables known to the process
show cli sockets : dump list of cli sockets
show cli level : display the level of the current CLI session
show fd [num] : dump list of file descriptors in use
查看haproxy状态
#查看haproxy状态
[root@haproxy ~]# echo "show info" | socat stdio /var/lib/haproxy/stats
Name: HAProxy
Version: 2.4.22-f8e3218
Release_date: 2023/02/14
Nbthread: 1
Nbproc: 1
Process_num: 1
Pid: 33675
Uptime: 0d 0h03m45s
Uptime_sec: 223
Memmax_MB: 0
PoolAlloc_MB: 0
查看集群状态
[root@haproxy ~]# echo "show servers state" | socat stdio /var/lib/haproxy/stats
1
# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight
srv_iweight srv_time_since_last_change srv_check_status srv_check_result
srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id
srv_fqdn srv_port srvrecord srv_use_ssl srv_check_port srv_check_addr
srv_agent_addr srv_agent_port
2 webcluster 1 web1 192.168.0.10 2 0 2 2 188 6 3 7 6 0 0 0 - 80 - 0 0 - - 0
2 webcluster 2 web2 192.168.0.20 2 0 1 1 188 6 3 7 6 0 0 0 - 80 - 0 0 - - 0
4 static 1 static 127.0.0.1 0 0 1 1 187 8 2 0 6 0 0 0 - 4331 - 0 0 - - 0
5 app 1 app1 127.0.0.1 0 0 1 1 187 8 2 0 6 0 0 0 - 5001 - 0 0 - - 0
5 app 2 app2 127.0.0.1 0 0 1 1 187 8 2 0 6 0 0 0 - 5002 - 0 0 - - 0
5 app 3 app3 127.0.0.1 0 0 1 1 186 8 2 0 6 0 0 0 - 5003 - 0 0 - - 0
5 app 4 app4 127.0.0.1 0 0 1 1 186 8 2 0 6 0 0 0 - 5004 - 0 0 - - 0
查看集群权重
#查看集群权重
[root@haproxy ~]# echo get weight webcluster/web1 | socat stdio
/var/lib/haproxy/stats
2 (initial 2)
[root@haproxy ~]# echo get weight webcluster/web2 | socat stdio
/var/lib/haproxy/stats
1 (initial 1)
设置权重
[root@haproxy ~]# echo "set weight webcluster/web1 1 " | socat stdio
/var/lib/haproxy/stats
[root@haproxy ~]# echo "set weight webcluster/web1 2 " | socat stdio
/var/lib/haproxy/stats
下线后端服务器
[root@haproxy ~]# echo "disable server webcluster/web1 " | socat stdio
/var/lib/haproxy/stats
上线后端服务器
[root@haproxy ~]# echo "enable server webcluster/web1 " | socat stdio
/var/lib/haproxy/stats