vlambda博客
学习文章列表

实战 | LVS 负载均衡器理论基础及抓包分析

写在之前



LVS 是 Linux Virtual Server 的简写,即 Linux 虚拟服务器,是一个虚拟的服务器集群系统。本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一。(百科)

kube-proxy 的ipvs模式是 2015年由k8s社区大佬thockin提出的(https://github.com/kubernetes/kubernetes/issues/17470),在2017年由华为云团队实现的(https://github.com/kubernetes/kubernetes/issues/44063),在kubernetes v1.8中已经引入了ipvs模式。
ipvs模式的实现也是实现了ipvsadm这个核心组件,由于我们都使用LVS,对这个组件都有所了解,这里简单做下总结。


LVS 基础



LVS 核心组件

ipvsadm:用户空间的命令行工具,用于管理集群服务及集群服务上的RS等;(管理工具)

ipvs:工作于内核上的程序,可根据用户定义的集群实现请求转发;(内核模块)


LVS 专业术语

VS:Virtual Server (虚拟服务)

DS:Director Server(负载均衡器)

RS:Real Server (后端真实处理请求的服务器)

CIP: Client IP (用户端IP)

VIP:Director Virtual IP (负载均衡器虚拟 IP)

DIP:Director IP (负载均衡器 IP)

RIP:Real Server IP (后端请求处理服务器 IP)


工作原理


(图片来源于网络)


ipvs (IP Virtual Server) 实现了4层负载均衡,ipvs 运行在主机上,在Real Server 集群前充当LB(负载均衡器),ipvs 将基于 TCP 和 UDP 的服务请求转发到真实服务器上,并使真实服务器上面的服务,能够在前面 Director Server上、通过提供的 VIP 对外提供服务。

LVS 常用算法

RR(Round Robin):轮询调度,在不考虑每台服务器处理能力的情况下,轮询调度算法是把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重新开始循环;

WRR(Weight Round Robin):加权轮询,由于每台服务器的配置、跑业务类型不同,其处理能力也会不同,所以我们根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能够接受相应权值数据的服务请求;

LC(Least Connections):最少链接,将网络请求调度到已建立的链接数最少的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用“最小连接”调度算法可以较好地均衡负载;

WLC(Weighted Least Connections):加权最少链接,在集群系统中的服务器性能差异较大的情况下,调度器采用“加权最少链接”调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载,调度器可以自动问询真实服务器的负载情况,并动态地调整其权值;

除上面一些常用调度算法外,还有一些几个,如下:LBLC(Locality-Based Least Connections)基于局部性的最少链接、LBLCR(Locality-Based Least Connections with Replication)带复制的基于局部性最少链接、SED(Shortest Expected Delay Scheduling)最短的期望的延迟、NQ(Never Queue Scheduling NQ)最少队列调度;

LVS 模式

DR、NAT、隧道模式;(后面重点讲解)

LVS 组件安装

yum -y install ipvsadm


ipvsadm 常用配置参数

-A     添加虚拟服务VIP

-D     删除虚拟服务VIP

-L     查看虚拟服务VIP

-C     清除所有虚拟服务VIP


-t     指定虚拟服务及端口 VIP:Port

-r     指定真实服务及端口 RS:Port 

-w     指定权重

-m     指定转发模式为NAT

-g     指定转发模式为DR

 -i     指定转发模式为IPIP隧道


NAT 模式 



报文请求过程图

实战 | LVS 负载均衡器理论基础及抓包分析

(图片来源于网络)


报文请求过程分析

1. 当用户请求到达 DS 时,请求报文会先经过内核空间中的 PREROUTING 链,此时源 IP 为CIP,目的 IP 为 VIP;
2. 在 PREROUTING 规则链上进行检查目的IP是否为本机,如果是的话将数据包送至 INPUT 链;

4. POSTROUTING 链的作用就是选路,根据 INPUT 链中目标 IP,将数据包发送给 RS;

5. RS 发现数据包中的目标 IP 是自己的 IP,此时它会开始构建响应报文发并回给 DS, 此时报文的源IP为RIP,目标IP为 CIP;


NAT 实验
NAT 模式
IP 角色
1.65.15.140/24 CIP
1.65.15.140/24 DS (VIP 所在宿主)
100.222.111.1/24 VIP
1.65.15.143/24 RS
1.65.15.144/24 RS
NAT 模式时,LB 节点IP与RS节点IP可以不在同一个网络内,现为了模拟我们在 LB 节点添加一虚拟IP 如下,并测试连通性。
[root@master02 ~]# ip addr add 100.222.111.1/24 dev ens32
[root@master02 ~]# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
2: ens32: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:50:56:8e:53:c1 brd ff:ff:ff:ff:ff:ff
    inet 1.65.15.141/24 brd 1.65.15.255 scope global ens32
       valid_lft forever preferred_lft forever
    inet 100.222.111.1/24 scope global ens32
       valid_lft forever preferred_lft forever
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:46:24:ae:8c brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
[root@master02 ~]# ping -c 1 100.222.111.1
PING 100.222.111.1 (100.222.111.1) 56(84) bytes of data.
64 bytes from 100.222.111.1: icmp_seq=1 ttl=64 time=0.033 ms

--- 100.222.111.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.033/0.033/0.033/0.000 ms
[root@master02 ~]#


创建负载均衡service 

[root@master02 ~]# ipvsadm -A -t 100.222.111.1:8000 -s rr
[root@master02 ~]#


添加 RS 到指定的负载均衡器下

[root@master02 ~]# ipvsadm -a -t 100.222.111.1:8000 -r 1.65.15.143:80 -m
[root@master02 ~]# ipvsadm -a -t 100.222.111.1:8000 -r 1.65.15.144:80 -m
[root@master02 ~]#


在client上面访问VIP

[root@master01 ~]# ping -c 1 100.222.111.1
PING 100.222.111.1 (100.222.111.1) 56(84) bytes of data.

--- 100.222.111.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

[root@master01 ~]#


我们发现并不通,由于这个VIP是虚拟的,需要添加路由,添加静态路由如下。

[root@master01 ~]# ip route add 100.222.111.1 via 1.65.15.141 dev ens32
[root@master01 ~]#


继续测试连通性

[root@master01 ~]# ping -c 1 100.222.111.1
PING 100.222.111.1 (100.222.111.1) 56(84) bytes of data.
64 bytes from 100.222.111.1: icmp_seq=1 ttl=64 time=0.088 ms

--- 100.222.111.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.088/0.088/0.088/0.000 ms
[root@master01 ~]#


发现可以ping通了,我们接下来验证service 

[root@master01 ~]# curl -m 15 --retry 1 -sSL 100.222.111.1:8000
curl: (28) Connection timed out after 15001 milliseconds
[root@master01 ~]#


LB抓包

实战 | LVS 负载均衡器理论基础及抓包分析

RS 抓包如下

实战 | LVS 负载均衡器理论基础及抓包分析

[root@master02 ~]# iptables -t nat -A POSTROUTING -m ipvs --vaddr 100.222.111.1 --vport 8000 -j MASQUERADE
[root@master02 ~]# iptables -t mangle -A POSTROUTING -m ipvs --vaddr 100.222.111.1 --vport 8000 -j LOG --log-prefix '[k8svip ipvs]'
[root@master02 ~]#


[root@master01 ~]# curl -m 15 --retry 1 -sSL 100.222.111.1:8000
curl: (28) Connection timed out after 15001 milliseconds
[root@master01 ~]#


哪问题出在什么地方呢?由于PROC文件系统的/proc/sys/net/ipv4/vs/conntrack可控制IPVS是否对其连接启用Netfilter系统的conntrack功能,默认情况下是关闭状态,这里需要打开,如下。

[root@master02 ~]# sysctl net.ipv4.vs.conntrack=1
net.ipv4.vs.conntrack = 1
[root@master02 ~]#


下面这个图是是否开启conntrack功能的iptables日志对比,上面只是SYN,根本无法完成三次握手,缺少链路追踪,这里需要再开启conntrack功能。

实战 | LVS 负载均衡器理论基础及抓包分析

再次测试,成功。

[root@master01 ~]# curl -m 15 --retry 1 -sSL 100.222.111.1:8000
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
。。。。。
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@master01 ~]#


