LVS负载均衡
Linux cluster
Linux集群简单来说就是部署许多计算机(服务器)来共同协作完成一个任务。一个计算机称作集群的一个节点。
集群的优势:
- 易于扩展,管理可以方便的对服务器进行增、删
- 高可用性,当集群中的某一个节点失效,会有其它节点的机器自动顶上去。不会影响业务的进行
- 高性能,负载均衡的机器可以将请求均衡的分发至各个服务器,大大减轻服务器承载的压力
常见的集群方式:
- LB集群(Load Balancing):负载均衡集群,就是将用户的请求合理的分发至各个服务器上
- HA集群(High Availiablity):高可用集群,当某台服务器出现单点故障时,服务不会中断,而是交由其它运行正常的服务器接管。
- HP集群(High Performance):高性能的集群是当某一项任务计算量非常大的时候,由一个计算机集群共同来完成这项任务,这种 处理方式我们称为并行处理机制。一般高性能集群用于科研工作方面
LVS
LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统。本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一。从linux内核的2.4版本之后内置了LVS的各个模块。可以直接使用。
LVS工作在网络模型的第四层,直接在内核中实现各种功能,也就无需监听套接字,所以摆脱了套接字数量的限制。
lvs的优缺点(转载):
1、抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生,保证了均衡器IO的性能不会受到大流量的影响;
2、配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率;
3、工作稳定,自身有完整的双机热备方案,如LVS+Keepalived和LVS+Heartbeat,不过我们在项目实施中用得最多的还是LVS/DR+Keepalived;
4、应用范围比较广,可以对所有应用做负载均衡,不管是http还是ssh协议都可以使用lvs;
5、软件本身不支持正则处理,不能做动静分离,这个就比较遗憾了;其实现在许多网站在这方面都有较强的需求,这个是Nginx/HAProxy+Keepalived的优势所在。
6、如果是网站应用比较庞大的话,实施LVS/DR+Keepalived起来就比较复杂了,特别后面有Windows Server应用的机器的话,如果实施及配置还有维护过程就比较复杂了,相对而言,Nginx/HAProxy+Keepalived就简单多了。
7、性能非常卓越,已经在多个公司使用可靠性也非常不错,并且是开源项目,可以修改源代码定制自己的需求
LVS体系结构
结合上图来解释LVS的构建结构
- Director Server:最前端的服务器,用来接收用户的请求报文,然后根据调度算法将用户的请求分发至后面的Real Server上。此处非常重要,因为它的健康与否直接影响了用户的访问结果,所以它一般都为两台,一台用来为用户提供服务,一台用来监听服务的那台机器。一旦服务的那台机器挂掉,就需要另一台立马顶上,并拥有它所有的资源。
- Real Server:提供服务的真正主机。它可以是web服务,ftp服务等。如何来监控它们的健康状态。可以在Director Server上安装Ldirectord来监听Real Server的健康状况。
- 数据:共享存储,假如用户在Real Server1上访问时,往购物车里加物品。第二次再访问时却分发到了Real Server2上。如果没有共享存储,用户会发现购物车里之前添加的东西都没有了。所以共享存储主要是为了各个服务器之间的资源统一性。
Director Server必须是linux或者freeBSD。而Real Server可以是大部分操作系统。
LVS集群类型以及调度算法
由于LVS是直接工作在内核中,跟iptables类似,需要用一个应用程序专门向内核中传递参数以达到添加规则的方法。lvs在内核中是由ipvs模块来实现的。利用ipvsadm程序来向ipvs模块中定义规则。为了后面便于书写,将如下名称简化:
术语 | 解释 |
---|---|
VS | Virtual Server 调度器,也叫Director |
RS | Real Server |
CIP | 客户端IP |
VIP | Virtual IP , 虚拟IP |
RIP | 后端主机IP |
DIP | Director IP,与RS通信的IP |
当用户请求资源时,调度器(VS)是怎么将资源发送给后方的RS节点的以及RS在响应时怎么响应?LVS集群类型主要以下几种类型:
LVS-NAT
- 客户端CIP通过网络中的路由到达处在公网的VIP
- VIP接收到用户请求,进入自己的防火墙规则,发现访问的是本机进程。直接在INPUT链上进行lvs策略转换
- lvs将客户端CIP访问的目标地址VIP,转变为后端真正实现服务的RIP地址上。所以变成了
src:CIP,dest:RIP
。经过POSTROUTING到达后端的real server - real server响应的时候,仍然原路返回,此时的
src:RIP,dest:CIP
。等到从VIP网卡出去的时候,会将RIP该为VIP进行响应。这是因为客户端就访问的VIP,我们仍然用VIP来响应。RIP虽然也可以进行响应,但是客户端只是想访问VIP,我们如果用RIP的话,客户端不会接受响应。
根据上述有以下几点: - VIP必须是公网,可以接受用户的访问
- RIP和DIP必须在一个本地网络,且应该使用私网地址,RS的网关需要指向DIP,如果都指向了公网,就没有意义了,用户可以直接访问到RS。 这是不被允许的。
这就有一个问题,不管响应还是请求,都要经过调度器,这样调度承载的压力就大大增加。压力越大,越容易崩溃。
LVS-DR
用户向VIP发起请求,调度器在源目标CIP和目标VIP之外在封装一个源DIPMAC地址和目标RIPMAC地址(为挑选出来的RSMAC地址)。然后在将这四个地址一起发送给挑选出来的RS。响应时,RS先拆除两个MAC地址,发现请求的目标VIP是本机地址,然后直接将结果返回给CIP。而不再经过调度器。
dr类型有以下几个要点:
- vs和各RS上都要有VIP
- 确保用户的请求目标为VIP的报文发送给调度器,因为RS上也有VIP,所以要对RS上VIP进行限制,以防用户发送的请求直接发到了RS上。后面示例会写到。直接调整内核参数即可。
- RS的RIP可以是私网地址,也可以是公网地址,但是RIP和VIP要在同一个物理网段上,RIP的网关不能指向DIP,以确保RS可以直接响应用户,而不是由Director响应。
- RS上的VIP要设置回环接口lo上,使用ARP限制VIP。稍后配置会说到。
LVS-tun
tun模型也称为隧道模型,由调度器把请求报文发送至某一个Real Server上。然后由Real Server直接响应给客户。有以下几个要点:
- DIP在向RS发送请求报文时,对最原始的源CIP/目标VIP不进行修改,而是在外面在添加一层IP,即源DIP和目标RIP。
- DIP,RIP,VIP应该都是公网地址,并且RS可以处在不同的地方。
- RS的网关不会指向DIP
- 请求可以经过VS,但是响应不能经由VS。
LVS-fullnat
简单来说就是将请求报文和响应报文全部进行修改。根据上图进行解释:
- 用户发起请求,源目标CIP/目标VIP
- 调度发现用户请求需要发送给RS,然后修改源CIP/目标VIP成源DIP/目标RIP(RS1)
- RS1收到请求后,将响应报文原路返回,这时源RIP/目标DIP
- 调度器将响应报文再次修改,最后变成源VIP/目标CIP响应给客户
fullnat由几个要点: - VIP是公网地址,DIP和RIP都是私网地址,且不再同一段网络,RIP的网关不要指向DIP
- RS收到的源地址IP是DIP,响应也一定要给DIP,最后由DIP转发给VIP响应给客户。
- 请求和响应报文都要流经VS
LVS调度算法
根据其调度时是否考虑各RS当前的负载状态,分为静态方法和动态方法:
静态方法:根据算法本身进行调度
- RR:轮询(roundrobin),即1:1进行分配,不考虑负载均衡。比如三台服务器,每一台都有10个请求,即使后两台都已经处理完,第一台仍在处理请求。进来最新的请求也会发送给第一台
- WRR:加权轮询(weight RR)。比如两台服务器,两台的权重比2:1,那么发送的请求就是212。
- SH:源地址哈希(Source Hashing) 。将来自于同一个IP的请求始终发往第一次挑中的RS,实现会话绑定。
- DH:目标地址哈希(Destination Hashing)。将发往同一个目标地址的请求始终转发至第一次挑中的RS。
动态方法:根据每RS当前的负载状态以及调度算法进行调度 - LC:最少连接数(least connections ),简单来说就是将新的请求发送给目前连接组少的服务器
- WLC:加权最少连接数(Weighted LC),是LC的升级版,将新请求平均分配到服务器上,以符合服务器之间的权重比。
- SED:最短期望延时(Shortest Expection Delay),基于WLC算法
- NQ:从不排队(Never Queue),直接将新请求发送给空闲的RS
- LBLC:基于局部性的最少连接数(Locality-Based LC),相当于DH和LC算法的集合,用来将目标地址IP调度到同一个服务端,如果该服务端负载正常,则继续发往该服务器端。如果该服务端负载已经超过一半以上,就按照LC规则发送到最少连接数上的一个服务器上。
- LBLCR:带复制功能的LBLC(LBLC with Replication)
ipvsadm
用来向集群服务定义规则。常用选项如下:
常用选项 | 解释 |
---|---|
-A | 添加一条新的虚拟服务 |
-E | 编辑虚拟服务 |
-D | 删除虚拟服务 |
-C | 清楚虚拟服务的规则 |
-R | 恢复虚拟服务的规则 |
-a | 在一个新的虚拟服务上面添加一条新的服务器 |
-e | 编辑某个真实的服务器 |
-d | 删除某个真实的服务器 |
-L|l | 显示内核中的虚拟服务器的规则 |
-n | 以数字形式显示ip端口 |
-c | 显示ipvs目前以存在的连接 |
-Z | 将转发的消息计数清零 |
-p | 配置持久化时间 |
-A | 添加一条新的虚拟服务 |
-t|-u | tcp或udp的虚拟服务协议 |
-g|-m|-i | lvs模型:DR,NAT,TUN |
-w | 配置真实服务器的权重 |
-s | 配合均衡负载算法 |
- -timeout | 显示配置的tcp/udp超时时间 |
- -stats | 显示历史消息转发统计 |
- -rate | 显示转发速率信息 |
管理集群服务:增、删、改
- 增/改:
ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]]
- 删:
ipvsadm -D -t|u|f service-address
示例:
[root@directory ~]# ipvsadm -A -t 192.168.199.146:80 -s rr
[root@directory ~]# 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.199.146:80 rr
添加一条新的虚拟服务,算法是轮询
[root@directory ~]# ipvsadm -D -t 192.168.199.146:80
[root@directory ~]# ipvsadm
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
删除虚拟服务
管理集群上的RS服务:增,改,删
- 增,改:
ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight]
- 删:
ipvsadm -d -t|u|f service-address -r server-address
示例:
[root@directory ~]# ipvsadm -a -t 192.168.199.146:80 -r 192.168.199.230:80 -g
[root@directory ~]# 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.199.146:80 rr
-> 192.168.199.230:80 Route 1 0 0
添加集群上的一条RS服务
[root@directory ~]# ipvsadm -d -t 192.168.199.146:80 -r 192.168.199.230:80
删除集群上的某条RS服务
lvs-nat
使用ipvsadm实现lvs-nat
实现NAT模型有以下几点:
- VS机器上有两张网卡,VIP接收用户请求,DIP向RS发送请求
- RIP和DIP应该都在私网上,并且RIP网关指向DIP
模拟环境 | ip地址 |
---|---|
VIP | 192.168.199.157 |
DIP | 192.168.192.129 |
RIP1 | 192.168.192.130 |
RIP2 | 192.168.192.128 |
#准备好后端httpd主机准备好网页,以及主机的网关指向
[root@http1 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.192.129 0.0.0.0 UG 0 0 0 ens33
[root@httpd2 ~]# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 192.168.192.129 0.0.0.0 UG 0 0 0 ens33
[root@http1 ~]# curl http://192.168.192.130
httpd1
[root@httpd2 ~]# curl http://192.168.192.128
httpd2
#添加lvs主机策略。
[root@lvs ~]# ipvsadm -A -t 192.168.199.157:80 -s rr 添加以轮询方式访问
#添加后端真正服务器
[root@lvs ~]# ipvsadm -a -t 192.168.199.157:80 -r 192.168.192.130 -m
[root@lvs ~]# ipvsadm -a -t 192.168.199.157:80 -r 192.168.192.128 -m
[root@lvs ~]# 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.199.157:80 rr
-> 192.168.192.128:80 Masq 1 0 0
-> 192.168.192.130:80 Masq 1 0 0
#测试访问
[root@client ~]# curl http://192.168.199.157
httpd2
[root@client ~]# curl http://192.168.199.157
httpd1
[root@client ~]# curl http://192.168.199.157
httpd2
[root@client ~]# curl http://192.168.199.157
httpd1
NAT类型的端口映射
#首先将128主机上的web端口改为8080
[root@httpd2 ~]# cat /etc/httpd/conf/httpd.conf | grep Listen
Listen 8080
[root@httpd2 ~]# ss -ntl | grep 8080
LISTEN 0 128 :::8080 :::*
#将策略修改成以下
[root@lvs ~]# 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.199.157:80 rr
-> 192.168.192.128:8080 Masq 1 0 0
-> 192.168.192.130:80 Masq 1 0 0
# 测试访问
[root@client ~]# curl http://192.168.199.157
httpd2
[root@client ~]# curl http://192.168.199.157
httpd1
[root@client ~]# curl http://192.168.199.157
httpd2
[root@client ~]# curl http://192.168.199.157
httpd1
实现NAT类型的https访问
这里不构建私有CA,直接创建自签证书,由于更换了IP,重新写一下IP地址
主机 | ip地址(192.168.199.0) |
---|---|
client | 175 |
lvs | 157(VIP)和 192.168.192.129(DIP) |
httpd1 | 192.168.192.131 |
httpd2 | 192.168.192.128 |
1)在httpd主机上创建存放自签证书的目录/etc/httpd/tls
[root@httpd2 httpd]# mkdir tls
2)在/etc/pki/tls/certs直接make生成自签证书。
[root@httpd2 certs]# make ydong.com.crt
umask 77 ; \
/usr/bin/openssl req -utf8 -new -key ydong.com.key -x509 -days 365 -out ydong.com.crt
Enter pass phrase for ydong.com.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:beijing
Locality Name (eg, city) [Default City]:beijing
Organization Name (eg, company) [Default Company Ltd]:ydong.com
Organizational Unit Name (eg, section) []:opt
Common Name (eg, your name or your server's hostname) []:www.ydong.com
Email Address []:
[root@httpd2 certs]# ll
total 20
lrwxrwxrwx. 1 root root 49 Jan 13 23:35 ca-bundle.crt -> /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
lrwxrwxrwx. 1 root root 55 Jan 13 23:35 ca-bundle.trust.crt -> /etc/pki/ca-trust/extracted/openssl/ca-bundle.trust.crt
-rwxr-xr-x. 1 root root 610 Oct 30 2018 make-dummy-cert
-rw-r--r--. 1 root root 2516 Oct 30 2018 Makefile
-rwxr-xr-x. 1 root root 829 Oct 30 2018 renew-dummy-cert
-rw------- 1 root root 1330 Apr 5 05:04 ydong.com.crt
-rw------- 1 root root 1766 Apr 5 05:03 ydong.com.key
3)安装ssl模块
[root@httpd2 certs]# yum install -y mod_ssl
4)将crt文件移动到/etc/httpd/tls目录下。
[root@httpd2 certs]# mv ydong.com.* /etc/httpd/tls/
5)配置ssl.conf文件,修改以下两项
SSLCertificateFile /etc/httpd/tls/ydong.com.crt
SSLCertificateKeyFile /etc/httpd/tls/ydong.com.key
6)重启服务
[root@httpd2 conf.d]# ss -tnl | grep 443
LISTEN 0 128 :::443 :::*
7)在lvs端添加策略
[root@lvs ~]# ipvsadm -A -t 192.168.199.157:443 -s rr
[root@lvs ~]# ipvsadm -a -t 192.168.199.157:443 -r 192.168.192.131 -m
[root@lvs ~]# ipvsadm -a -t 192.168.199.157:443 -r 192.168.192.128 -m
[root@lvs ~]# 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.199.157:443 rr
-> 192.168.192.128:443 Masq 1 0 0
-> 192.168.192.131:443 Masq 1 0 0
8)客户端测试
[root@client ~]# curl -k https://192.168.199.157
httpd2
[root@client ~]# curl -k https://192.168.199.157
httpd1
LVS-DR
VIP和DIP处在同一网段实现
DR模型有以下几个要点:
- VIP仍是公网,接收用户请求,RIP可以是私网,也可以是公网,但是要跟DIP在同一段物理网络
- RS上配置VIP,并且对VIP进行抑制配置。
- RIP网关不能指向DIP
关于抑制vip通告和响应需要设置arp_ignore(响应)和arp_announce(通告)
限制响应级别arp_ignore:
- 0:默认值,表示可使用本地上任意接口上配置的任意地址进行响应。意思是主机在1.1接口上请求2.1的接口时,也会给予响应。
- 1:仅在请求的目标IP配置在本地主机的接收到请求报文接口上时,才给予响应。意思是主机在1.1接口上请求2.1的接口时,不给予响应。只有主机亲自去2.2接口上请求才给予响应
限制通告级别arp_announce:
- 0:默认值,把本机上所有接口的所有信息向每个接口上的网络进行通信,通告所有主机上本机的网络mac。意思是主机即使只在1.1接口上,但是它可以获得本机所有的网络mac地址,1.1的mac,2.1的mac,3.1的mac。它都会收到
- 1:尽量避免向非直接连接网络进行通告;
- 2:必须避免向非本网络通告;意思就是1.1只通告给连接在自己接口上的主机,其它的一律不通告。
在RS上配置VIP时,需要将它的响应设置为1,通告级别设置成2。
1)首先配置路由具有转发功能
[root@route ~]# vim /etc/sysctl.conf
[root@route ~]# sysctl -p
net.ipv4.ip_forward = 1
2)测试客户端是否ping通路由的192网段
[root@localhost ~]# ping 192.168.192.100
PING 192.168.192.100 (192.168.192.100) 56(84) bytes of data.
64 bytes from 192.168.192.100: icmp_seq=1 ttl=64 time=0.274 ms
跨路由访问lvs
[root@localhost ~]# ping 192.168.192.132
PING 192.168.192.132 (192.168.192.132) 56(84) bytes of data.
64 bytes from 192.168.192.132: icmp_seq=1 ttl=63 time=0.423 ms #可以看到ttl是63,证明跨了一个路由。
3)在httpd主机上设置VIP,到时vip会绑在lo回环网卡上
[root@httpd1 ~]# echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
[root@httpd1 ~]# echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@httpd1 ~]# echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@httpd1 ~]# echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
4)将VIP地址绑定在lo上
[root@httpd1 ~]# ip address add 192.168.192.132 dev lo
[root@httpd1 ~]# 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
inet 192.168.192.132/32 scope global lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
5)定制lvs策略
[root@lvs ~]# 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.192.134:80 rr
-> 192.168.192.131:80 Route 1 0 13
-> 192.168.192.133:80 Route 1 0 4
6)client测试
[root@client ~]# curl http://192.168.192.134
httpd1
[root@client ~]# curl http://192.168.192.134
httpd2
[root@client ~]# curl http://192.168.192.134
httpd1
[root@client ~]# curl http://192.168.192.134
httpd2
PS:
同一网段的主机其实没太大作用,因为你可以直接访问后端真正的服务器,没必要在通过lvs多次一举。上边演示有几个小问题。
- LVS上的VIP不是物理网卡上的ip地址,而是在一张物理网卡上新添加的地址,两张物理网卡的话,在real server上添加VIP时,可能会导致lvs上会出现没有到主机路由的情况。从而导致访问失败。
- Real Server的网管应该指向route,而lvs的网关可以随意指向。仅限同一网段。因为返回的报文是不经过lvs的。
VIP和DIP不处在同一网段实现
1)配置各主机的ip地址以及网关指向,测试client端是否能ping通lvs的VIP。
[root@client ~]# ping 192.168.192.132
PING 192.168.192.132 (192.168.192.132) 56(84) bytes of data.
64 bytes from 192.168.192.132: icmp_seq=1 ttl=63 time=0.328 ms
#ttl=63,证明是跨路由了
2)对后端real server进行抑制arp广播
[root@httpd1 ~]# echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
[root@httpd1 ~]# echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
[root@httpd1 ~]# echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
[root@httpd1 ~]# echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
3)在real server上添加vip地址
[root@httpd1 ~]# ip a a 192.168.192.132/32 dev lo
4)配置lvs服务器
[root@lvs ~]# 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.192.132:80 wrr
-> 172.16.0.101:80 Route 2 0 0
-> 172.16.0.102:80 Route 1 0 0
5)测试
[root@client ~]# curl http://192.168.192.132
httpd2
[root@client ~]# curl http://192.168.192.132
httpd1
[root@client ~]# curl http://192.168.192.132
httpd1
[root@client ~]# curl http://192.168.192.132
httpd2
[root@client ~]# curl http://192.168.192.132
httpd1
[root@client ~]# curl http://192.168.192.132
httpd1
[root@client ~]# curl http://192.168.192.132
httpd2
PS
- RIP的网关应该指向route的172地址段。