LVS负载均衡集群架设

why LVS

说到LVS,不得不说起F5。F5的LTM(本地流量管理器)在部署上、负载均衡原理上类似,但是也有十分大的区别,之前暑期实习的时候稍微接触过F5的设备,不得不说其是一款十分优秀的设备,强悍的负载均衡能力,人性化的界面、加上自身携带的Irules也是大大增加了其灵活性(就像是lua给nginx插上了飞翔的翅膀),他的代名词是不仅仅是负载均衡,强大SSL卸载芯片,HTTP优化、连接复用、抗DDoS特性等等,再加上和GTM(广域网流量管理器)的联动,使得在其在同城双活或者两地三中心建设领域大放异彩,你,值得拥有~

然而好货不便宜,它的价格昂贵让许多企业望而却步。单单一台LTM设备加license就是6位数,这也让一些企业开始拥抱开源,寻找免费的负载均衡产品,如今的开源文化已经十分繁荣,如本文介绍的LVS,当然还有Nginx,Haproxy等等,都是很好的开源软件,他们都有各自的应用领域和特点。(有时间会另说)

LVS和其他负载均衡产品相比有它自己的特点,它是一个纯4层设备,仿佛就是一个四层的交换机,由于它不需要对应用层报文进行处理,不涉及代理工作(只考虑原生的lvs),所以它的性能非常好,得以广泛应用,再加上自身就是开源的作品,很方便给有研发能力互联网企业足够的空间来施展拳脚。如阿里他们开源的LVS-FULLNAT,给LVS增添了很多新的特性

LVS简介

LVS(Linux Virtual Server)是一款优秀的负载均衡软件,一般用于具备完善运维能力的互联网企业,为业务主机实现应用负载均衡一种技术,实现后端服务器压力分担、scale out的一种方式。

LVS将多台提供相同服务功能的server组成服务器池,每次请求的时候根据负载均衡算法挑选出相对压力较小或更适合被请求的服务器发送请求。我们一般称这个节点为其为load balancer。其作者就是大明鼎鼎 chinese man 淘宝正明(现应叫DiDi正明~)章文嵩博士,它是一款四层的负载均衡软件,表明其性能强悍,其已经被整合到linux内核内;但是它无法对数据包进行更加详细的分析,从负载均衡上说存在缺陷。

组成

LVS主要分为ipvsadm和IPVS。ipvsadm是管理集群服务的命令行工具,工作在用户空间;而IPVS则是工作在INPUT链上的内核模块。在使用传统的LVS时,只需安装ipvsadm即可,2.6后IPVS的代码在内核中已经被编译好,无需打补丁即可使用。安装前建议查看kernel版本或直接查看内核是否支持:modprobe -l | grep ipvs

结构
  • DS:director server,即负载均衡器,根据一定的负载均衡算法将流量分发到后端的真实服务器上
  • RS:Real server 真实的提供服务的server,可被DR划分到一个或多个负载均衡组。
  • BDS:backup director server,为了保证负载均衡器的高可用衍生出的备份
  • VS:vitual server,负载均衡集群对外提供的IP+Port
  • VIP:VS的IP,client请求服务的DIP(destination IP address),在DR上,client或其网关需要有其路由
原理

ipvs基于netfilter框架,netfilter的架构就是在整个网络流程的若干位置放置了一些检测点(HOOK),而在每个检测点上登记了一些处理函数进行处理(如包过滤,NAT等,甚至可以是用户自定义的功能)。IPVS就是定义了一系列的“钩子函数”,在INPUT链和Forward上放置一些HOOK点,如匹配了ipvs的规则,就会通过函数来对数据包进行操作,比如修改目的IP为realserver的接口IP(NAT),对MAC进行修改(DR)等等。

负载均衡算法
  • RR:轮询
  • WRR:给后台real server根据性能比例设定权重,根据权重进行轮询
  • SH:source hash 根据SIP进行哈希,生成hash表,收到结果根据sip进行哈希并和hash表进行比对。
  • DH:destination hash 对同一个资源的请求发往同一台服务器,常用于缓存服务器的场景
  • LC:最少连接数,计算当前后端server的活动连接数*256+非活动连接数,最小的server被调度接受请求
  • WLC:加权最少连接,(后端server的活动连接数*256+非活动连接数)/weight,最小的server被调度接受请求
  • Sed:最短期望延迟,(active+1)*256/weight
  • NQ:never queue
  • LBLC:基于本地的最少连接,动态的DH
  • LBLCR:基于本地的带复制功能的最少连接

