LVS(Linux Virtual Server)作者为章文嵩博士,是一款传输层负载均衡调度器。
vs:Virtual Server
rs:Real Server
CIP:Client IP
VIP: Virtual serve IP
RIP: Real server IP
DIP: Director IP
当请求报文到达vs,vs修改目的IP:vip→rip,使其能够路由到后端rs
当响应报文到达vs,vs修改源IP:rip→vip,使vs能够完成代理工作
我们可知:
当请求报文到达vs,vs修改源mac为dip的mac地址,经由交换机二层寻址到rs
rs以vip作为源地址封装,按照正常发包过程到pc
我们可知:
当请求报文到达vs,vs外层封装一层源目IP,通过internet找到rs
rs解开外层封装IP得到真实地址,直接封装vip和cip,将响应报文通过internet发给pc
vip、dip、rip处于同一网段
我们可知:
RR(roundrobin)轮询
调度器会将所有的请求平均分配给每个服务器,可认为RR是后端rs的权重一样的WRR
WRR(Weighted RR)加权轮询
在RR的基础上添加权重,服务器性能较高的应分配较大权重,调度器转发给其请求更多,即它能处理更多请求
SH(Source Hashing)源地址hash
对请求的源地址进行hash,用于反向代理,保证同一ip的请求总是发往同一后端rs。但由于nat,会导致调度器请求分配不均
DH(Destination Hashing)目标地址hash
对请求的目的地址进行hash,用于正向代理
LC(least connections)最少连接
动态评估后端rs的连接数,调度器将连接分配给最少连接数的服务器,可认为LC是后端rs权重一样的WLC
算法:overhead=activeconns*256+inactiveconns
overhead谁小选谁
WLC(Weighted LC)加权最少连接
在LC的基础上添加权重,服务器性能较高的应分配较大权重,调度器转发给其请求更多,即它能处理更多请求
算法:overhead=(activeconns*256+inactiveconns)/weight
overhead谁小选谁
SED(Shortest Expection Delay)最短期望延迟
基于WLC
算法:overhead=(activeconns+1)*256/weight
overhead谁小选谁
NQ(Never Queue)永不排队
改进的SED
后端rs如果有连接数为0的直接分配请求,当后端所有rs的连接数不为0,进行SED
LBLC(Locality-Based Least-Connection)基于局部性的最少连接
动态的DH算法,对目的地址hash,找到对应后端rs,如果该rs没有超载荷,则请求分配给它,如果超载荷,则使用LC选出连接数最少的rs进行分配
LBLCR (Locality-Based Least-Connection with Replication)带复制的基于局部性的最少链接
LBLC算法维护从一个目标IP地址到一台服务器的映射,而LBLCR算法是维护从一个 目标IP地址到一组服务器的映射。对目的地址hash,找到对应的后端服务器组,在按照LC选出组中连接数最少的rs,若该rs未超载,则分配请求;若该rs超载,则从整个集群中按LC找出连接数最小的rs进行分配,并将rs添加进这个组。同时,服务器组一段时间内未修改,则将最忙的服务器从组中删除,以降低复制的程度
ipvs工作在TCP/IP的第四层,与netfilter一样是直接工作在内核。netfilter是使用iptables管理,同样ipvs也有管理工具ipvsadm
查看内核是否支持ipvs
[root@node1 ~]# grep -i -A 7 "# IPVS transport protocol load balancing support" /boot/config-4.18.0-147.el8.x86_64
# IPVS transport protocol load balancing support
#
CONFIG_IP_VS_PROTO_TCP=y
CONFIG_IP_VS_PROTO_UDP=y
CONFIG_IP_VS_PROTO_AH_ESP=y
CONFIG_IP_VS_PROTO_ESP=y
CONFIG_IP_VS_PROTO_AH=y
CONFIG_IP_VS_PROTO_SCTP=y
可确认支持TCP、UDP、AH、ESP、AH_ESP、SCTP协议的负载均衡
[root@node1 ~]# grep -i -A 14 "# IPVS scheduler" /boot/config-4.18.0-147.el8.x86_64
# IPVS scheduler
#
CONFIG_IP_VS_RR=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_LC=m
CONFIG_IP_VS_WLC=m
CONFIG_IP_VS_FO=m
CONFIG_IP_VS_OVF=m
CONFIG_IP_VS_LBLC=m
CONFIG_IP_VS_LBLCR=m
CONFIG_IP_VS_DH=m
CONFIG_IP_VS_SH=m
# CONFIG_IP_VS_MH is not set
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m
查看支持与不支持的调度算法
[root@node1 ~]# yum search ipvsadm
ipvsadm.x86_64 : Utility to administer the Linux Virtual Server
[root@node1 ~]# yum info ipvsadm
Name : ipvsadm
Version : 1.29
Release : 8.el8
Architecture : x86_64
Size : 57 k
Source : ipvsadm-1.29-8.el8.src.rpm
Repository : AppStream
Summary : Utility to administer the Linux Virtual Server
URL : https://kernel.org/pub/linux/utils/kernel/ipvsadm/
License : GPLv2+
Description : ipvsadm is used to setup, maintain, and inspect the virtual server
: table in the Linux kernel. The Linux Virtual Server can be used to
: build scalable network services based on a cluster of two or more
: nodes. The active node of the cluster redirects service requests to a
: collection of server hosts that will actually perform the
: services. Supported Features include:
: - two transport layer (layer-4) protocols (TCP and UDP)
: - three packet-forwarding methods (NAT, tunneling, and direct routing)
: - eight load balancing algorithms (round robin, weighted round robin,
: least-connection, weighted least-connection, locality-based
: least-connection, locality-based least-connection with
: replication, destination-hashing, and source-hashing)
[root@node1 ~]# yum -y install ipvsadm
Installed:
ipvsadm-1.29-8.el8.x86_64
Complete!
程序文件:
[root@node1 ~]# rpm -ql ipvsadm
/etc/sysconfig/ipvsadm-config #配置文件
/usr/lib/systemd/system/ipvsadm.service #服务文件
/usr/sbin/ipvsadm #管理工具
/usr/sbin/ipvsadm-restore #规则重载
/usr/sbin/ipvsadm-save #规则保存
[root@node1 ~]# ipvsadm -h
Commands:
--add-service -A 添加VS
--edit-service -E 编辑VS
--delete-service -D 删除VS
--clear -C 清空整张表
--restore -R 从标准输入重载
--save -S 从标准输出保存
--add-server -a 添加RS
--edit-server -e 编辑RS
--delete-server -d 删除RS
--list -L|-l 列出整张表
--zero -Z 清空计数
--set tcp tcpfin udp 设置连接超时
--start-daemon 开启连接同步后台进程
--stop-daemon 停止连接同步后台进程
--help -h 帮助
virtual-service:
--tcp-service|-t service-address 服务器地址ip:port,tcp协议
--udp-service|-u service-address 服务器地址ip:port,udp协议
--sctp-service service-address 服务器地址ip:port,sctp协议
--fwmark-service|-f fwmark 防火墙标记ipv4
Options:
--ipv6 -6 防火墙标记ipv6
--scheduler -s scheduler 负载均衡算法rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq,
默认wlc.
--persistent -p [timeout] 持久连接
--real-server -r server-address RS地址
--gatewaying -g 网关(DR)
--ipip -i IP封装(tunneling)
--masquerading -m 地址伪装(NAT)
--weight -w weight RS的权重
--u-threshold -x uthreshold 连接上限
--l-threshold -y lthreshold 连接下限
--connection -c 输出当前ipvs连接
--timeout 输出超时时间(tcp tcpfin udp)
--daemon 输出后台进程信息
--stats 输出统计信息
--rate 输出速率信息
--exact 显示精确信息
--thresholds 输出阈值信息
--persistent-conn 输出持久连接信息
--ops -o 单包调度
--numeric -n 数字格式显示ip和port
ipvsadm -A -t|u|f service-address [-s scheduler] [-p [timeout]]
ipvs -l [-c] [-n] [--state] [--rate]
ipvs -E -t|u|f service-address [-s scheduler] [-p [timeout]]
修改时-t|u|f service-address即为选定要修改的server
ipvsadm -D -t|u|f service-address
ipvsadm -a -t|u|f service-address -r server-address [-g|i|m] [-w weight]
ipvs -l [-c] [-n] [--state] [--rate]
ipvsadm -e -t|u|f service-address -r server-address [-g|i|m] [-w weight]
ipvsadm -d -t|u|f service-address -r server-address
ipvsadm -C
ipvsadm -Z [-t|u|f service-address]
ipvsadm-save > /PATH/IPVSADM_FILE
或
ipvsadm -S > /PATH/IPVSADM_FILE
ipvsadm-restore < /PATH/IPVSADM_FILE
或
ipvsadm -R < /PATH/IPVSADM_FILE
1、删除DIP的网关
GATEWAY IP #不在网络配置文件中指明网关
ip route del default via IP #如果指明网关可删除默认路由
2、打开网络转发
echo 1 > /proc/sys/net/ipv4/ip_forward
3、ipvsadm配置
ipvsadm -A -t 10.10.20.10:80 -s wlc
ipvsadm -a -t 10.10.20.10:80 -r 10.10.10.20:80 -m -w 2
ipvsadm -a -t 10.10.20.10:80 -r 10.10.10.21:80 -m -w 2
1、添加默认网关
ip route add default via 10.10.10.10 dev ens33
arp_ignore
控制收到arp请求时,arp响应的动作
arp_announce
控制系统在对外发送arp请求时,如何选择arp请求数据包的源IP地址
#!/bin/bash
vip="10.10.10.9"
vprefix=32
dip="10.10.10.10"
vport="80"
rip=("10.10.10.20" "10.10.10.21")
weight=("1" "1")
rport="80"
sheduler="wlc"
type="-g"
iface="net1"
lockFile="/var/lock/subsys/ipvsadm"
case $1 in
start)
#增加ip地址
ip tuntap add mode tap dev $iface &> /dev/null
ip addr add $vip/$vprefix dev $iface &> /dev/null
ip link set $iface up
#添加路由
ip route add $vip/$vprefix dev $iface &> /dev/null
#清空防火墙规则
iptables -F
iptables -X
iptables -Z
#开启ip转发
echo 1 > /proc/sys/net/ipv4/ip_forward
#清空ipvs规则
ipvsadm -C
#添加directory规则
ipvsadm -A -t $vip:$vport -s $sheduler
#添加realserver规则
declare count=0
for i in ${rip[*]} ; do
ipvsadm -a -t $vip:$vport -r $i:$rport $type -w ${weight[$count]}
let count++
done
#创建锁文件
touch $lockFile
;;
stop)
#判断服务是否启动
if [ ! -e $lockFile ] ; then
echo "ipvsadm is stopped"
else
#删除ip地址
ip tuntap del mode tap $iface
#ip addr del $vip/$vprefix dev $iface &> /dev/null
#关闭ip转发
echo 0 > /proc/sys/net/ipv4/ip_forward
#清空ipvs规则
ipvsadm -C
#删除锁文件
rm -fr $lockFile
fi
;;
status)
if [ ! -e $lockFile ] ; then
echo "ipvsadm is stopped"
else
echo "ipvsadm is running"
fi
;;
*)
echo "Usage: $0 {start | stop |status}"
exit 1
;;
esac
#!/bin/bash
vip="10.10.10.9"
vprefix="32"
iface="net1"
case $1 in
start)
#配置ip
ip tuntap add mode tap dev $iface &> /dev/null
ip addr add $vip/$vprefix dev $iface &> /dev/null
ip link set $iface up
#配置路由
ip route add $vip/$vprefix dev $iface &> /dev/null
#关闭arp
echo 1 >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo 1 >/proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 >/proc/sys/net/ipv4/conf/$iface/arp_ignore
echo 2 >/proc/sys/net/ipv4/conf/lo/arp_announce
echo 2 >/proc/sys/net/ipv4/conf/all/arp_announce
echo 2 >/proc/sys/net/ipv4/conf/all/arp_announce
;;
stop)
#恢复arp
echo 0 >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo 0 >/proc/sys/net/ipv4/conf/all/arp_ignore
echo 0 >/proc/sys/net/ipv4/conf/lo/arp_announce
echo 0 >/proc/sys/net/ipv4/conf/all/arp_announce
#删除ip
ip tuntap del mode tap dev $iface
;;
*)
echo "Usage: $0 {start | stop |status}"
exit 1
;;
esac
#!/bin/bash
vip="10.10.10.9"
vport="80"
dip="10.10.10.10"
rip=("10.10.10.20" "10.10.10.30")
weight=("1" "1")
declare -a status
rport="80"
sheduler="wlc"
type="-g"
chknum=3
online=0
#添加rs
addrs(){
ipvsadm -a -t $vip:$vport -r $1:$rport $type -w $2 &> /dev/null
if [ $? -eq 0 ]; then
let online++
return 0
else
return 1
fi
}
#删除rs
delrs(){
ipvsadm -d -t $vip:$vport -r $1:$rport
if [ $? -eq 0 ]; then
let online--
return 0
else
return 1
fi
}
#检测rs
chkrs(){
local i=1
while [ $i -le $chknum ]; do
curl --connect-timeout 1 -I http://$1 &> /dev/null
[ $? -eq 0 ] && return 0
let i++
done
return 1
}
#初始rs状态
initrs(){
local i=0
for r in ${rip[*]}; do
ipvsadm -ln | grep "$r:$rport" &> /dev/null
if [ $? -eq 0 ]; then
status[$i]=1
let online++
else
status[$i]=0
fi
let i++
done
}
initrs
#for s in ${status[*]}; do
# echo $s
#done
while :; do
i=0
for r in ${rip[*]}; do
if chkrs $r; then
if [ ${status[$i]} -eq 0 ]; then
addrs $r ${weight[$i]}
[ $? -eq 0 ] && status[$i]=1
fi
else
echo $i
if [ ${status[$i]} -eq 1 ]; then
delrs $r
[ $? -eq 0 ] && status[$i]=0
fi
fi
let i++
done
if [ $online -eq 0 ]; then
ipvsadm -ln | grep "127.0.0.1:80" &> /dev/null
[ $? -eq 0 ] || ipvsadm -a -t $vip:$vport -r 127.0.0.1:80 $type -w 1
else
ipvsadm -ln | grep "127.0.0.1:80" &> /dev/null
[ $? -eq 0 ] && ipvsadm -d -t $vip:$vport -r 127.0.0.1:80
fi
sleep 1
done