RS 抓包

实战 | LVS 负载均衡器理论基础及抓包分析

LB抓包

实战 | LVS 负载均衡器理论基础及抓包分析

到这里nat实验就完成了,可以看下数据包,源IP已经变成了LB的IP。


NAT 特性总结

2. 客户端的请求和响应报文都要经由 DS 转发,在大并发、大流量的场景中,DS有可能会成为系统瓶颈;

3. 支持端口映射;


DR 模式 



报文请求过程图


实战 | LVS 负载均衡器理论基础及抓包分析

(图片来源于网络)


报文请求过程分析

1. 当用户请求到达 DS 时,请求报文会先经过内核空间中的 PREROUTING 链,此时源IP为CIP,目的 IP 为 VIP;

2. 在 PREROUTING 规则链上进行检查目的IP是否为本机,如果是的话将数据包送至 INPUT 链;

6. 响应报文最终到客户端;


DR 实验
DR 模式
IP MAC 角色
1.65.15.140/24 00:50:56:8e:39:98 CIP
1.65.15.140/24 00:50:56:8e:53:c1 DS(VIP 所在宿主)
1.65.15.145/24 00:50:56:8e:53:c1 VIP
1.65.15.143/24 00:50:56:8e:00:47 RS
1.65.15.144/24 00:50:56:8e:0f:e8 RS
从DR模式原理可知,调度器只是修改请求报文的目的mac(二层转发),这就要求调度器和RS需要在同一个网段,并且也无需要开启ip_forward,所以需要分配一个同网段的IP 做为VIP;
[root@master02 ~]# ping -c 1 1.65.15.145
PING 1.65.15.145 (1.65.15.145) 56(84) bytes of data.
From 1.65.15.141 icmp_seq=1 Destination Host Unreachable


