Linux的负载均衡器 | Word Count: 3.8k | Reading Time: 16mins | Post Views:
负载均衡(Load Balance),简称LB,是一种基于服务或者基于硬件设备等实现的高可用反向代理。负载均衡将特定的业务分担指向一个或者多个后端特定服务器或者设备,从而提高服务的并发处理能力,保证了高可用性和可扩展性。负载均衡建立在现有的网络结构之上,提供了一种廉价、有效、透明的方法来扩展网络设备和服务器的处理能力,提高了网络的灵活性和可用性。
增加业务并发访问及处理能力
节约公网IP地址
隐藏内部服务器IP
Web服务器动态水平扩展
简化负载均衡配置
提供多层负载均衡能力
根据TCP/IP的分层,四层的负载均衡软件有LVS、Nginx、Haproxy,七层的负载均衡有Nginx和Haproxy。硬件有F5、Netscaler等。
服务发现 服务发现组件记录了大规模系统中所有服务的信息,人们或者其他服务可以据此找到这些服务,类似于DNS就是现有最大服务发现系统。
LVS LVS:Linux Virtual Server,Linux内核集成的负载调度器。LVS根据请求报文的目标IP和目标协议以及端口将其调度转发至某RS,根据调度算法来挑选RS。LVS是内核级功能,工作在INPUT链的位置,将发往INPUT的流量进行“处理”。
概念 术语 VS:Virtual Server,Director Server (DS),Dispatcher(调度器),LoadBalancer
RS:Real Server(LVS),upstream server(nginx),backend server(haproxy)
CIP: Client IP
VIP: Viratual Server IP
RIP: Real Server IP
访问流程:CIP——VIP——DIP——RIP
体系结构 LVS集群采用三层结构:
负载均衡器:服务器集群系统的唯一入口点
服务器池:整体系统的性能级别上随着服务器池的节点数目增加而线性增长
共享存储:服务器节点上需要动态更新的数据一般存储再数据库系统中,同时数据库会保证并发访问时数据的一致性
工作模式 NAT模式 修改请求报文的目标IP,多目标IP的DNAT。
RIP和DIP应在同一个IP网络,且应使用私网地址,RS网关指向DIP
请求报文和响应报文都必须经由Director转发
支持端口映射,可修改请求报文的目标PORT
DR模式 Direct Routing,直接路由,LVS的默认模式。通过为请求重新封装新的MAC地址进行转发。
Director和RS都配置VIP
在RS上使用arptables工具
RS和Director要在同一个物理网络
不支持端口映射
无需开启ip_forward
TUN模式 不修改请求报文的IP首部,而在原请求IP报文之外新加一个IP首部,将报文法网挑选出来的目标RS,RS直接响应客户端。
RIP和DIP可以不处于同一物理网络,可以跨互联网实现
Director转发给RealServer需要借助隧道
请求报文要经由Director,响应不经由Director,响应由RealServer完成
不支持端口映射
OS必须支持隧道功能
FullNAT模式 通过同时修改请求报文的源和目标IP进行转发,默认内核不支持
VIP是公网地址,RIP和DIP是私网地址
RS收到请求报文源地址是DIP
支持端口映射
支持跨VLAN通讯
调度算法 静态方法
RR: roundrobin 轮询算法
WRR; Weighted RR 加权轮询
SH:Source Hashing 源IP地址哈希
DH:Destination Hashing 目标地址哈希
FO:Weighted Fail Over 找到未过载且权重高的RS进行调度
动态方法
LC: least connections 适用于长连接应用
WLC:Weighted LC 默认调度方法
SED: Shortest Expection Delay 初始连接高权重优先
NQ: Never Queue 第一轮均匀分配,后续使用SED
LBLC:Locality-Based LS 动态DH算法,用于webCache
LBLCR:LBLC with Replication 带复制功能的LBLC,解决负载不均衡问题
OVF:Overflow-connection 基于RS权重值调度
ipvsadm 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 [root@nginx ~]# rpm -ql ipvsadm /etc/sysconfig/ipvsadm-config # 配置文件 /usr/lib/.build-id /usr/lib/.build-id/06 /usr/lib/.build-id/06/ac0ff7fe8b4b02cb38c6107cedeed6e4979f49 /usr/lib/systemd/system/ipvsadm.service /usr/sbin/ipvsadm # 主程序 /usr/sbin/ipvsadm-restore # 规则重载工具 /usr/sbin/ipvsadm-save # 规则保存工具 /usr/share/doc/ipvsadm /usr/share/doc/ipvsadm/MAINTAINERS /usr/share/doc/ipvsadm/README /usr/share/man/man8/ipvsadm-restore.8.gz /usr/share/man/man8/ipvsadm-save.8.gz /usr/share/man/man8/ipvsadm.8.gz
集群构建 NAT模式 准备工作
角色
主机名称
IP地址
LVS
nginx
192.168.10.30;172.16.10.130
RS1
k3lb1
172.16.10.128
RS2
k2lb2
172.16.10.129
1 2 3 4 5 6 7 8 9 10 11 12 [root@nginx ~]# echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf [root@nginx ~]# sysctl -p [root@nginx ~]# modprobe iptable_nat [root@nginx ~]# curl 172.16.10.128 <h1>This is WebSite K3LB1 </h1> [root@nginx ~]# curl 172.16.10.129 <h1>This is WebSite K3LB2</h1> [root@nginx ~]# touch /etc/sysconfig/ipvsadm [root@nginx ~]# systemctl start ipvsadm [root@nginx ~]# systemctl enable ipvsadm
实例部署 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 # 后端RS主机的gateway要指向LVS主机 # 清理链表 [root@nginx ~]# ipvsadm -C # 新增NAT集群,vip为192.168.10.30 [root@nginx ~]# ipvsadm -A -t 192.168.10.30:80 -s wrr [root@nginx ~]# ipvsadm -a -t 192.168.10.30:80 -r 172.16.10.128:80 -m [root@nginx ~]# ipvsadm -a -t 192.168.10.30:80 -r 172.16.10.129:80 -m [root@nginx ~]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.10.30:80 wrr -> 172.16.10.128:80 Masq 1 0 0 -> 172.16.10.129:80 Masq 1 0 0 # 检验 [sujx@infra ~]$ while :;do curl 192.168.10.30;sleep 0.5; done <h1>This is WebSite K3LB2</h1> <h1>This is WebSite K3LB1 </h1> <h1>This is WebSite K3LB2</h1> <h1>This is WebSite K3LB1 </h1> <h1>This is WebSite K3LB2</h1> <h1>This is WebSite K3LB1 </h1> <h1>This is WebSite K3LB2</h1> <h1>This is WebSite K3LB1 </h1> <h1>This is WebSite K3LB2</h1> [root@nginx ~]# ipvsadm -Ln --stats IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Conns InPkts OutPkts InBytes OutBytes -> RemoteAddress:Port TCP 192.168.10.30:80 187 1122 748 74239 92471 -> 172.16.10.128:80 93 558 372 36921 46035 -> 172.16.10.129:80 94 564 376 37318 46436 [root@nginx ~]# ipvsadm -Lnc IPVS connection entries pro expire state source virtual destination TCP 21188505:19 TIME_WAIT 192.168.10.254:41700 192.168.10.30:80 172.16.10.129:80 TCP 00:35 TIME_WAIT 192.168.10.254:51316 192.168.10.30:80 172.16.10.129:80 TCP 00:48 TIME_WAIT 192.168.10.254:33400 192.168.10.30:80 172.16.10.129:80 TCP 00:36 TIME_WAIT 192.168.10.254:51330 192.168.10.30:80 172.16.10.129:80 TCP 00:17 TIME_WAIT 192.168.10.254:41732 192.168.10.30:80 172.16.10.128:80 TCP 00:43 TIME_WAIT 192.168.10.254:33292 192.168.10.30:80 172.16.10.128:80 TCP 00:21 TIME_WAIT 192.168.10.254:51130 192.168.10.30:80 172.16.10.129:80 TCP 00:54 TIME_WAIT 192.168.10.254:53464 192.168.10.30:80 172.16.10.129:80 TCP 01:02 TIME_WAIT 192.168.10.254:42092 192.168.10.30:80 172.16.10.128:80 # 保存配置 [root@nginx ~]# ipvsadm-save -A -t nginx:http -s wrr -a -t nginx:http -r 172.16.10.128:http -m -w 1 -a -t nginx:http -r 172.16.10.129:http -m -w 1
DR模式 准备工作
角色
主机名
IP地址
客户端
client
192.168.10.19
路由
router
192.168.10.20,172.16.10.120
LVS
lvs
172.16.10.130,172.16.10.100
RS
rs1
172.16.10.128,172.16.10.100
RS
rs2
172.16.10.129,172.16.10.100
LVS和RS角色的gateway指向路由。
DR模型中各主机上均需要配置VIP,解决地址冲突的方式有三种:
在前端网关做静态绑定
在各RS使用arptables
在各RS修改内核参数,来限制arp响应和通告的级别 限制响应级别:arp_ignore 0:默认值,表示可使用本地任意接口上配置的任意地址进行响应 1:仅在请求的目标IP配置在本地主机的接收到请求报文的接口上时,才给予响应 限制通告级别:arp_announce 0:默认值,把本机所有接口的所有信息向每个接口的网络进行通告 1:尽量避免将接口信息向非直接连接网络进行通告 2:必须避免将接口信息向非本网络进行通告
配置要点
Director 服务器采用双IP桥接网络,一个是VIP,一个DIP
Web服务器采用和DIP相同的网段和Director连接
每个Web服务器配置VIP
每个web服务器可以出外网
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 # 配置路由器 [root@router ~]# echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf [root@router ~]# modprobe iptable_nat [root@router ~]# sysctl -p net.ipv4.ip_forward = 1 # 新增一块网卡 [root@router ~]# nmcli con add type ethernet ifname ens192 con-name ens192 ipv4.add 172.16.10.120/24 ipv4.gateway 192.168.10.254 ipv4.dns 192.168.10.2 # 配置客户端,网关指向路由 [root@client ~]# mcli c m ens160 ipv4.method man ipv4.add 192.168.10.19/24 ipv4.gateway 192.168.10.20 [root@client ~]# nmcli c d ens160 && nmcli c u ens160 # 配置rs网关指向router,并修改主机arp配置 [root@k3lb1 ~]# nmcli c m ens160 ipv4.method man ipv4.add 172.16.10.128/24 ipv4.gateway 172.16.10.120 [root@k3lb1 ~]# nmcli c d ens160 && nmcli c u ens160 [root@k3lb1 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore [root@k3lb1 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce [root@k3lb1 ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore [root@k3lb1 ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce [root@k3lb1 ~]# nmcli c m lo ipv4.add 172.16.10.100/32 [root@k3lb1 ~]# nmcli c d lo && nmcli c u lo [root@k3lb2 ~]# nmcli c m ens160 ipv4.method man ipv4.add 172.16.10.129/24 ipv4.gateway 172.16.10.120 [root@k3lb2 ~]# nmcli c d ens160 && nmcli c u ens160 [root@k3lb2 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore [root@k3lb2 ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore [root@k3lb2 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce [root@k3lb2 ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce [root@k3lb2 ~]# nmcli c m lo ipv4.add 172.16.10.100/32 [root@k3lb2 ~]# nmcli c d lo && nmcli c u lo # LVS主机配置 [root@lvs ~]# nmcli c m ens160 ipv4.method man ipv4.add 172.16.10.130/24 ipv4.gateway 172.16.10.120 [root@lvs ~]# modprobe iptable_nat [root@lvs ~]# nmcli c m lo ipv4.add 172.16.10.100/32 [root@lvs ~]# nmcli c d lo && nmcli c u lo [root@lvs ~]# curl 172.16.10.128 <h1>This is WebSite K3LB1 </h1> [root@lvs ~]# curl 172.16.10.129 <h1>This is WebSite K3LB2</h1> # 配置LVS服务 [root@lvs ~]# touch /etc/sysconfig/ipvsadm [root@lvs ~]# systemctl start --now ipvsadm
配置DR实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 [root@lvs ~]# ipvsadm -A -t 172.16.10.100:80 -s rr [root@lvs ~]# ipvsadm -a -t 172.16.10.100:80 -r 172.16.10.128:80 -g [root@lvs ~]# ipvsadm -a -t 172.16.10.100:80 -r 172.16.10.129:80 -g [root@lvs ~]# ipvsadm -Ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 172.16.10.100:80 rr -> 172.16.10.128:80 Route 1 0 0 -> 172.16.10.129:80 Route 1 0 0 [root@lvs ~]# ipvsadm-save > /etc/sysconfig/ipvsadm # 测试 [sujx@Rocky ~]$ while :;do curl 172.16.10.100;sleep 0.5; done <h1>This is WebSite K3LB1 </h1> <h1>This is WebSite K3LB2</h1> <h1>This is WebSite K3LB1 </h1> <h1>This is WebSite K3LB2</h1> <h1>This is WebSite K3LB1 </h1> <h1>This is WebSite K3LB2</h1>
Haproxy 介绍和架构 HaProxy是法国开发者Willy Tarreau在2000年使用C语言开发的一个软件,是一款具有高并发、高性能的TCP和HTTP负载均衡器,支持基于cookie的持久性、自动故障切换、支持正则表达式以及web状态统计等功能。
安装 1 2 3 4 5 6 7 8 9 10 11 12 13 # Rockylinux9安装 dnf install -y haproxy systemctl enable --now haproxy # 可见haproxy为父子进程,且为单进程 pstree -p systemd(1)─├─haproxy(29445)───haproxy(29447) # 查看版本号 haproxy --version HAProxy version 2.4.17-9f97155 2022/05/13 - 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.17.html
基础配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 # /etc/haproxy/haproxy.cfg 默认配置文件 --------------------------------------------------------------------- global # 全局选项 log 127.0.0.1 local2 # 日志标识 chroot /var/lib/haproxy # chroot限定 pidfile /var/run/haproxy.pid # 进程pid maxconn 4000 # 最大连接数 user haproxy # 进程用户 group haproxy # 进程用户组 daemon # turn on stats unix socket stats socket /var/lib/haproxy/stats # socket状态页 # utilize system-wide crypto-policies ssl-default-bind-ciphers PROFILE=SYSTEM ssl-default-server-ciphers PROFILE=SYSTEM defaults # 默认选项 mode http # 设置默认工作类型,建议修改为TCP,性能更好,减少压力 log global option httplog option dontlognull option http-server-alive # 开启与客户端的对话保持 # option http-server-close 关闭后端客户端会话保持 option forwardfor except 127.0.0.0/8 # 透传客户端真实IP给后端web服务器 option redispatch # Server ID对应服务器挂掉后,强制定向到其他健康的服务器,重新派发 retries 3 timeout http-request 10s timeout queue 1m timeout connect 10s #客户端请求从haproxy到后端server最长连接等待时间 timeout client 1m # 设置haproxy与客户端的最长非活动时间 timeout server 1m # 设置haproxy与后端服务器的最长非活动时间 timeout http-keep-alive 10s # session会话保持超时时间,超时会转发到其他服务器 timeout check 10s # 对后端服务器的默认检测超时时间 maxconn 3000 frontend main # 前端server 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
日志配置 HAproxy本身不记录客户端的访问日志,一般生产中HAproxy不记录日志,也可以配置HAproxy利用rsyslog记录日志到指定日志文件中。
调度算法 HaProxy通过固定参数balance指明对后端服务器的调度算法。
静态算法 按照实现定义好的规则进行调度,无关后端服务器的负载、连接数、响应速度等。
static-rr算法:基于权重的轮询
first算法:根据服务器在列表中的位置,自上而下进行调度,当前一台服务器连接数达到上限,新请求才会分配给下一个台服务器。
动态算法
roundrobin算法:基于权重的轮询动态调度算法,为默认算法
leastconn算法:加权的最少连接数动态调度算法,适合长连接场景,常用于MySQL场景
random算法:负载平衡算法,基于一致性hash的key随机负载平衡,适用于大型服务器场
其他算法
source算法:源地址hash,适用于session会话保持但不支持cookie和缓存场景
map-base取模法:对源地址hash,再基于服务器总权重的取模,为静态算法
一致性hash:当服务器总权重发生变化时,对调度结果影响是局部
uri算法:基于对用户请求的uri的左半部分或整个uri做hash,再将hash结果对总权重进行取模后,根据最终结果将请求转发到后端指定服务器,适用于后端是缓存服务器场景,默认为静态算法,只支持http mode,不支持tcp mode
url_param算法:对用户请求的url中的一个参数key对应的value值做hash计算
hdr算法:针对用户http头部请求中指定的信息做hash
rdp-cookie算法:对Windows远程桌面负载,使用cookie保持会话默认是静态的。
高级功能 haproxy状态页 1 2 3 4 5 6 7 listen stats #定义监控页面 bind *:9999 #绑定端口1080 stats refresh 30s #每30秒更新监控数据 stats uri /stats #访问监控页面的uri stats realm HAProxy Stats #监控页面的认证提示 stats auth admin:admin #监控页面的用户名和密码 stats admin if TRUE # 状态页可以管理