ipvs

ipvs是个4层负载均衡器,常常用于服务的高可用

ipvs已经合并到linux内核当中,用户层面使用ipvsadm

安装ipvsadm

yum install ipvsadm

原理

ipvs

整个动作在内核态完成,跳过了一些链

术语

缩写 全写 说明
CIP Client IP 客户端ip
VIP Virtual IP 虚拟ip
DIP Director Server IP 负载均衡ip
RIP Real Servier IP 真正的后端服务ip
DS Director Server 部署负载均衡的服务器
RS Real Server 后端服务器

三种模式

类型 IP
CIP 10.23.18.81
VIP 10.23.59.162
DS 10.23.12.87
RS1 10.23.197.23
RS2 10.23.9.198
NAT
  • 本质是个dnat
  • 流量出入都经过DR
  • 来回流量都从dr过dr会成为瓶颈
  • 同一个网段时RS的默认网关需要指向DS,且本网段的路由需要删除不然不会通过默认路由到DR

x

NAT部署
  • 在DS配置规则
echo 1 >/proc/sys/net/ipv4/ip_forward

export VIP=10.23.59.162
export RS1=10.23.197.23
export RS2=10.23.9.198

ipvsadm -A -t $VIP:80 -s rr
ipvsadm -a -t $VIP:80 -r $RS1 -m
ipvsadm -a -t $VIP:80 -r $RS2 -m
  • 查看规则