--- 1.65.15.145 ping statistics ---
1 packets transmitted, 0 received, +1 errors, 100% packet loss, time 0ms


[root@master02 ~]#

添加 VIP 网卡信息

[root@master02 ~]# ifconfig ens32:0 1.65.15.145/24 up
[root@master02 ~]#

创建 service 负载均衡

[root@master02 ~]# ipvsadm -A -t 1.65.15.145:80 -s rr
[root@master02 ~]#

把 RS 添加到负载均衡

[root@master02 ~]# ipvsadm -a -t 1.65.15.145:80 -r 1.65.15.143:80 -g
[root@master02 ~]# ipvsadm -a -t 1.65.15.145:80 -r 1.65.15.144:80 -g
[root@master02 ~]#

客户端连通性测试

[root@master01 ~]# ping -c 1 1.65.15.145
PING 1.65.15.145 (1.65.15.145) 56(84) bytes of data.
64 bytes from 1.65.15.145: icmp_seq=1 ttl=64 time=0.078 ms

--- 1.65.15.145 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.078/0.078/0.078/0.000 ms
[root@master01 ~]#

负载测试

[root@master01 ~]# curl -m 15 --retry 1 -sSL 1.65.15.145:80
curl: (7) Failed connect to 1.65.15.145:80; 没有到主机的路由
[root@master01 ~]#

发现负载服务不通,进行抓包分析

dr模式LB抓包

实战 | LVS 负载均衡器理论基础及抓包分析

dr模式RS抓包

实战 | LVS 负载均衡器理论基础及抓包分析

根据 DR 模式路由转发原理,LB上面源MAC地址修改为LB的MAC地址,而目标MAC地址修改为RS MAC地址,上图中已经发现MAC正常修改了,但为什么不通呢?在RS数据包中发现源IP和目标IP也都未修改,那么问题来了,我们Client期望访问的是RS(通过 mac 二次互访),但RS收到的目标IP却是LB上面的VIP,发现这个目标IP并不是自己的IP,因此不会通过 INPUT 链转发到用户空间,这时要不直接丢弃这个包,要不根据路由再次转发到其他地方,总之两种情况都不是我们期望的结果。那怎么办呢?如果想让RS接收这个包,必须得让RS有这个目标IP才行,不妨在lo上添加个虚拟IP,IP地址伪装成LB IP 1.65.15.145。所以需要在RS上面添加虚拟IP,并且添加一条路由如下。
[root@master03 ~]# ifconfig lo:0 1.65.15.145/32 up
[root@master03 ~]# route add -host 1.65.15.145 dev lo
[root@master03 ~]#

