Linux Virtual Server

本文详细解析Linux Virtual Server (LVS) 负载均衡技术,包括其工作原理、配置方法、调度算法以及如何应对高并发场景。通过具体实例,展示了如何在不同环境下部署LVS,实现高效稳定的服务分发。
摘要由CSDN通过智能技术生成

Linux Cluster

Cluster:计算机集合,为解决某个特定问题组合起来形成的单个系统;

Linux Cluster类型:

  • LB:Load Balancing,负载均衡;
  • HA:High Availability,高可用;
    • A=MTBF/(MTBF+MTTR)
      • (0,1):90%,95%,99%,99.5%,99.9%,99.99%,99.999%,99.9999%
  • HP:High Performance,高性能;
  • 分布式系统:
    • 分布式存储
    • 分布式计算
  • 系统扩展方式:
    • Scale UP:向上扩展
    • Scale OUT:向外扩展;Cluster

LB Cluster

  • LB Cluster的实现:

    • 硬件:

      • F5 Big-IP

      • Citrix Netscaler

      • A10 A10

    • 软件:

      • lvs:Linux Virtual Server
        • 四层负载均衡,调度能力强
      • nginx #伪四层
      • haproxy #伪四层:可以模拟四层负载均衡但是实际工作在应用层
      • ats:apache traffic server
      • perlbal
      • pound
    • 基于工作的协议层次划分:

      • 传输层(通用):(DPORT)
        • lvs:
        • nginx:(stream)
        • haproxy:(mode tcp)
      • 应用层(专用):(自定义的请求模型分类)
        • proxy server:
          • http:nginx,httpd,haproxy(mode http),…
          • fastcgi:nginx,httpd,…
          • mysql:mysql-proxy,proxySQL…
      • 站点指标:
        • PV:Page View
        • UV:Unique Vistor
        • IP:
    • 会话保持:

      • 1.session sticky:用户绑定,一个用户的请求绑定在一台主机上;称为会话粘性
        • Source IP,根据ip来识别
        • Cookie,根据cookie来识别
      • 2.session replication;复制session会话集群,session在集群中同步
        • session cluster
      • 3.session server;共享存储,内存存储服务器,基于内存向外提供存储功能;session server,专用于存放session
    • Iptables/netfilter:

      • iptables:用户空间的管理工具
      • netfilter:内核空间上的框架
        • 流入:prerouting–>input
        • 流出:output–>postrouting
        • 转发:prerouting–>forward–>postrouting
      • DNAT:目标地址转换;prerouting;
      • SNAT:源地址转换;postrouting;
    • lvs : ipvsadm/ipvs

      • ipvsadm:用户空间的命令行工具,规则管理器,用于管理集群服务及相关的RealServer;
      • ipvs:工作于内核空间的netfilter的INPUT钩子之上的框架;
    • lvs集群类型中的术语:

      • VS: Virtual Server,Director, Dispatcher,Balancer
        • VS根据请求报文的目标ip和目标协议及端口将其调度转发至某RealServer,根据调度算法来挑选RS;
      • RS: Real Server,upstream server , backend server
      • lvs:四层路由器,四层交换机;
      • CIP: Client ip
      • VIP: Virtual server ip
      • RIP: Real server ip
      • DIP: Director ip
