实战LVS三种负载均衡模式

LVS简介

LVS是章文嵩开发的一个国产开源负载均衡软件,中文官网为http://www.linuxvirtualserver.org/zh/index.html 。LVS最初是他在大学期间的玩具,随着后来使用的用户越来越多,LVS也越来越完善,最终集成到了Linux的内核中。其全称是Linux virtual server,即Linux虚拟服务器。之所以是虚拟服务器,是因为LVS自身是个负载均衡器(director),不直接处理请求,而是将请求转发至位于它后端真正的服务器realserver上。

LVS是四层(传输层tcp/udp)、七层(应用层)的负载均衡工具,只不过大众一般都使用它的四层负载均衡功能ipvs,而七层的内容分发负载工具ktcpvs(kernel tcp virtual server)不怎么完善,使用的人并不多。ipvs是集成在内核中的框架,可以通过用户空间的程序ipvsadm工具来管理,该工具可以定义一些规则来管理内核中的ipvs。就像iptables和netfilter的关系一样。

LVS三种模式

首先要解释的是LVS相关的几种IP:

  • DS:Director Server。指的是前端负载均衡器节点
  • RS:Real Server。后端真实的工作服务器

  • VIP:virtual IP,LVS服务器上接收外网数据包的网卡IP地址。

  • DIP:director IP,LVS服务器上转发数据包到realserver的网卡IP地址。
  • RIP:realserver(常简称为RS)上接收Director转发数据包的IP,即提供服务的服务器IP。
  • CIP:客户端的IP。

LVS的三种工作模式:通过网络地址转换(NAT)将一组服务器构成一个高性能的、高可用的虚拟服务器,是VS/NAT技术。在分析VS/NAT的缺点和网络服务的非对称性的基础上,提出了通过IP隧道实现虚拟服务器的方法VS/TUN(Virtual Server via IP Tunneling),和通过直接路由实现虚拟服务器的方法VS/DR(Virtual Server via Direct Routing),它们可以极大地提高系统的伸缩性。

LVS NAT模式

用户请求LVS到达director,director将请求的报文的目的IP改为RIP,同时将报文的目标端口也改为realserver的相应端口,最后将报文发送到realserver上,realserver将数据返回给director,director再把数据发送给用户。

(1). 当用户请求到达 Director Server,此时请求的数据报文会先到内核空间的 PREROUTING 链。 此时报文的源 IP 为 CIP,目标 IP 为 VIP
(2). PREROUTING 检查发现数据包的目标 IP 是本机,将数据包送至 INPUT 链
(3). IPVS 比对数据包请求的服务是否为集群服务,若是,修改数据包的目标 IP 地址为后端服务器 IP,然后将数据包发至 POSTROUTING 链。 此时报文的源 IP 为 CIP,目标 IP 为 RIP
(4). POSTROUTING 链通过选路,将数据包发送给 Real Server
(5). Real Server 比对发现目标为自己的 IP,开始构建响应报文发回给 Director Server。 此时报文的源 IP 为 RIP,目标 IP 为 CIP
(6). Director Server 在响应客户端前,此时会将源 IP 地址修改为自己的 VIP 地址,然后响应给客户端。 此时报文的源 IP 为 VIP,目标 IP 为 CIP

LVS NAT特性:

  • NAT模式修改的是目的ip,直接走的是switch不需要修改mac地址,所以VIP和RIP不需要在同一个网段内
  • NAT的包的进出都需要经过LVS,所以LVS可能会成为一个系统的瓶颈问题

LVS TUN原理

用户请求LVS到达director,director通过IP-TUN加密技术将请求报文的包封装到一个新的IP包里面,目的IP为VIP(不变),然后director将报文发送到realserver,realserver基于IP-TUN解密,然后解析出来包的目的为VIP,检测网卡是否绑定了VIP,绑定了就处理这个包,如果在同一个网段,将请求直接返回给用户,否则通过网关返回给用户;如果没有绑定VIP就直接丢掉这个包。

img

交互过程:

(1) 当用户请求到达 Director Server,此时请求的数据报文会先到内核空间的 PREROUTING 链。 此时报文的源 IP 为 CIP,目标 IP 为 VIP 。
(2) PREROUTING 检查发现数据包的目标 IP 是本机,将数据包送至 INPUT 链
(3) IPVS 比对数据包请求的服务是否为集群服务,若是,在请求报文的首部再次封装一层 IP 报文,封装源 IP 为 DIP,目标 IP 为 RIP。然后发至 POSTROUTING 链。 此时源 IP 为 DIP,目标 IP 为 RIP
(4) POSTROUTING 链根据最新封装的 IP 报文,将数据包发至 RS(因为在外层封装多了一层 IP 首部,所以可以理解为此时通过隧道传输)。 此时源 IP 为 DIP,目标 IP 为 RIP
(5) RS 接收到报文后发现是自己的 IP 地址,就将报文接收下来,拆除掉最外层的 IP 后,会发现里面还有一层 IP 首部,而且目标是自己的 lo 接口 VIP,那么此时 RS 开始处理此请求,处理完成之后,通过 lo 接口送给 eth0 网卡,然后向外传递。 此时的源 IP 地址为 VIP,目标 IP 为 CIP
(6) 响应报文最终送达至客户端

LVS TUN特性:

  • TUNNEL必须在所有的realserver上绑定VIP
  • realserver直接把包发给client
  • 隧道模式运维起来会比较难,所以一般不用

LVS DR模式

用户请求LVS到达director,director将请求的报文的目的MAC地址改为后端的realserver的MAC地址,目的IP为VIP(不变),源IP为client IP地址(不变),然后director将报文发送到realserver,realserver检测到目的地址为自己本地的VIP,如果在同一网段,将请求直接返回给用户,如果用户跟realserver不在同一个网段,则需要通过网关返回给用户。

img

LVS DR特性:

  • 前端路由将目标地址为VIP报文统统发给Director Server
  • RS跟Director Server必须有一个网卡在同一个物理网络中
  • 所有的请求报文经由Director Server,但响应报文必须不能进过Director Server
  • 所有的real server机器上都有VIP地址

三种模式比较

  • 是否需要VIP和realserver在同一网段:DR模式因为只修改包的MAC地址,需要通过ARP广播找到realserver,所以VIP和realserver必须在同一个网段,也就是说DR模式需要先确认这个IP是否只能挂在这个LVS下面;其他模式因为都会修改目的地址为realserver的IP地址,所以不需要在同一个网段内。
  • 是否需要在realserver上绑定VIP:realserver在收到包之后会判断目的地址是否是自己的IP。DR模式的目的地址没有修改,还是VIP,所以需要在realserver上绑定VIP;IP TUN模式值是对包重新包装了一层,realserver解析后的包的IP仍然是VIP,所以也需要在realserver上绑定VIP
  • 四种模式的性能比较:DR模式、IP TUN模式都是在包进入的时候经过LVS,在包返回的时候直接返回给client;所以二者的性能比NAT高,但TUN模式更加复杂,所以性能不如DR,性能比较:DR>TUN>NAT

LVS负载均衡十种算法

  1. 轮叫调度 rr
    均等地对待每一台服务器,不管服务器上的实际连接数和系统负载
  2. 加权轮叫 wrr
    调度器可以自动问询真实服务器的负载情况,并动态调整权值
  3. 最少链接 lc
    动态地将网络请求调度到已建立的连接数最少的服务器上
    如果集群真实的服务器具有相近的系统性能,采用该算法可以较好的实现负载均衡
  4. 加权最少链接 wlc
    调度器可以自动问询真实服务器的负载情况,并动态调整权值
    带权重的谁不干活就给谁分配,机器配置好的权重高
  5. 基于局部性的最少连接调度算法 lblc
    这个算法是请求数据包的目标 IP 地址的一种调度算法,该算法先根据请求的目标 IP 地址寻找最近的该目标 IP 地址所有使用的服务器,如果这台服务器依然可用,并且有能力处理该请求,调度器会尽量选择相同的服务器,否则会继续选择其它可行的服务器
  6. 复杂的基于局部性最少的连接算法 lblcr
    记录的不是要给目标 IP 与一台服务器之间的连接记录,它会维护一个目标 IP 到一组服务器之间的映射关系,防止单点服务器负载过高。
  7. 目标地址散列调度算法 dh
    该算法是根据目标 IP 地址通过散列函数将目标 IP 与服务器建立映射关系,出现服务器不可用或负载过高的情况下,发往该目标 IP 的请求会固定发给该服务器。
  8. 源地址散列调度算法 sh
    与目标地址散列调度算法类似,但它是根据源地址散列算法进行静态分配固定的服务器资源。
  9. 最少期望延迟 sed
    不考虑非活动链接,谁的权重大,优先选择权重大的服务器来接收请求,但权重大的机器会比较忙
  10. 永不排队 nq
    无需队列,如果有realserver的连接数为0就直接分配过去