集群部署

NAT(DNAT)

原理:顾名思义,进出的数据报文都需要经过director,client请求报文请求VIP和对应的端口号时director根据负载均衡算法选出接受请求的Real server,并将DIP和Dport更换成real server的ip和监听端口。回包时需保证回复报文经过director,将其SIP和SPort替换为Virtual server的IP和port
(类似于F5 LTM的路由模式)

RS上的配置
在RS1,RS2上安装httpd用于测试,RS1上(RS2上类似RS1):

1
2
3
4
yum install -y httpd
echo 'Real server1' > /var/www/html/index.html
service httpd restart
iptables -F

DR上的配置

1
2
3
4
5
6
7
8
9
echo 1 > /proc/sys/net/ipv4/ip_forward #打开路由转发功能
ipvsadm -C #清空ipvs的配置
ipvsadm -At 172.16.130.1:8080 -s wrr #添加VS,调度算法为wrr
ipvsadm -at 172.16.130.1:8080 -r 192.168.162.101:80 -m -w 3 #给VS指定realserver 权重为3
ipvsadm -at 172.16.130.1:8080 -r 192.168.162.100:80 -m -w 1
ipvsadm -L -n #查看ipvs的配置
ipvsadm -S > ipvs.conf #保存ipvs为一个配置文件ipvs.conf
ipvsadm -R < ipvs.conf #读取配置文件

最后两条在实验的时候可以方便调试,也可以将前面的几条柔和成一个脚本运行

1
2
3
4
5
6
7
zhxfei@zhxfei-HP-ENVY-15-Notebook-PC:~$ sudo ./lvs.sh
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.16.130.1:8080 wrr
-> 192.168.162.100:80 Masq 1 0 0
-> 192.168.162.101:80 Masq 3 0 0

验证

1
2
3
4
[root@localhost ~]# curl 172.16.130.1:8080
realserver1
[root@localhost ~]# curl 172.16.130.1:8080
realserver2

优点:可以做端口映射,如向外提供的端口和real server的服务端口可以不一样;Realserver可使用任意操作系统
缺点:请求分发器存在屏顶;保证回包的流量经过director将SIP和Sport转换(Real server一般将网关指向DIP)

DR(direct routing)

原理:流量三角走向,即client的请求报文路由到director的VIP接口,director根据负载均衡算法选出接受请求的real server后,将目的MAC转换为real server的接口MAC(和VIP所在同一网段)。在realserver收到报文回复请求后,直接回复给客户端,源地址为realserver的VIP接口(一般配置为环回口)。为实现以上,请求报文到达director和realserver所在网关时,网关arp请求时应保证只有director会响应对VIP的ARP请求,real server对arp请求应保持静默。且为了保证real server响应报文的SIP为VIP,realserver需要配置接口地址和VIP相同。且回复时,二层的SMAC应该保证为RIP接口的MAC地址,不能为VIP接口的MAC地址,防止GW缓存VIP的mac在Realserver上,导致发包直接发到realserver。(类似于LTM的n-path组网,由于F5是基于TMOS全代理架构,所以需要保证来回路径一致,现在基本不使用)

arp ignore
为了实现client的请求报文到达server所在的GW(Gateway)上,广播ARP请求时,只有LVS会回复其ARP请求,realserver不会回复,需要修改后台服务器上的arp_ignore内核参数。
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
arp_announce
为了保证server将报文直接回复给client而不经过LVS,我们需要在realserver上配置一个VIP接口来作为回复报文的源地址。但是接受报文的接口是VIP接口,我们回复的时候需要将realserver的VIP接口的MAC地址隐藏起来不作为恢复报文的源MAC地址,防止GW上的MAC地址表动荡。此时需要更改个内核参数,配置echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce,忽略源ip而使用本地路由的最佳出站接口的ip地址

架构如图:

部署见下面的keepalived+LVS

