LVS

发布时间 2023-04-07 16:32:00作者: ——浮生——

LVS

VS根据请求报文的目标IP和目标协议及端口将其调度转发至某RS,根据调度算法来挑选RS。LVS是内核 级功能,工作在INPUT链的位置,将发往INPUT的流量进行“处理”

VS:Virtual Server,Director Server(DS), Dispatcher(调度器),Load Balancer
RS:Real Server(lvs), upstream server(nginx), backend server(haproxy)
CIP:Client IP
VIP:Virtual serve IP VS外网的IP
DIP:Director IP VS内网的IP
RIP:Real server IP 
访问流程:CIP <--> VIP == DIP <--> RIP

工作模式

  • vs-nat:修改请求报文的目标IP,多目标IP的DNAT

    1.客户端发送源地址为CIP。目标地址为VIP的请求报文到VS
    2.VS接收报文后将目标地址转换为调度算法选择的RS地址
    3.RS接收报文后返回源地址时RIP,目标地址是CIP的响应报文到VS,VS接收报文后转换源地址为VIP。并将报文发送gei客户端
    
    lvs-nat:本质是多目标IP的DNAT,通过将请求报文中的目标地址和目标端口修改为某挑出的RS的RIP和
    PORT实现转发
    (1)RIP和DIP应在同一个IP网络,且应使用私网地址;RS的网关要指向DIP
    (2)请求报文和响应报文都必须经由Director转发,Director易于成为系统瓶颈
    (3)支持端口映射,可修改请求报文的目标PORT
    (4)VS必须是Linux系统,RS可以是任意OS系
    
  • lvs-dr:操纵封装新的MAC地址

  • 1.客户端发送源地址为CIP,目标地址为VIP的请求报文,此时源MAC为CIP的MAC,目标MAC为VIP的MAC
    2.VS接收请求报文后将源MAC转换成RIP的MAC,目标MAC转换成RIP的MAC,发送给RS
    3.RS接收目标MAC为RIP的报文,返回响应报文到CIP
    请求报文和响应报文的源地址和目标地址不变
    DR模式的特点:
    1. Director和各RS都配置有VIP
    2. 确保前端路由器将目标IP为VIP的请求报文发往Director
    	在前端网关做静态绑定VIP和Director的MAC地址
    	在RS上使用arptables工具
    	arptables -A IN -d $VIP -j DROP
    	arptables -A OUT -s $VIP -j mangle --mangle-ip-s $RIP
    	在RS上修改内核参数以限制arp通告及应答级别
    	/proc/sys/net/ipv4/conf/all/arp_ignore
    	/proc/sys/net/ipv4/conf/all/arp_announce
    3. RS的RIP可以使用私网地址,也可以是公网地址;RIP与DIP在同一IP网络;RIP的网关不能指向DIP,以确保响应报文不会经由Director
    4. RS和Director要在同一个物理网络
    5. 请求报文要经由Director,但响应报文不经由Director,而由RS直接发往Client
    6. 不支持端口映射(端口不能修改)
    7. 无需开启 ip_forward
    8. RS可使用大多数OS系统
    
    
    echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
    echo 1 > /proc/sys/net/ipv4/conf/all/arp_announce
    echo 1 > /proc/sys/net/ipv4/conf/lo/arp_announce
    echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
    限制响应级别:arp_ignore
    0:默认值,表示可使用本地任意接口上配置的任意地址进行响应
    1:仅在请求的目标IP配置在本地主机的接收到请求报文的接口上时,才给予响应
    限制通告级别:arp_announce
    0:默认值,把本机所有接口的所有信息向每个接口的网络进行通告
    1:尽量避免将接口信息向非直接连接网络进行通告
    2:必须避免将接口信息向非本网络进行通告
    
  • lvs-tun:在原请求IP报文之外新加一个IP首部

  • 请求报文在通过VS时不改变源地址和目标地址,添加目标地址为RIP,源地址为DIP的首部,将报文发送给RS。RS返回源地址为RIP,目标地址为CIP的响应报文
    TUN模式特点:
    1. RIP和DIP可以不处于同一物理网络中,RS的网关一般不能指向DIP,且RIP可以和公网通信。也就是
    说集群节点可以跨互联网实现。DIP, VIP, RIP可以是公网地址
    2. RealServer的tun接口上需要配置VIP地址,以便接收director转发过来的数据包,以及作为响应的报文源IP
    3. Director转发给RealServer时需要借助隧道,隧道外层的IP头部的源IP是DIP,目标IP是RIP,而RealServer响应给客户端的IP头部是根据隧道内层的IP头分析得到的,源IP是VIP,目标IP是CIP
    4. 请求报文要经由Director,但响应不经由Director,响应由RealServer自己完成
    5. 不支持端口映射
    6. RS的OS须支持隧道功能
    
  • lvs-fullnat:修改请求报文的源和目标IP