lvs-nat:
  • 多目标的DNAT,通过将请求报文的目标地址和目标端口修改为某挑选出的RS的ip、port实现转发。

    • RIP和DIP必须在同一个ip网络,且应该使用私网地址;RS的网关要指向DIP
    • 请求报文和响应报文都必须经由Director转发;Director易于称为系统瓶颈;
    • 支持端口映射,可以修改请求报文的目标PORT;
    • VS必须是Linux系统,RS可以是任意系统;
      使用场景:小并发的实验性应用、mysql集群
  • 客户端通过Internet访问本地的服务,发送请求报文(源地址CIP:目标地址VIP:端口号)通过路由和Director的公网ip地址(VIP)到达Director,Director收到请求报文后,通过INPUT链上的规则发现是访问RealServer的服务,就把请求报文的目标地址和端口改为通过算法挑选出RS的ip地址和端口(源地址CIP:目标地址RIP:端口),并通过DIP网卡发送给RS;此处要求Director开启核心转发功能;

  • RS收到请求报文,解封装后发送响应报文(源端口RIP:目标端口:CIP)给Director(此处RS的网关必须指向Director的DIP才行),Director收到报文后看到目标地址是CIP,因此就通过本地VIP网卡发送给Client;

  • RIP和DIP在同一IP网络。RIP的网关要指向DIP;

  • 支持端口映射,需要在创建集群的时候加上端口用作映射;

  • Directot要开启核心转发功能;
    在这里插入图片描述
    实验机器ip配置:

  • Client:172.16.0.57/16 CIP

  • Director:172.16.0.7/16 VIP

    •           192.168.79.7/24     DIP
      
  • RS1:192.168.79.27/24 gateway:192.168.79.7

  • RS2:192.168.79.37/24 gateway:192.168.79.7

[root@director ~]# grep -i "ipvs" -C 10 /boot/config-3.10.0-693.el7.x86_64                                          #查看当前系统内核是否支持lvs
[root@director ~]# echo 1 > /proc/sys/net/ipv4/ip_forward                                                               #开启本机核心路由转发功能

[root@rs1 ~]# cat /var/www/html/index.html                                                                                  #配置RS测试页面
<h1>RS1
192.168.79.27</h1>
[root@rs2 ~]# cat /var/www/html/index.html                                                                                  #配置RS测试页面
<h1>RS2</h1>
[root@director ~]# yum -y install ipvsadm                                                                                      #安装ipvsadm软件包
[root@director ipv4]# ipvsadm -A -t 172.16.0.7:80 -s rr                                                                      #在Director上定义集群,设定将目标地址为172.16.0.7:80的请求以轮询的方式转发至后端RS
[root@director ipv4]# ipvsadm -ln                                                                                                 #查看集群
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.7:80 rr
[root@director ipv4]# ipvsadm -a -t 172.16.0.7:80 -r 192.168.79.27 -m                                                  #添加集群后端转发规则
[root@director ipv4]# ipvsadm -a -t 172.16.0.7:80 -r 192.168.79.37 -m                                                  #添加集群后端转发规则
[root@director ipv4]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.7:80 rr
  -> 192.168.79.27:80             Masq    1      0          0         
  -> 192.168.79.37:80             Masq    1      0          0         
  
[root@client network-scripts]# for i in {1..10};do curl http://172.16.0.7;done                                           #测试访问情况
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>

[root@director ipv4]# ipvsadm -E -t 172.16.0.7:80 -s wrr                                                                #将集群调度方式更改为加权轮询
[root@director ipv4]# ipvsadm -e -t 172.16.0.7:80 -r 192.168.79.27 -w 1 -m                                       #设置RS1的权重为1
[root@director ipv4]# ipvsadm -e -t 172.16.0.7:80 -r 192.168.79.37 -w 2 -m                                       #设置RS2的权重为2
[root@director ipv4]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.7:80 wrr
  -> 192.168.79.27:80             Masq    1      0          0         
  -> 192.168.79.37:80             Masq    2      0          0         