实战篇

ipvsadm命令

ipvsadm的选项中,大写选项管理虚拟服务virtual service,小写选项管理关联了虚拟服务的真实服务器RealServer,”-L”和”-l”除外,它们同义。

  • 管理virtual services

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    添加:-A  -t|u|f service-address [-s scheduler]
    -t:tcp协议的集群
    -u:udp协议的集群
    service-address格式为IP:PORT
    -f:firewall-mark防火墙标记
    service-address:a num for mark
    -s:调度算法
    修改:-E -t|u|f service-address [-s scheduler] 和-A使用方法一样
    删除:-D -t|u|f service-address
    示例:
    # ipvsadm -A -t 172.16.10.20:80 -s rr (对外的地址,也就是VIP)
  • 管理virtual service中的RealServer,主要是 -g/-i/-m是指定lvs的类型

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    添加:-a  -t|u|f service-address -r server-address [-g|i|m] [-w weight]
    -t|u|f service-address:指定Real server所绑定的virtual service
    -r server-address:某RS地址,在NAT模型中,可IP:PORT实现端口映射,即端口无需等于VIP对应的port
    -g|i|m:指定lvs的类型,有三种:
    -g:gataway即DR类型(默认的模型)
    -i:--ipip,即TUN类型
    -m:masquerade地址伪装即NAT
    -w:指定权重(需要调度算法支持权重)
    修改:-e和-a用法一样
    删除:-d -t|u|f service-address -r server-address表示从哪个virtual service中删除哪个realserver
    示例:
    # ipvsadm -a -t 172.16.10.20:80 -r 192.168.100.99 -m
    # ipvsadm -a -t 172.16.10.20:80 -r 192.168.100.10 -m
  • 其他项

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    -L或者-l:列出状态信息,配合以下选项用于显示更精确数据
    -n:只显示数字格式,不反解IP地址和端口
    --stats:显示统计信息
    --rate:显示速率信息(每秒的值)
    --timeout:显示tcp/tcpfin/udp的会话超时时间长度
    --daemon:显示进程状态和多播端口(不太用)
    --sort:对-n列出来的进行排序(按协议、IP、端口号升序排序)
    -c:显示当前ipvs的连接状况(不能和stats选项同用)

    -Z:清空统计数据
    -C:删除一个或所有virtual service,连同与之绑定的real server也删除
    -S:保存规则 ipvsadm -S > /path/to/somefile 或者使用ipvsadm-save > /path/to/somefile
    -R:载入规则 ipvsadm -R < /path/to/somefile 或者使用ipvsadm-restore < /path/to/somefile
    service ipvsadm save
    service ipvsadm restore

nat模式

环境准备:

            graph LR
            A[client 192.168.1.111]-->|vip 192.168.1.77|B{Diretor}
B-->|DIP 172.16.1.77|C[rip 172.16.1.55]
B-->|DIP 172.16.1.77|D[rip 172.16.1.66]
          

Diretor上要准备2张网卡,一个是做vip使用,另一个是跟后端通信的DIP。realserver准备2台即可。

realserver配置

安装apache为http服务器

1
2
3
4
yum -y install httpd
echo "from RS1:172.16.1.55" >/var/www/html/index.html # 在RS1上操作
systemctl start httpd
ip route add default via 172.16.2.55 #默认网关必须的lvs-server上面的DIP

lvs-server配置

先安装ipvsadm以及开启IP转发