此时问题又来了,这就相当于在一个局域网内有两个相同的IP,IP重复了怎么办?办法就是隐藏这个虚拟网卡,不让它回复ARP,其他主机的neigh也就不可能知道有这么个网卡的存在了。

[root@node01 ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@node01 ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@node01 ~]#


因为我们在RS上都配置了VIP,因此此时是存在IP冲突的,当外部客户端向VIP发起请求时,会先发送arp请求,此时调度器和RS都会响应这个请求。如果某个RS响应了这个请求,则之后该客户端的请求就都发往该RS,并没有经过LVS,因此也就没有真正的负载均衡,LVS也就没有存在的意义。因此我们需要设置RS不响应对VIP的arp请求,这样外部客户端的所有对VIP的arp请求才会都解析到调度器上,然后经由LVS的调度器发往各个RS。

arp_announce=2,网卡在发送arp请求时使用出口网卡IP作为源IP。

测试连通性

[root@master01 ~]# curl 1.65.15.145:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
 
。。。。
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@master01 ~]#

RS抓包如下

实战 | LVS 负载均衡器理论基础及抓包分析

LB抓包如下

实战 | LVS 负载均衡器理论基础及抓包分析


DR 模式特性总结

1. 前端路由器将目标 IP 为 VIP 时的请求报文,发往DS,需要在前端网关做静态绑定,RS上使用 arptables,并且在RS上修改内核参数以限制 arp 通告及应答级别;

4. 请求报文要经由 DS,但响应时不经过 DS,而是由 RS 直接发往 客户端;

5. DR 模式不支持端口映射;


IPIP 模式



报文请求过程图


实战 | LVS 负载均衡器理论基础及抓包分析

(图片来源于网络)


报文请求过程分析

1. 当用户请求到达 DS 时,请求报文会先经过内核空间中的 PREROUTING 链,此时源IP为CIP,目的 IP 为 VIP;

2. 在 PREROUTING 规则链上进行检查目的IP是否为本机,如果是的话将数据包送至 INPUT 链;

3. 数据包到达INPUT链后,IPVS 会比对数据包请求的服务是否为集群服务,若是,在请求报文的首部再次封装一层 IP 报文,封装源 IP 为 DIP,目标 IP 为 RIP,然后发至POSTROUTING链,此时源 IP 为 DIP,目标 IP 为 RIP;

4. POSTROUTING 链根据最新封装的 IP 报文,将数据包发至 RS(因为在外层封装多了一层IP首部,所以可以理解为此时通过隧道传输);此时源 IP 为 DIP,目标 IP 为 RIP;

6. 响应报文最终送达至客户端;


IPIP 实验

IPIP模式
IP 角色
1.65.15.140 CIP
1.65.15.141 DS
1.65.15.145 VIP
1.65.15.143 RS
1.65.15.144 RS
DR 模式是通过MAC地址进行交换,只能限制在一个局域网内,而TUN隧道方式 ,是通过给数据包加上新的IP头部来实现,这个可以跨机房(可以实现异地容灾)、跨公网、主要是解决不能跨网的问题;

添加 VIP 网卡信息
# 配置 VIP
[root@master02 ~]# ifconfig ens32:1 1.65.15.145 netmask 255.255.255.0 up

#
 测试连通性
[root@master02 ~]# ping -c 1 1.65.15.145
PING 1.65.15.145 (1.65.15.145) 56(84) bytes of data.
64 bytes from 1.65.15.145: icmp_seq=1 ttl=64 time=0.026 ms

--- 1.65.15.145 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.026/0.026/0.026/0.000 ms
[root@master02 ~]#


创建负载均衡
[root@master02 ~]# ipvsadm -A -t 1.65.15.145:80 -s rr
[root@master02 ~]#


添加RS到LB


# 添加 RealServer 作为 VIP 的后端
[root@master02 ~]# ipvsadm -a -t 1.65.15.145:80 -r 1.65.15.143:80 -i
[root@master02 ~]# ipvsadm -a -t 1.65.15.145:80 -r 1.65.15.144:80 -i
[root@master02 ~]#