[root@director ipv4]# ipvsadm -e -t 172.16.0.7:80 -r 192.168.79.27 -w 0 -m                                      #模拟RS1宕机,此时若不对集群转发规则进行调整的话,会出现访问异常的情况。为避免这种情况的发生,需要手动从集群中删除对应的已宕机的转发规则或将此规则权重设置为0.
[root@client network-scripts]# for i in {1..20};do curl http://172.16.0.7;done
<h1>RS2</h1>
<h1>RS2</h1>
curl: (7) Failed connect to 172.16.0.7:80; Connection refused
<h1>RS2</h1>
<h1>RS2</h1>
curl: (7) Failed connect to 172.16.0.7:80; Connection refused
<h1>RS2</h1>
<h1>RS2</h1>
curl: (7) Failed connect to 172.16.0.7:80; Connection refused
<h1>RS2</h1>
<h1>RS2</h1>
curl: (7) Failed connect to 172.16.0.7:80; Connection refused
<h1>RS2</h1>
<h1>RS2</h1>
curl: (7) Failed connect to 172.16.0.7:80; Connection refused
<h1>RS2</h1>
<h1>RS2</h1>
curl: (7) Failed connect to 172.16.0.7:80; Connection refused
<h1>RS2</h1>
<h1>RS2</h1>
[root@director ipv4]# ipvsadm -e -t 172.16.0.7:80 -r 192.168.79.37 -w 0 -m                                   #模拟RS2宕机,此时后端所有RS全部宕机,服务完全无法正常访问
[root@director ipv4]# ipvsadm -a -t 172.16.0.7:80 -r 127.0.0.1 -w 1 -g                                          #服务无法正常访问时可在Rirector调度器上设置一个本地页面暂时响应请求,将原来所有的访问请求全都转发至固定的页面
[root@director ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  172.16.0.7:80 wrr
  -> 127.0.0.1:80                 Route   1      0          0         
[root@director ipv4]# ipvsadm -ln --stats                                                                               #查看集群负载情况
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port               Conns   InPkts  OutPkts  InBytes OutBytes
  -> RemoteAddress:Port
TCP  172.16.0.7:80                     177      928      510    69241    59548
  -> 127.0.0.1:80                       22      134        0     8720        0
  -> 192.168.79.37:80                  118      641      417    50781    49348
[root@director ipv4]# ipvsadm -ln --rate                                                                                #查看集群负载速率
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port                 CPS    InPPS   OutPPS    InBPS   OutBPS
  -> RemoteAddress:Port
TCP  172.16.0.7:80                       0        0        0       13        0
  -> 127.0.0.1:80                        0        0        0       13        0
  -> 192.168.79.37:80                    0        0        0        0        0
lvs-dr:
  • 工作原理:
    • Client发送请求报文(源地址CIP:目标的地址VIP),经过层层路由到达离我们最近的末梢路由后,末梢路由通过ARP广播,得到Director的MAC地址,然后在请求报文外封装一层MAC首部(源MAC地址末梢路由网卡的MAC:目标MAC为Director网卡MAC),发送给Director
    • Director收到请求报文后,发现目标MAC地址是自己,拆除最外层MAC首部封装,给请求报文重新封装一个MAC首部(源MAC为DIP:目标MAC为RIP)发送给挑选出的RS
    • 返回时经由所挑选的RS上存在vip的网卡通过交换进行返回,返回报文不经过Director,最终源地址为VIP,目标地址为CIP
      • 注意:此处RS与Director在同一个物理网络(处于同一个交换下联,可通过MAC进行物理寻址通信),都有VIP。因此要确保RS不响应末梢路由的ARP广播才行;有以下三种方法
        • 在前端网关做静态绑定
        • 在RS上使用arptables
        • 修改内核参数以限制ARP通告及应答级别(arp_announce和arp_ignore)
          • 限制响应级别:arp_ignore
            • 0:默认值:表示可使用本地任意接口上配置的任意地址进行响应
            • 1:仅在请求的目标IP配置在本地主机的接收请求保温接口上时,才给予响应
          • 限制通告级别:arp_announce
            • 0:默认值:把本机上的所有接口的所有信息向每个接口上的网络进行通告;
            • 1:尽量避免向非直接连接网络进行通告;
            • 2:必须避免向非本网络通告;

在这里插入图片描述
实验:

按上图设置实验环境,为了简化实验过程,将客户端client与vip置于同一网段,中间省略交换和路由。

[root@rs1 ~]# vim setparam.sh                   #修改内核参数来限制ARP通告和应答级别,使得多个VIP在同一网络中不会产生冲突,而且在前端client请求访问VIP时不会直接访问至后端RS上
#!/bin/bash
#
case $1 in
start)
echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
;;
stop)
echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce
;;
*)
echo "Usage $(basename $0) start|stop"
exit 1
;;
esac