调度算法

静态算法

仅根据算法本身进行调度

  • RR:roundrobin,轮询,较常用

    调度算法将外部请求按顺序轮流分配到集群中的真实服务器上,它均等地对待每一台服务器,而不管服务器上实际的连接数和系统负载。
    
  • WRR:Weighted RR,加权轮询,较常用

    调度算法根据真实服务器的不同处理能力来调度访问请求。这样可以保证处理能力强的服务器处理更多的访问流量。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。
    
  • SH:Source Hashing,实现session sticky,源IP地址hash;将来自于同一个IP地址的请求始终发往第一次挑中的RS,从而实现会话绑定

  • DH:Destination Hashing;目标地址哈希,第一次轮询调度至RS,后续将发往同一个目标地址的请求始终转发至第一次挑中的RS,典型使用场景是正向代理缓存场景中的负载均衡,如: Web缓存

  1. RR:roundrobin,轮询,较常用
  2. WRR:Weighted RR,加权轮询,较常用
  3. SH:Source Hashing,实现session sticky,源IP地址hash;将来自于同一个IP地址的请求始终发往
  4. 第一次挑中的RS,从而实现会话绑定
  5. DH:Destination Hashing;目标地址哈希,第一次轮询调度至RS,后续将发往同一个目标地址的
  6. 请求始终转发至第一次挑中的RS,典型使用场景是正向代理缓存场景中的负载均衡,如: Web缓存

动态算法

主要根据每RS当前的负载状态及调度算法进行调度Overhead=value 较小的RS将被调度

  • LC:least connections 适用于长连接应用

    Overhead=activeconns*256+inactiveconns
    调度器通过”最少连接”调度算法动态地将网络请求调度到已建立的链接数最少的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用”最小连接”调度算法可以较好地均衡负载
    
  • WLC:Weighted LC,默认调度方法,较常用

    Overhead=(activeconns*256+inactiveconns)/weight
    在集群系统中的服务器性能差异较大的情况下,调度器采用“加权最少链接”调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。
    
  • SED:Shortest Expection Delay,初始连接高权重优先,只检查活动连接,而不考虑非活动连接

    Overhead=(activeconns+1)*256/weight
    在WLC基础上改进,Overhead = (ACTIVE+1)*256/加权,不再考虑非活动状态,把当前处于活动状态的数目+1来实现,数目最小的,接受下次请求,+1的目的是为了考虑加权的时候,非活动连接过多缺陷:当权限过大的时候,会倒置空闲服务器一直处于无连接状态。
    
  • NQ:Never Queue,第一轮均匀分配,后续SED

    无需队列。如果有台 realserver的连接数=0就直接分配过去,不需要再进行sed运算,保证不会有一个主机很空间。在SED基础上无论+几,第二次一定给下一个,保证不会有一个主机不会很空闲着,不考虑非活动连接,才用NQ,SED要考虑活动状态连接,对于DNS的UDP不需要考虑非活动连接,而httpd的处于保持状态的服务就需要考虑非活动连接给服务器的压力。
    
  • LBLC:Locality-Based LC,动态的DH算法,使用场景:根据负载状态实现正向代理,实现Web Cache等

    基于局部性的最少链接”调度算法是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。该算法根据请求的目标IP地址找出该目标IP地址最近使用的服务器,若该服务器是可用的且没有超载,将请求发送到该服务器;若服务器不存在,或者该服务器超载且有服务器处于一半的工作负载,则用“最少链接”的原则选出一个可用的服务器,将请求发送到该服务器。
    
  • LBLCR:LBLC with Replication,带复制功能的LBLC,解决LBLC负载不均衡问题,从负载重的复制到负载轻的RS,,实现Web Cache等

    带复制的基于局部性最少链接”调度算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。它与LBLC算法的不同之处是它要维护从一个目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。该算法根据请求的目标IP地址找出该目标IP地址对应的服务器组,按”最小连接”原则从服务器组中选出一台服务器,若服务器没有超载,将请求发送到该服务器;若服务器超载,则按“最小连接”原则从这个集群中选出一台服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该服务器组有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度。
    