优点:直接路由,性能最好(只处理请求报文(很小),响应报文(很大)无需经过DR直接发往客户端)
缺点:不支持端口映射;大多数的操作系统支持realserver(realserver需要隐藏VIP);集群节点即realserver需要和director在一个网段中

TUN(ip tunnel)

Director收到DIP为VIP的报文,在IP包头外再封装一个IP头部,源为DIP和目的为RIP,协议号为4,表示IPIP封装。Realserver收到报文后拆开外层头后发现是IPIP封装继续拆内部的三层头,源IP为client目的IP为TUNL0即为本地接口地址,继续拆解数据包,回包后即根据内部数据包的yuanIP直接路由回到client
优点无需经过director路由,且realserver没有地理位置的限制,可以在不同的网段
缺点对realserver的系统有要求,linux和BSD系列的支持ipip tunl。
拓扑如下:

MTU问题::在ip_vs模块中,有相关MTU检测的内容,当DF标志位为1,且len超过MTU时,会发送ICMP_FRAG_NEEDED

如果lvs的vs收到的数据以太网帧已经超过1.5K即接口MTU,则LVS会回复一个icmp报文给客户,如果客户端支持路径MTU(PMTU),会把后续的报文调小于MTU。再把后面的交换机的mtu调大。或者在server端设置较小的MSS。如可以使用iptables 来进行调整:iptables -A FORWARD -p tcp -m tcpmss -j TCPMSS --class-mss-to-pmtu。可以关注/proc/sys/net/ipv4/ip_forward_use_pmtu这个kernel参数

由于在LVS收到分片的报文之后网卡会交由协议栈需要将报文重组,这样会带来一定的延时,此时可以在LVS上考虑使用ethtool使用网卡对数据合并,而协议栈不需要对报文进行重组:

DS上的ipvs的配置文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost ~]# cat ipvs.conf
-A -t 192.168.162.80:http -s rr
-a -t 192.168.162.80:http -r 192.168.100.50:http -i -w 1
-a -t 192.168.162.80:http -r 192.168.130.50:http -i -w 1
[root@localhost ~]# ipvsadm -R < ipvs.conf
[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.162.80:80 rr
-> 192.168.100.50:80 Tunnel 1 0 0
-> 192.168.130.50:80 Tunnel 1 0 0
[root@localhost ~]# ip addr add 192.168.162.80/32 dev eth0:1

RS上的配置脚本:

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
# description: RealServer's script # 关于脚本的简短描述
# processname: realserver.sh # 第一个进程名,后边设置自动时会用到
# !/bin/bash
VIP=192.168.162.80
case "$1" in
start)
ifconfig tunl0 $VIP netmask 255.255.255.255 broadcast $VIP up
/sbin/route add -host $VIP dev tunl0
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 "RealServer Start OK"
;;
stop)
ifconfig tunl0 down
route del $VIP >/dev/null 2>&1
echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/tunl0/rp_filter
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
iptables -F
setenforce 0
exit 0

rp_filter
注意:echo "0" > /proc/sys/net/ipv4/conf/tunl0/rp_filter是将RPF反向路径检查关闭,其原本是为了防止DDoS攻击伪造的IP源数据包在公网上穿行,将收到的报文的SIP作为目的IP查找路由表,将结果的出接口和收到报文的接口相比对,将不一致的报文丢弃。如果其从eth0收到了VIP的数据包查找路由表会优先匹配本地接口TUNL0,出接口不一致会导致kernel将数据包丢弃。

抓包
request:

reply:

keepalived+LVS

简介

keepalived被成为LVS的黄金搭档,其原先是负责了为负载均衡组内的realserver的健康检查,将出现故障的realserver从负载均衡组中剔除,而当服务器恢复正常,再加入到负载均衡组。
后来加入了可以防止LVS单点故障的特性,基于VRRP协议为LVS节点保证了HA。

在keepalived启动后会有三个进程
父进程:内存管理,子进程管理等等
子进程:VRRP子进程
子进程:healthchecker子进程,检查各自服务器的健康状态