[root@rs1 ~]# bash setparam.sh start
[root@rs2 ~]# bash setparam.sh start

[root@rs1 ~]# ifconfig lo:0 192.168.79.99 netmask 255.255.255.255 broadcast 192.168.79.99 up                                            #在RS的lo别名网卡上配置vip,指定其广播范围为自己
[root@rs2 ~]# ifconfig lo:0 192.168.79.99 netmask 255.255.255.255 broadcast 192.168.79.99 up                                            #在RS的lo别名网卡上配置vip,指定其广播范围为自己

[root@client ~]# ifconfig ens33:0 192.168.79.99 netmask 255.255.255.255 broadcast 192.168.79.99 up                          

[root@director ~]# ipvsadm -A -t 192.168.79.99:80 -s rr             #定义192.168.79.99:80集群,调度方式为轮询 
[root@director ~]# ipvsadm -a -t 192.168.79.99:80 -r 192.168.79.27 -g       #添加集群调度规则,设定后端RS,设定为DR类型
[root@director ~]# ipvsadm -a -t 192.168.79.99:80 -r 192.168.79.37 -g
[root@director ~]# ipvsadm -ln
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.79.99:80 rr
 -> 192.168.79.27:80             Route   1      0          0         
 -> 192.168.79.37:80             Route   1      0          0    

之后还需准备测试页面等内容,其操作与nat类型一致,省略之~~~~




DH:Destination Hashing类型,目标地址哈希,

在实际使用中,用户可能会遇到这样一种情况,就是比如说client使用80端口去访问某个网站,这个时候director将请求调度至RS1,在网站上选择了商品并添加至购物车中,选择支付时登录,这个时候会跳转至https重新发起请求,而这个新的请求极有可能被调度至其他RS,导致之前未登录时添加的缓存丢失,因为缓存在RS1上。
针对这种情况,可以将网站做成全https的,然后使用sh算法进行调度,将同一个源地址的相同访问请求在一定周期内转发至同一个RS。
此外还可以使用FWM(firewall mark)的方式借助防火墙标记来分类报文,而后基于标记定义集群服务,将多个不同端口的应用使用同一个集群服务进行调度;

#在各RS节点配置https服务
[root@rs1 certs]# umask 077; openssl genrsa -out /etc/pki/CA/private/cakey.pem 2048 				#搭建CA
[root@rs1 certs]# openssl req -new -x509 -key /etc/pki/CA/private/cakey.pem -days 3650 -out cacert.pem
[root@rs1 certs]# umask 066; openssl genrsa -out /data/test.key 2048
[root@rs1 certs]# openssl req -new -key /data/test.key -out /data/test.csr

[root@rs1 certs]# touch /etc/pki/CA/index.txt
[root@rs1 certs]# echo 01 > /etc/pki/CA/serial
[root@rs1 certs]# openssl ca -in /data/test.csr -out /etc/pki/CA/certs/test.crt -days 365
[root@rs1 certs]# curl --cacert /etc/pki/CA/cacert.pem https://192.168.79.27
[root@rs1 certs]# vim /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.79.99 www.ilinux.io
192.168.79.27 www.ilinux.io
[root@rs1 certs]# curl --cacert /etc/pki/CA/cacert.pem https://www.ilinux.io 						#指定CA证书测试https访问结果
[root@rs1 certs]# scp /etc/pki/CA/cacert.pem 192.168.79.37:/etc/pki/CA/cacert.pem		#在后端RS上同步http,https配置
[root@rs1 certs]# scp /etc/pki/CA/certs/test.crt 192.168.79.37:/etc/pki/CA/certs/test.crt
[root@rs1 ~]# vim /etc/httpd/conf.d/ssl.conf 
SSLCertificateFile /etc/pki/CA/certs/test.crt
SSLCertificateKeyFile /data/test.key
[root@rs1 certs]# scp /etc/httpd/conf.d/ssl.conf 192.168.79.37:/etc/httpd/conf.d/ssl.conf