负载均衡器(LB)要开启转发功能 
[root@master02 ~]# echo 1 >/proc/sys/net/ipv4/ip_forward
[root@master02 ~]#


查看负载情况
[root@master02 ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 1.65.15.145:80 rr
  -> 1.65.15.143:80 Tunnel 1 0 0
  -> 1.65.15.144:80 Tunnel 1 0 0
[root@master02 ~]#


RealServer 配置tunl0 (所有RS服务器)
# 加载下 tunl 模式
[root@node01 ~]# modprobe ipip

#
 为 tunl0 网口配置 IP(即VIP)
[root@node01 ~]# ifconfig tunl0 1.65.15.145 netmask 255.255.255.255 up
[root@node01 ~]#


修改内核参数(所有RS服务器)

[root@node01 ~]# echo 0 > /proc/sys/net/ipv4/ip_forward
[root@node01 ~]# echo 1 > /proc/sys/net/ipv4/conf/tunl0/arp_ignore
[root@node01 ~]# echo 2 > /proc/sys/net/ipv4/conf/tunl0/arp_announce
[root@node01 ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@node01 ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
[root@node01 ~]# echo 0 > /proc/sys/net/ipv4/conf/tunl0/rp_filter
[root@node01 ~]# echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter


arp_ignore 与 arp_announce上面已经有详细说明,这里说下rp_filter,官方说明  https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt

1:开启严格的反向路径校验,对每个入访的数据包,通过指定网卡,校验其出访路径是否为最佳路径,如果不是最佳路径,则直接丢弃;(Linux 服务器默认是1)

其实这个参数和安全也息息相关:
1.   Distribute Deny of Service 即 分布式拒绝服务攻击,原理就是通过构造大量的无用数据包向 目标服务发起请求,占用目标服务主机大量的资源,还可能造成链路上面网络拥塞,进而影响到正常用户的访问,我们把这个参数设为1,严格校验数据包的反向路径,如果出访路径不合适,就直接丢弃数据包,这样避免过多的无效连接消耗Linux系统资源;


测试访问

[root@master01 ~]# curl -m 15 --retry 1 -sSL http://1.65.15.145
<!DOCTYPE html>
<html>
<head>
。。。
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
[root@master01 ~]#


RS 抓包

实战 | LVS 负载均衡器理论基础及抓包分析

图一


实战 | LVS 负载均衡器理论基础及抓包分析

图二

通过RS抓包,可以清楚看出IPIP隧道数据包封装的格式,但回包的时候,直接就回了;


DS抓包(转发server)

这个数据包,感觉有问题,后面我再查下,分析下原因,如果有人知道,也可交流;


IPIP 特性总结

2. RS 的网关不能、也不可能指向DIP;

3. 请求报文要经由 DS,但响应不经过 DS;

4. 不支持端口映射;

5. RS 的 OS 得支持隧道功能;


总结



对比项 NAT 模式 DR模式 IPIP模式
实现要点 地址转化 MAC转化 封装IP
复杂度 简单 复杂 复杂
操作系统 任何操作系统 服务器支持虚拟网卡,并且能够禁用设备的ARP响应 须支持IP隧道模式,目前只有Linux
网络 私有地址即可 合法局域网地址,并且必须同一网段 可私网IP、可公网IP
支持RS数量 依赖均衡器处理能力而定,一般支持10~20个 支持上100个RS 支持上100个RS
网关要求 均衡器(DS)即为RS网关 RS同自己的网关或路由直接连接,不经过负载均衡器 RS同自己的网关或路由直接连接,不经过负载均衡器
安全性 较好,采用内部IP 采用公网IP时,较差,结点完全暴露 采用公网IP时,较差,结点完全暴露
IP要求 仅需要一个合法的IP作为VIP 除VIP外,还需要RS拥有合法的IP地址,可以直接路由至客户端 除VIP外,还需要RS拥有合法的IP地址,可以直接路由至客户端
扩展性(主要从IP网段分析) 很好


由于各个公司实际情况不同、业务类型不同、容灾策略、基础架构不同,需要结合自己公司的情况进行分析,然后选择合适的解决方案。



后台回复“加群”,带你进入高手如云交流群


推荐阅读:












下载



喜欢,就给我一个“在看”