1
2
3
4
5
6
7
8
[root@localhost ~]# yum install ipvsadm -y
...
[root@localhost ~]# ip -4 -o addr
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
2: eth0 inet 192.168.1.77/24 brd 192.168.1.255 scope global eth0\ valid_lft forever preferred_lft forever
3: eth1 inet 172.16.2.77/24 brd 172.16.2.255 scope global eth1\ valid_lft forever preferred_lft forever
[root@localhost ~]# sysctl -w 'net.ipv4.ip_forward=1'
net.ipv4.ip_forward = 1

然后运行脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost ~]# cat lvs_nat.sh
#!/bin/bash

vip="192.168.1.77:80"
rip=("172.16.2.66:80" "172.16.2.55:80")
ipvsadm -C
ipvsadm -At $vip -s rr
for i in ${rip[@]};do ipvsadm -at $vip -r $i -m;done
ipvsadm -L -n

[root@localhost ~]# sh lvs_nat.sh
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.1.77:80 rr
-> 172.16.2.55:80 Masq 1 0 0
-> 172.16.2.66:80 Masq 1 0 0

测试如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# curl http://192.168.1.77/
from 172.16.2.55
[root@localhost ~]# curl http://192.168.1.77/
from 172.16.2.66
[root@localhost ~]# curl http://192.168.1.77/
from 172.16.2.55
[root@localhost ~]# 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.1.77:80 3 18 12 1188 1422
-> 172.16.2.55:80 2 12 8 792 948
-> 172.16.2.66:80 1 6 4 396 474

注意:lvs-server不能安装docker,可能会有影响。

tun模式

关键点是虚拟IP 192.168.10.10,lvs-server配置如下:

1
2
3
4
5
6
7
ifconfig tunl0 192.168.10.10 netmask 255.255.255.255 up
route add -host 192.168.10.10 dev tunl0
ipvsadm -C
ipvsadm -At 192.168.10.10:80 -s rr
ipvsadm -at 192.168.10.10:80 -r 192.168.10.12:80 -i
ipvsadm -at 192.168.10.10:80 -r 192.168.10.13:80 -i
ipvsadm -L -n

realserver如下:

1
2
3
4
5
6
ifconfig tunl0 192.168.10.10 netmask 255.255.255.255 up
route add -host 192.168.10.10 dev tunl0
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

DR直接路由模式

环境准备:

            graph LR
            A[client 192.168.1.111]-->B{Diretor vip 192.168.1.88}
B-->C[rip 192.168.1.55]
B-->D[rip 192.168.1.66]
          

这时vip也做为dip来使用的,此时也需要在RS上面配置这个vip,但是是配置在lo上面的,realserver配置如下:

1
2
3
4
5
6
7
8
ip addr add 192.168.1.88/32 dev lo
route add -host 192.168.1.88/32 dev lo
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce

yum -y install httpd
echo "from RS1:192.168.1.55" >/var/www/html/index.html # 在RS1上操作
systemctl start httpd

在lvs-server上需要配置2个IP,一个是管理IP,一个是vip:

1
2
3
4
[root@localhost ~]# ip addr add 192.168.1.88/32 dev eth0 label eth0:0
[root@localhost ~]# ip -4 -o addr show eth0
2: eth0 inet 192.168.1.77/24 brd 192.168.1.255 scope global eth0\ valid_lft forever preferred_lft forever
2: eth0 inet 192.168.1.88/32 scope global eth0:0\ valid_lft forever preferred_lft forever

再配置ipvs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost ~]# cat lvs_dr.sh
#!/bin/bash

vip="192.168.1.88:80"
rip=("192.168.1.66:80" "192.168.1.55:80")
ipvsadm -C
ipvsadm -At $vip -s rr
for i in ${rip[@]};do ipvsadm -at $vip -r $i -g;done
ipvsadm -L -n

[root@localhost ~]# sh lvs_dr.sh
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 192.168.1.88:80 rr
-> 192.168.1.55:80 Route 1 0 0
-> 192.168.1.66:80 Route 1 0 0

在另外一台进行测试:

1
2
3
4
5
6
[root@localhost ~]# curl 192.168.1.88
from RS1:192.168.1.55
[root@localhost ~]#
[root@localhost ~]# curl 192.168.1.88
from RS2:192.168.1.66
[root@localhost ~]#

我们从抓包上面来看:


首先发了一个arp包,回复192.168.1.88的mac为00:15:5d:af:b3:0a,然后192.168.1.5就发起SYN请求,目的IP为192.168.1.88,目的mac为00:15:5d:af:b3:0a,然后192.168.1.88就回复了SYN+ACK包,这个看到源mac变成了00:15:5d:af:b3:03,说明不是vip这台机器回复的,是RS回复的包。由此可见,DR的最核心的工作原理就是替换MAC。

keepalived+lvs

一般keepalived是跟lvs结合使用的,keepalived实现故障转移的功能是通过VRRP(virtual router redundancy protocol虚拟路由器冗余协议)协议来实现的。 在keepalived正常工作的时候,主节点(master)会不断的发送心跳信息给备节点(backup),当备节点不能在一定时间内收到主节点的心跳信息时,备节点会认为主节点宕了,然后会接管主节点上的资源,并继续向外提供服务保证其可用性。当主节点恢复的时候,备节点会自动让出资源并再次自动成为备节点。

安装keepalived很简单,直接使用yum安装即可。直接复用上例的LVS的DR模式配置。realserver不需要修改。只需要在lvs-server上面安装keepalived(这里要新增一台服务器做Diretor,配置省略),且写入以下配置。相关的配置解释可以参考:https://www.cnblogs.com/f-ck-need-u/p/8483807.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
57
58
59
60
61
[root@localhost ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived

global_defs {
notification_email {
acassen@firewall.loc
failover@firewall.loc
sysadmin@firewall.loc
}
#notification_email_from Alexandre.Cassen@firewall.loc
#smtp_server 192.168.200.1
#smtp_connect_timeout 30
router_id LVS_web_2 # 路由ID,不能相同
vrrp_skip_check_adv_addr
vrrp_strict
vrrp_garp_interval 0
vrrp_gna_interval 0
}

vrrp_instance VI_1 {
state MASTER # 备用节点配置为:BACKUP
interface eth0
virtual_router_id 51
priority 100 # 优先级,主备配置必须不一样,数字越小优先级越低
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.88 dev eth0 label eth0:0
}
}

virtual_server 192.168.1.88 80 {
delay_loop 6
lb_algo rr
lb_kind DR
persistence_timeout 50
protocol TCP

real_server 192.168.1.55 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 1
nb_get_retry 2
delay_before_retry 1
}
}

real_server 192.168.1.66 80 {
weight 1
TCP_CHECK {
connect_port 80
connect_timeout 1
nb_get_retry 2
delay_before_retry 1
}
}
}

启动keepalived之后,先查看IP是否存在,再使用ipvsadm查看lvs配置:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# ip -4 -o addr
1: lo inet 127.0.0.1/8 scope host lo\ valid_lft forever preferred_lft forever
2: eth0 inet 192.168.1.77/24 brd 192.168.1.255 scope global eth0\ valid_lft forever preferred_lft forever
2: eth0 inet 192.168.1.88/32 scope global eth0:0\ valid_lft forever preferred_lft forever
[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.1.88:80 rr persistent 50
-> 192.168.1.55:80 Route 1 0 0
-> 192.168.1.66:80 Route 1 0 0

keepalived+httpd

keepalived是可以单独使用的,如跟apache结合使用,可以实现主备的高可用,如下配置:

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
[root@localhost keepalived]# cat keepalived.conf
! Configuration File for keepalived

global_defs {
router_id LVS_web_2
}

vrrp_script chk_httpd {
script "/root/httpd.sh"
interval 2
weight 2
}

vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
192.168.1.88 dev eth0 label eth0:0
}
track_script {
chk_httpd
}
}
[root@localhost keepalived]# cat /root/httpd.sh
#!/bin/bash
status=$(ps -C httpd --no-heading |wc -l)
if [ "${status}"x = "0"x ]; then
systemctl start http
sleep 1
status2=$(ps -C httpd --no-heading |wc -l)
if [ "${status2}"x = "0"x ]; then
systemctl stop keepalived
fi
fi

参考资料

  • 本文作者: wumingx
  • 本文链接: https://www.wumingx.com/linux/lvs-keepalived.html
  • 本文主题: 实战LVS三种负载均衡模式
  • 版权声明: 本博客所有文章除特别声明外,转载请注明出处!如有侵权,请联系我删除。
0%