#在Director节点配置集群服务,并在防火墙上做标记
[root@director ~]# iptables -t mangle -A PREROUTING -d 192.168.79.99 -p tcp -m multiport --dports 80,443 -j MARK --set-mark 3         
[root@director ~]# ipvsadm -A -f 3 -s sh		#基于防火墙标记建立集群
[root@director ~]# ipvsadm -a -f 3 -r 192.168.79.27 -g
[root@director ~]# ipvsadm -a -f 3 -r 192.168.79.37 -g 
[root@director ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
FWM  3 sh
  -> 192.168.79.27:0              Route   1      0          0         
  -> 192.168.79.37:0              Route   1      0          0         
[root@client ~]# for i in {1..5};do curl http://www.ilinux.io;curl --cacert /etc/pki/CA/cacert.pem https://www.ilinux.io;done
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
[root@director ~]# ipvsadm -E -f 3 -s rr
[root@client ~]# for i in {1..5};do curl http://www.ilinux.io;curl --cacert /etc/pki/CA/cacert.pem https://www.ilinux.io;done
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>
<h1>RS1
192.168.79.27</h1>
<h1>RS2</h1>


  • ipvs的持久连接:lvs persistence
    • 持久连接模板:无论使用任何调度算法,在一段时间内,能够实现将来自同一个地址的请求始终发往同一个RS;
    • 将本地所有端口的服务都绑定在一起,使用轮询方式进行调度,简单粗暴,但是加了持久连接,会使一段时间内的负载都调度到同一台RS上。
[root@director ~]# ipvsadm -A -t 192.168.79.99:0 -s rr -p
[root@director ~]# 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.79.99:0 rr persistent 360
  -> 192.168.79.27:0              Route   1      0          0         
  -> 192.168.79.37:0              Route   1      0          0  
[root@client ~]# for i in {1..10};do curl http://www.ilinux.io;curl --cacert /etc/pki/CA/cacert.pem https://www.ilinux.io;done
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
<h1>RS2</h1>
[root@client ~]# ssh 192.168.79.99        
The authenticity of host '192.168.79.99 (192.168.79.99)' can't be established.
ECDSA key fingerprint is SHA256:UXcDHVz7rqAG+9gC6wdEofZXYhmVkjCsBffMo01t+t0.
ECDSA key fingerprint is MD5:02:03:46:24:46:24:fd:48:b2:08:d6:24:28:f4:93:13.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.79.99' (ECDSA) to the list of known hosts.
root@192.168.79.99's password: 
Last login: Wed Jun  5 10:01:20 2019 from 192.168.79.1
[root@rs2 ~]#                                                       #可以看到使用ssh协议远程连接vip时连到了RS2上

  • port affinity:

    • 每端口持久:每个端口定义为一个集群服务,每集群服务单独调度
    • 每防火墙标记持久:基于防火墙标记定义集群服务;可实现将多个端口上的应用统一调度,即所谓的port affinity
    • 每客户端持久:基于0端口定义集群服务,即将客户端对所有应用的请求统统调度至后端主机,必须定义为持久模式
  • ipvs保存和重载规则:

    • 保存:建议保存至/etc/sysconfig/ivpsadm
      • ipvsadm-save > /PATH/TO/IPVSADM_FILE
      • ipvsadm -S > /PATH/TO/IPVSADM_FILE
    • 重载:
      • ipvsadm-restore < /PATH/TO/IPVSADM_FILE
      • ipvsadm -R < /PATH/TO/IPVSADM_FILE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值