1
2
3
Aug 5 08:01:49 localhost Keepalived[7233]: Starting Keepalived v1.2.19 (08/03,2016)
Aug 5 08:01:49 localhost Keepalived[7234]: Starting Healthcheck child process, pid=7236
Aug 5 08:01:49 localhost Keepalived[7234]: Starting VRRP child process, pid=7237

使用keepalived来构建高可用LVS的话,可以不用在LVS上使用ipvsadm来配置VIP,LB策略等等,直接使用keepalived配置模板拉取配置相关信息,注意关闭iptables和selinux

安装

keepalived官网上下载之本地,解压并安装:

1
2
3
4
5
6
tar -xvf keepalived-1.2.19.tar.gz
cd keepalived-1.2.19
./configure --sysconf=/etc --with-kernel-dir=/usr/src/kernels/`uname -r` #--with-kernel-dir表明使用内核源码中的头文件,只有使用LVS时才会用到此文件
make && make install
ln -s /usr/local/sbin/keepalived /sbin/
keepalived -v #查看安装版本

DS和BDS配置(基于DR模式)

配置模板(DS MASTER):

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
[root@localhost ~]# cat /etc/keepalived/keepalived.conf
! Configuration File for keepalived
global_defs {
notification_email {
root@localhost
}
notification_email_from admin@localdomain
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id LVS_DEVEL #显示在邮件中
}
vrrp_instance VI_1 {
state MASTER !VRRP启动时候的状态
interface eth0 !指定监视HA的接口
virtual_router_id 51 !虚拟路由器组的id号,在LVS中可以理解为负载均衡组的id号,master和backup需要相同
priority 100 !优先级,越大越优先(0没有选举资格,255为固定MASTER)
advert_int 1 !默认为1,表示1s发一次
authentication {
auth_type PASS !明文验证,还支持MD5
auth_pass 1111
}
virtual_ipaddress {
192.168.162.80 !定义VIP
}
}
virtual_server 192.168.162.80 80 {
delay_loop 6 !运行状况检查时间
lb_algo rr !调度算法
lb_kind DR !负载均衡机制
persistence_timeout 1 !会话保持时间1s,在1s内,统一用户的会话会调度到一台机器上
protocol TCP
real_server 192.168.162.100 80 {
weight 1
HTTP_GET { !基于http get的健康检查
url {
path /
status_code 200 !状态码200即正常
}
connect_timeout 3 !超时时间3S
nb_get_retry 3 !尝试3次
delay_before_retry 3 !retry间隔3s
}
}
real_server 192.168.162.101 80 {
weight 1
HTTP_GET {
url {
path /
status_code 200
}
connect_timeout 3
nb_get_retry 3
delay_before_retry 3
}
}
}

BDS BACKUP:
直接scp root@192.168.162.102:/etc/keepalived/keepalived.conf /etc/keepalived/keepalived.conf 之后
修改state和priority即可
开启keepalived: service keepalived start

当开启后,client去访问VIP的80端口,LVS DS会选出一台realserver,当client在回话保持设置的超时时间内都会被调度到一台realserver上。
(PS:实验一直以为自己失败了,明明设置了RR,但是却访问的是一台服务器~_~!)

RS配置

提供配置脚本:

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
[root@localhost ~]# cat realserver.sh
#/bin/bash
#
# description: RealServer's script # 关于脚本的简短描述
# processname: realserver.sh # 第一个进程名,后边设置自动时会用到
# !/bin/bash
VIP=192.168.162.80
case "$1" in
start)
ifconfig lo:0 $VIP netmask 255.255.255.255 broadcast $VIP
/sbin/route add -host $VIP dev lo:0
echo "1" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "RealServer Start OK"
;;
stop)
ifconfig lo:0 down
route del $VIP >/dev/null 2>&1
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/lo/arp_announce
echo "0" >/proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" >/proc/sys/net/ipv4/conf/all/arp_announce
echo "RealServer Stoped"
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
esac
iptables -F
setenforce 0
exit 0

VRRP

选举
通过优先级选举,越大越优先,相同即比较IP地址,priority为0没有选举资格,255为MASTER VIP的拥有者
优先级相同比较IP地址越大越优先成为MASTER