LVS工具

ipvsadm

  • Unit File: ipvsadm.service
  • 主程序:/usr/sbin/ipvsadm
  • 规则保存工具:/usr/sbin/ipvsadm-save
  • 规则重载工具:/usr/sbin/ipvsadm-restore
  • 配置文件:/etc/sysconfig/ipvsadm-config
  • ipvs调度规则文件:/etc/sysconfig/ipvsadm

ipvsadm命令用法

管理集群服务:增、改、删:
增、修改:
ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]]
删除:
ipvsadm -D -t|u|f service-address 

管理集群上的RS:增、改、删
增、改:
ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight] 
删:
ipvsadm -d -t|u|f service-address -r server-address
server-address:
     rip[:port] 如省略port,不作端口映射
选项:
lvs类型:
    -g: gateway, dr类型,默认
    -i: ipip, tun类型
    -m: masquerade, nat类型        
-w weight:权重

-C 清空定义内容
-Z [-t|u|f service-address] 清空计数器
-L|l [options]  查看
--numeric, -n:以数字形式输出地址和端口号
--exact:扩展信息,精确值     
--connection,-c:当前IPVS连接输出
--stats:统计信息
--rate :输出速率信息
给则保存
ipvsadm-save > /PATH/TO/IPVSADM_FILE
ipvsadm -S > /PATH/TO/IPVSADM_FILE
systemctl stop ipvsadm.service  #会自动保存规则至/etc/sysconfig/ipvsadm

规则重新载入
ipvsadm-restore < /PATH/FROM/IPVSADM_FILE
systemctl  start ipvsadm.service  #会自动加载/etc/sysconfig/ipvsadm中规则

防火墙标记实现分类

做标记
iptables -t mangle -A PREROUTING -d $vip -p $proto -m multiport --dports $port1,$port2,… -j MARK --set-mark NUMBER 
基于标记定义集群
ipvsadm -A -f NUMBER [options] 

持久连接

持久连接( lvs persistence )模板:实现无论使用任何调度算法,在一段时间内(默认360s ),能够 实现将来自同一个地址的请求始终发往同一个RS

ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]]

持久连接实现方式:

  • 每端口持久(PPC):每个端口定义为一个集群服务,每集群服务单独调度
  • 每防火墙标记持久(PFWMC):基于防火墙标记定义集群服务;可实现将多个端口上的应用统一调度,即所谓的port Affinity
  • 每客户端持久(PCC):基于0端口(表示所有服务)定义集群服务,即将客户端对所有应用的请求都调度至后端主机,必须定义为持久模式

案例实现

LVS-NAT模式实现

RS1:10.0.0.17
RS2:10.0.0.27
VS:VIP 10.0.0.18 DIP 192.168.10.129
VS配置
yum -y install ipvsadm
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.conf 
sysctl -p
ipvsadm -A -t 192.168.10.129:80 -s rr
ipvsadm -a -t 192.168.10.129:80 -r 10.0.0.17 -m
ipvsadm -a -t 192.168.10.129:80 -r 10.0.0.27 -m
[root@localhost ~]# 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.129:80 rr
  -> 10.0.0.17:80                 Masq    1      0          0         
  -> 10.0.0.27:80                 Masq    1      0          0 
  
RS1
BOOTPROTO=none
IPADDR=10.0.0.17
PREFIX=24
GATEWAY=10.0.0.18
NAME="eth0"
DEVICE="eth0"
ONBOOT="yes"
RS2
BOOTPROTO=none
IPADDR=10.0.0.27
PREFIX=24
GATEWAY=10.0.0.18
NAME="eth0"
DEVICE="eth0"
ONBOOT="yes"

测试:
root@ubuntu:~# curl 192.168.10.129
10.0.0.27
root@ubuntu:~# curl 192.168.10.129
10.0.0.17
root@ubuntu:~# curl 192.168.10.129
10.0.0.27
root@ubuntu:~# curl 192.168.10.129
10.0.0.17