[root@10-23-12-87 ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  10.23.59.162:80 rr
  -> 10.23.9.198:80               Masq    1      0          2
  -> 10.23.197.23:80              Masq    1      0          1
  • 在RS上部署一个httpd用于判断访问到哪那台机器
yum -y install httpd && systemctl start httpd
echo "i am rs $HOSTNAME" > /var/www/html/index.html
  • 此时在rs上curl 10.23.59.162这个vip会轮询访问,此时cip是自己
[root@10-23-12-87 ~]# curl 10.23.59.162
i am rs 10-23-9-198
[root@10-23-12-87 ~]# curl 10.23.59.162
i am rs 10-23-197-23
[root@10-23-12-87 ~]#
同一个网络说明

client此时并不知道vip这个地址在哪,所以需要在dr上绑定vip,让隔壁的邻居知道vip的mac

且由于vip和rs的地址都在同一个网段默认会通过二层直接到client,未经过dr的nat,导致client不认回包而被丢弃因此需要在rs上设置默认网关为dr

  • dr执行
ip addr add 10.23.59.162 dev eth0
  • RS上执行,将默认路由指向dr
export DS=10.23.12.87

# 设置默认路由
ip route replace default via $DS
# 删除路由
ip r del 10.23.0.0/16 dev eth0 proto kernel scope link src 10.23.197.23
流量转发路径

cl
dr
rs

通过抓包我可以看到client请求vip之后,dr接受到会将vip替换成rip然后发送给rs
rs收到之后因为会路由设置会发送给dr,dr将src地址再改回vip

rs

DR
  • rs和ds需要在一个二层中

  • dr模式中客户端请求vip流量从ds通过修改mac地址来达到负载均衡

  • 由于没有修改ip地址所以rs上需要添加vip到lo或者dummy类型的网口上,不然rs发现请求的ip不在本机就会被丢弃

  • 由于rs的lo或者dummy的网卡上配置的有vip为了防止rs响应vip的请求,所以需要修改arp配置

  • 不支持端口映射

DR部署
  • DS配置
export VIP=10.23.59.162
export RS1=10.23.197.23
export RS2=10.23.9.198

ip link add vip type dummy
ip addr add $VIP dev vip

ipvsadm -A -t $VIP:80 -s rr
ipvsadm -a -t $VIP:80 -r $RS1:80 -g
ipvsadm -a -t $VIP:80 -r $RS2:80 -g
  • 两个RS配置
# 部署http服务用于区分是否负载均衡
yum -y install httpd && systemctl start httpd
echo "i am rs $HOSTNAME" > /var/www/html/index.html

# 配置arp
echo 1 >/proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 >/proc/sys/net/ipv4/conf/all/arp_announce

export VIP=10.23.59.162

# 配置vip网卡(用dummy和lo都可以)
ip link add vip type dummy
ip addr add $VIP dev vip
  • Client

添加路由,原则来说因为在同一个交换机中直接通过二层,但是有些vpc的子网不是通过vpc创建的ip不会转发

也可以查看云厂商的文档如vip或者辅助ip等来作为vip

export VIP=10.23.59.162
export DR=10.23.12.87

ip r add $VIP/32 via $DR dev eth0
  • 测试
[root@10-23-18-81 ~]# curl 10.23.59.162
i am rs 10-23-197-23
[root@10-23-18-81 ~]# curl 10.23.59.162
i am rs 10-23-9-198
流量抓包

dr

dr

图中可看出dr将mac地址换成类似rs的mac地址

隧道(IPIP)
隧道(IPIP)部署
  • DR配置
export VIP=10.23.59.162
export RS1=10.23.197.23
export RS2=10.23.9.198

ipvsadm -A -t $VIP:80 -s rr
ipvsadm -a -t $VIP:80 -r $RS1:80 -i
ipvsadm -a -t $VIP:80 -r $RS2:80 -i
  • RS
# 加载内部模块
modprobe ipip

export VIP=10.23.59.162
# 将vip添加到ipip隧道网卡
ip addr add $VIP 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
IPIP流量分析

ipip

ipip

由于实验环境在同一个网段所以需要对arp响应进行处理

内核参数

内核参数的文档

https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

arp_ignore

设置使用那个网卡的mac和ip用来请求arp,即arp请求的src_mac和src_ip

  • 0(默认):将任何网卡的地址响应出去,而不关系该ip是否在接受的网卡上
  • 1:只响应目标ip接受网卡的地址
  • 2:只响应目标ip接受网卡的地址,且需要在同网段
  • 3:请求的地址作用域为host的不响应,只有作用域为globallink的才响应
  • 4-7:保留
  • 8:任何arp都不响应

在dr模式中每个rs上都配置了vip的地址如果不设置arp_ignore为1则会响应vip的arp请求使客户端的请求绕过了ds直接到了rs

arp_announce

设置使用那个网卡的mac和ip用来响应arp请求,既arp响应的dst_mac和dst_ip

  • 0:使用任何配置在本接口上的地址响应
  • 1:尽量避免使用不属于该发送网卡子网的本地地址作为发送arp请求的源IP地址
  • 2:忽略IP数据包的源IP地址,选择该发送网卡上最合适的本地地址作为arp请求的源IP地址
rp_filter

反向路径过滤

  • 0:不校验
  • 1(默认):严格的校验,每个数据包都进行校验,校验反向路径通过特定的接口是否是最佳路径,如不是则丢弃
  • 2:宽松模式。只校验通过任意接口是否可达,如果不通则丢弃
  • 取conf/{all,interface}/rp_filter中的最大值

负载均衡算法

  • rr(轮询)
  • wrr(权重)
  • lc(最后连接)
  • wlc(权重)
  • lblc(本地最后连接)
  • lblcr(带复制的本地最后连接)
  • dh(目的地址哈希)
  • sh(源地址哈希)
  • sed(最小期望延迟)
  • nq(永不排队)

ipvsadm常用命令

# 查看规则
ipvsadm -L

# 查看指定规则
ipvsadm -L -t 10.0.0.1:80

# 查看链接
ipvsadm -l -c

# 清理所有规则
ipvsadm -c

# 清空计数器
ipvsadm -Z

# 添加一个虚拟服务器,算法为轮询
ipvsadm -A -t 10.0.0.1:80 -s rr

# 删除一个虚拟服务,同时删除RS
ipvsadm -D -t 10.0.0.1:80

# 修改一个服务,将算法修改为wlc
ipvsadm -E -t 10.0.0.1:80 -s wlc

# 添加一个RS,nat模式
ipvsadm -a -t 10.0.0.1:80 -r 192.168.32.129:80 -m

# 添加一个RS,路由模式,权重为3
ipvsadm -a -t 10.0.0.1:80 -r 192.168.32.129:80 -g -w 3

# 添加一个RS,ipip隧道模式
ipvsadm -a -t 10.0.0.1:80 -r 192.168.32.129:80 -i

# 修改rs 将此rs的模式改为ipip权重为2
ipvsadm -e -t 10.0.0.1:80 -r 192.168.32.129:80 -i -w 2

# 删除一个RS
ipvsadm -d -t 10.0.0.1:80 -r 192.168.32.129:80

# 查看转发情况
ipvsadm -L -n -c

# 保存配置
ipvsadm -S -n >ipvs.conf

# 读取配置
ipvsadm -R < ipvs.conf

参考资料

https://www.cnblogs.com/laolieren/p/lvs_explained.html
https://www.cnblogs.com/klb561/p/9215667.html
https://www.jianshu.com/p/734640384fda
https://www.cnblogs.com/f-ck-need-u/p/8472744.html