抢占和非抢占
BACKUP收到MASTER发来的通告报文中携带的优先级比自己低就会抢占MASTER并向外发送VRRP通告报文(相同不会抢占),如果原MASTER比原BACKUP的优先级低收到通告报文则会变为BACKUP
如果原BACKUP工作在非抢占模式下,只要MASTER出现故障,BACKUP即使优先级更低也不会成为MASTER路由器
默认是抢占模式(抢占只比较优先级不比较IP地址,即优先级相同就不会抢占)

healthcheck

重启后台realserver httpd服务

1
2
3
4
5
6
7
8
9
Aug 5 08:43:23 localhost Keepalived_healthcheckers[7689]: Error connecting server [192.168.162.101]:80.
Aug 5 08:43:23 localhost Keepalived_healthcheckers[7689]: Removing service [192.168.162.101]:80 from VS [192.168.162.80]:80
Aug 5 08:43:23 localhost Keepalived_healthcheckers[7689]: Remote SMTP server [127.0.0.1]:25 connected.
Aug 5 08:43:23 localhost Keepalived_healthcheckers[7689]: SMTP alert successfully sent.
Aug 5 08:43:50 localhost Keepalived_healthcheckers[7689]: HTTP status code success to [192.168.162.101]:80 url(1).
Aug 5 08:43:56 localhost Keepalived_healthcheckers[7689]: Remote Web server [192.168.162.101]:80 succeed on service.
Aug 5 08:43:56 localhost Keepalived_healthcheckers[7689]: Adding service [192.168.162.101]:80 to VS [192.168.162.80]:80
Aug 5 08:43:56 localhost Keepalived_healthcheckers[7689]: Remote SMTP server [127.0.0.1]:25 connected.
Aug 5 08:43:56 localhost Keepalived_healthcheckers[7689]: SMTP alert successfully sent.
failover测试

在client使用webbench进行故障倒换压测,期间,在DS上使用iptable将VRRP通告DROP:iptables -A OUTPUT -d 224.0.0.18 -j DROP
可以看到BDS上的VIP迅速浮上来:

1
2
3
4
5
6
7
8
9
[root@localhost webbench-1.5]# ./webbench -c 10000 -t 20 http://192.168.162.80:/index.html
Webbench - Simple Web Benchmark 1.5
Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.
Benchmarking: GET http://192.168.162.80:/index.html
10000 clients, running 20 sec.
Speed=3060 pages/min, 14122 bytes/sec.
Requests: 1016 susceed, 4 failed.

看到BDS上的日志

1
2
3
4
5
6
Aug 5 07:35:50 localhost Keepalived_vrrp[6905]: VRRP_Instance(VI_1) Transition to MASTER STATE
Aug 5 07:35:51 localhost Keepalived_vrrp[6905]: VRRP_Instance(VI_1) Entering MASTER STATE
Aug 5 07:35:51 localhost Keepalived_vrrp[6905]: VRRP_Instance(VI_1) setting protocol VIPs.
Aug 5 07:35:51 localhost Keepalived_healthcheckers[6904]: Netlink reflector reports IP 192.168.162.80 added
Aug 5 07:35:51 localhost Keepalived_vrrp[6905]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth4 for 192.168.162.80
Aug 5 07:35:56 localhost Keepalived_vrrp[6905]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth4 for 192.168.162.80

我们可以看到,当BACKUP成为MASTER的时候,发送了gratuitous ARPs(免费ARP)用于刷新GW的MAC地址表项,表示BACKUP接手VIP的arp响应
此时原本的MASTER收到原BACKUP的通告消息(只有MASTER才会发送VRRP通告报文),也会重复发送通告报文和免费ARP信息告诉BACKUP“我才是MASTER!”并刷新GW的MAC地址表:

1
2
Aug 5 07:59:00 localhost Keepalived_vrrp[7060]: VRRP_Instance(VI_1) Received lower prio advert, forcing new election
Aug 5 07:59:00 localhost Keepalived_vrrp[7060]: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.162.80

若心跳报文(Master发送的通告报文)被阻止或者丢弃没有被Slave上的VRRP程序接受,则LVS会产生脑裂,GW上的MAC地址表可能会产生动荡,即MAC地址漂移,所以一般专业的设备都会有专门的心跳电缆互联

坚持原创技术分享,您的支持将鼓励我继续创作!