LVS-DR模式实现

单网段

路由配置:
[root@localhost network-scripts]# cat ifcfg-eth0 ifcfg-eth1
TYPE=Ethernet
BOOTPROTO=none
NAME=eth0
DEVICE=eth0
ONBOOT=yes
IPADDR=10.0.0.18
NETMASK=255.255.255.0
GATEWAY=10.0.0.2
DNS1=8.8.8.8
TYPE=Ethernet
BOOTPROTO=none
NAME=eth1
DEVICE=eth1
ONBOOT=yes
IPADDR=192.168.10.200
NETMASK=255.255.255.0
DNS1=8.8.8.8
echo 'net.ipv4.ip_forward=1' > /etc/sysctl.conf 
sysctl -p

VS配置
TYPE=Ethernet
BOOTPROTO=none
NAME=eth0
DEVICE=eth0
ONBOOT=yes
IPADDR=10.0.0.28
NETMASK=255.255.255.0
DNS1=8.8.8.8

yum -y install ipvsadm
ip addr add 10.0.0.100/32 dev lo:1
ipvsadm -A -t 10.0.0.100:80 -s rr
ipvsadm -a -t 10.0.0.100:80 -r 10.0.0.17 -g
ipvsadm -a -t 10.0.0.100:80 -r 10.0.0.27 -g

RS1:
BOOTPROTO=none
IPADDR=10.0.0.17
PREFIX=24
NAME="eth0"
DEVICE="eth0"
ONBOOT="yes"

echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
ip addr add 10.0.0.100/32 dev lo:1


RS2:
BOOTPROTO=none
IPADDR=10.0.0.27
PREFIX=24
NAME="eth0"
DEVICE="eth0"
ONBOOT="yes"

echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
ip addr add 10.0.0.100/32 dev lo:1

多网段

路由ip:eth1:192.168.10.200 eth0:10.0.0.18 172.16.0.200
VS:lo:1 172.16.0.100/24 eth0:10.0.0.28
RS1:lo:1 172.16.0.100/32 eth0:10.0.0.17
RS2:lo:1 172.16.0.100/32 eth0:10.0.0.27

VS配置
ip addr add 172.16.0.100/32 dev lo:1
ipvsadm -A -t 172.16.0.100:80 -s rr
ipvsadm -a -t 172.16.0.100:80 -r 10.0.0.17 -g
ipvsadm -a -t 172.16.0.100:80 -r 10.0.0.27 -g

RS1 RS2
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_announce
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
ip addr add 172.16.0.100/32 dev lo:1

测试:
root@ubuntu:~# curl 172.16.0.100
10.0.0.27
root@ubuntu:~# curl 172.16.0.100
10.0.0.17
root@ubuntu:~# curl 172.16.0.100
10.0.0.27
root@ubuntu:~# curl 172.16.0.100
10.0.0.17

LVS-TUN模式实现

路由ip:eth1:192.168.10.200 eth0:10.0.0.18
VS:tunl0: 10.0.0.100/32 eth0:10.0.0.28
RS1:tunl0: 10.0.0.100/32 eth0:10.0.0.17
RS2:tunl0: 10.0.0.100/32 eth0:10.0.0.27

VS:
ip a a 10.0.0.100/32 dev tunl0
ip link set tunl0 up
ipvsadm -A -t 10.0.0.100:80 -s rr
ipvsadm -a -t 10.0.0.100:80 -r 10.0.0.17 -i
ipvsadm -a -t 10.0.0.100:80 -r 10.0.0.27 -i
[root@localhost ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.0.0.100:80 rr
  -> 10.0.0.17:80                 Tunnel  1      0          0         
  -> 10.0.0.27:80                 Tunnel  1      0          0 
RS1 RS2:
ip a a 10.0.0.100/32 dev tunl0
ip link set tunl0 up
echo "1" > /proc/sys/net/ipv4/conf/tunl0/arp_ignore 
echo "2" > /proc/sys/net/ipv4/conf/tunl0/arp_announce 
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore 
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce 
echo "0" > /proc/sys/net/ipv4/conf/tunl0/rp_filter
echo "0" > /proc/sys/net/ipv4/conf/all/rp_filter