Linux Nginx LVS HAproxy 负载均衡功能对比

Nginx:

  1. 工作在网络7层,可以针对http应用做一些分流的策略,比如针对域名,目录结构
  2. Nginx对网络的依赖较小,理论上能ping通就能进行敷在功能
  3. Nginx安装配置比较简单,测试起来很方便
  4. 也可以承担较高的负载压力且稳定,Nginx是为了解决c10k问题而诞生的
  5. 对后端服务器的健康检查,只支持通过端口来检测,不支持通过url来检测
  6. Nginx对请求的异步处理可以帮助节点服务器减轻负载压力
  7. Nginx仅能支持http、https和Email协议,这样就在适用范围较小
  8. 不支持Session的直接保持,但能通过ip_hash来解决,对Bigrequestheader的支持不是很好
  9. Nginx还能做Web服务器即Cache功能。

LVS:

  1. 抗负载能力强,性能高,能达到F5的60%,对内存和cpu资源消耗比较低
  2. 工作在网络4层,通过VRRP协议(仅做代理使用),具体的流量是由liunx内核来处理,因此没有流量的产生。
  3. 稳定,可靠性强,自身有完美的热备方案(Keepalived+LVS)
  4. 不支持正则处理,不能做动静分离
  5. 支持多种负载均衡算法:rr(轮询),wrr(带权轮询)、lc(最小连接)、wlc(带权最小连接)
  6. 配置相对复杂,对网络依赖比较大,稳定性很高。

LVS工作模式有4种:

  • nat地址转换
  • dr直接路由
  • tun隧道
  • full-nat

HAproxy:

  1. 支持两种代理模式:TCP(四层)和HTTP(七层),支持虚拟主机
  2. 能够补充Nginx的一些缺点比如Session的保持,Cookie引导等工作
  3. 支持url检测后端的服务器出问题的检测会有很好的帮助。
  4. 更多负载均衡策略比如:动态加权轮循,加权源地址哈希,加权URL哈希加权等参数哈希已经实现。
  5. 单纯从效率上来讲HAproxy更会比Nginx有更出色的负载均衡
  6. HAproxy可以对MYsql进行负载均衡,对后端的DB节点进行检测和负载均衡
  7. 支持负载均衡算法:轮循、带权轮循、源地址保持、请求URL、根据Cookie
  8. 不能做Web服务器即Cache。

三大主流软件负载均衡器适用的生产场景:

  1. 网站建设初期,可以选用Nginx、HAproxy作为反向代理负载均衡(流量不大时可以选择不用负载均衡)因为其配置简单,性能也能满足一般业务场景。如果考虑到负载均衡器是有单点失败问题,可以采用Nginx+Keepalived避免负载均衡器自身单点问题。
  2. 网站并发达到一定程度后,为了提高稳定性和转发效率,可以使用LVS,毕竟LVS比Nginx/HAproxy要更稳定,转发效率也高。

lvs工作模式和工作原理

一、lVS基本介绍

LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器。也是国人章文嵩博士发起的一个开源项目,现在LVS已经是Linux内核标准的一部分。利用LVS技术可以实现高性能,高可压缩的网络服务,例如www服务,FTP服务,MAIL服务等。

二、LVS的体系架构

使用LVS架设的服务器集群系统有三个部分组成:最前端的负载均衡层(Loader Balancer),中间的服务器群组层,用Server Array 表示,最底层的数据共享存储层,用Shared Storage表示。在用户看来所有的应用都是透明的,用户只是在使用一个虚拟服务器提供的高性能服务。

1、LVS的体系架构如图

未分类

2、LVS的各个层次的详细介绍

Load Balancer层:位于整个集群系统的最前端,有一台或者多台负载调度器(Director Server)组成,LVS模块就安装在Director Server 上,而Director 的主要作用类似于一个路由器,它含有完成LVS功能所设定的路由表,通过这些路由表把用户的请求分发给Server Array层的应用服务器上。同时,在Director Server上还要安装对Real Server服务的监控模块Ldirectord,此模块用于监测各个Real Server服务的健康状况。在Real Server不可用时把它从LVS路由表中剔除,恢复时加入。

Server Array层:由一组实际运行应用服务的机器组成,Real Server可以是WEB服务器、MAIL服务器、FTP服务器、DNS服务器、时评服务器中的一个或多个,每个Real Server之间通过高速的LAN或分布在各地的wan相连接。在实际的应用中,Director Server也可以同时兼任Real Server的角色。

Shared Storage层:是为所有Real Server提供共享存储空间和内容一致性的存储区域,在物理上,一般有磁盘阵列设备组成,为了提供内容的一致性,一般可以通过NFS网络文件系统共享数据,但是NFS在繁忙的业务系统中,性能并不是很好,此时可以采用集群文件系统。

从整个LVS结构可以看出,Director Server是整个LVS的核心,对于Real Server,可以是所有的系统平台,Linux、windows、Solaris、AIX、BSD系列都能很好的支持。

三、LVS集群

1、十种调度算法

(1)静态

  • rr 轮循调度 (Round-Robin Scheduling)

  • wrr 加权轮循调度 (Weighted Round-Robin Scheduling)

  • sh 源地址散列调度 (Source Hashing Scheduling)

  • dh 目的地址散列调度 (Destination Hashing Scheduling)

(2)动态

  • lc 最小连接调度 (Least-Connection Scheduling)

  • wlc 加权最小连接调度 (Weighted Least-Connection Scheduling)

  • sed 最短预期延时调度 (Shortest Expected Delay Scheduling)

  • nq 不排队调度 (Never Queue Scheduling)

  • lblc 基于局部性的最少连接调度 (Locality-Based Least Connections Scheduling)

  • lblcr 带复制的基于局部性的最少连接调度 (Locality-Based Least Connections with Replication Scheduling)

2、三种IP负载均衡技术

(1)IPVS/NAT

网络结构图:

未分类

负载均衡内核空间原理图

未分类

IPVS/NAT模式的基本原理

首先CIP发送请求package给VIP,VIP收到package后,会根据LVS设置的LB算法选择一个合适的RS?然后把package的目标IP修改为RIP,RIP收到这个package后判断目标ip为自己,就处理这个package,处理完后把这个包发送给LVS VIP,LVS 收到这个package 后把sorce ip改成VIP的IP,dst ip改成 CIP,然后发给CIP。其中的转换我们可以这样理解:所有发送到VIP的数据包全部转换为RIP的地址以及对应端口。IPVS/NAT模式优缺点

优点:

  • 容易配置,容易理解,容易管理的工作模式
  • 节省外网IP资源,LVS-NAT工作方式将系统架构封装在局域网中,只需要LVS有一个外网地址或外网地址映射就可实现访问
  • 系统架构相对封闭,内网环境下防火墙的设置要求不会太高,容易进行物理服务器的运维
  • LVS/NAT工作模式下的RS服务器可以是任何操作系统,只要支持TCP/IP协议即可

缺点:

  • LVS-NAT中,负载均衡调度器作为转发点,当RS服务器数量变多时,调度器将会负载,转发点也是瓶颈点

(2)IPVS/DR

网络结构图

未分类

IPVS/DR模式的基本原理

LVS节点接收到请求报文后,会改写报文的数据链路层格式。将VIP MAC写成RIP的Mac,但是网络层和传输层报文不会改写,然后重新回发给交换机。这里就涉及一个问题,现在RIP和 IP的对应关系的错误的,这个数据报文到了交换机后,由于这种错位的关系,是不能进行三层交换的,只能进行二层交换(一旦进行IP交换,数据报文的验证就会出错,被丢弃)。所以LVS-DR方式要求Real Server和LVS节点必须在同一个局域网内,或者这样说更确切:LVS节点需要找到一个二层链路,将改写了Mac地址的报文发送给Real Server,而不能进行三层交换的校验。

简单来说就是CIP发送一个PV请求给VIP,VIP收到这个请求后会跟LVS设置的LB算法选择一个LB比较合理的realserver,然后将此请求的package的MAC地址修改为realserver的MAC地址;VIP会把这个包广播到当前这个LAN里面,所以,要提前保证VIP和所有的realserver在同一个网段

IPVS/DR 模式的优缺点

优点

  • 解决了LVS-NAT工作模式中的转发瓶颈问题,能够支撑规模更大的负载均衡场
  • 比较耗费网外IP资源,机房的外网IP资源都是有限的,如果在正式生产环境中确实存在这个问题,可以采用LVS-NAT和LVS-DR混合使用的方式来缓解

缺点

  • 配置工作较LVS-NAT方式稍微麻烦一点,您至少需要了解LVS-DR模式的基本工作方式才能更好的指导自己进行LVS-DR模式的配置和运行过程中问题的解决
  • 由于LVS-DR模式的报文改写规则,导致LVS节点和Real Server节点必须在一个网段,因为二层交换是没法跨子网的。但是这个问题针对大多数系统架构方案来说,实际上并没有本质限制

(3)IPVS/TUN

首先这里需要理解以下关于IP隧道的概念

将一个完整的IP报文封装成另一个新的IP报文的数据部分,并通过路由器传送到指定的地点。在这个过程中路由器并不在意被封装的原始协议的内容。到达目的地点后,由目的地方依靠自己的计算能力和对IP隧道协议的支持,打开封装协议,取得原始协议。如图:

未分类

其实数据转发原理和DR是一样的,不过这个我个人认为主要是位于不同位置(不同机房);LB是通过隧道进行了信息传输,虽然增加了负载,可是因为地理位置不同的优势,还是可以参考的一种方案;

优点

  • 负载均衡器只负责将请求包分发给物理服务器,而物理服务器将应答包直接发给用户。所以,负载均衡器能处理很巨大的请求量,这种方式,一台负载均衡能为超过100台的物理服务器服务,负载均衡器不再是系统的瓶颈。使用VS-TUN方式,如果你的负载均衡器拥有100M的全双工网卡的话,就能使得整个Virtual Server能达到1G的吞吐量。

缺点

  • 这种方式需要所有的服务器支持”IP Tunneling”(IP Encapsulation)协议;

lvs,nginx,haproxy的优缺点,适合场景

Nginx/LVS/HAProxy的基于Linux的开源免费的负载均衡软件。

LVS:使用集群技术和Linux操作系统实现一个高性能、高可用的服务器,它具有很好的可伸缩性、可靠性和可管理性,是一款强大实用的开源软件。

LVS的优点:

1:抗负载能力强、是工作在网络4层之上仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的,也保证了均衡器I/O的性能不会受到大流量的影响。;
2:lvs是专门的负载均衡软件,对任何应用都可以做负载均衡;
3:工作稳定,因为其本身抗负载能力很强,自身有完整的双机热备方案,目前用的比较多的是lvs+keepalived,比较大型的用的多的是lvs+heartbeat。

nginx的优点:

1:Nginx的高并发,同时能承载上万个并发连接;
2:nginx有充足的第三方功能模块的支持,主要通过upstream模块进行负载均衡;
3:nginx对网络的依赖较小,理论上只要Ping得通,网页访问正常,nginx就能连得通;
4:工作在网络的7层之上,可以针对http应用做一些分流的策略,它的正则规则比haproxy更为强大和灵活,这也是它目前广泛流行的主要原因之一,nginx单凭这点可利用的场合就远多于lvs了。

nginx的缺点:

1:将Nginx当做反向代理时,负载均衡功能不是很好,对后端服务器的健康检查功能较弱;
2:nginx仅能支持http、https和email协议,这样就在适用范围上面小些,这个是它的缺点;
3:nginx只支持通过端口来检测,不支持通过url来检测。

haproxy的优点:

1:HAProxy的优点能够补充Nginx的一些缺点,比如支持Session的保持,Cookie的引导;同时支持通过获取指定的url来检测后端服务器的状态;
2:haproxy也是专门的负载均衡软件,Haproxy可以负载http,还可以负载均衡mysql;
3:HAProxy是支持虚拟主机的。

总结这么多,我觉得根据不同的需求,不同的功能,可以选择不同的软件类的负载均衡软件,当然也是可以选择硬件类的负载均衡器。
像对于大型的,需要进行高并发的网站或者对网络不太严格的时候,可以使用nginx;
对于大型的Web服务器的时候可以使用haproxy;
对性能有严格要求的时候可以使用lvs,就单纯从负载均衡的角度来说,lvs也许会成为主流,更适合现在大型的互联网公司。

RHEL6 搭建LVS/NAT 负载均衡集群 案例

实验拓扑图:

未分类

操作流程:

Director Server : 192.168.4.50 pc50
安装并启用ipvsadm
创建虚拟服务器
向虚拟服务器上加入节点

Real Server : 192.168.4.51 pc51 192.168.4.52 pc52
配置WEB 服务器

Clinet : 192.168.2.253 pc253
连接虚拟服务器测试

具体步骤:

环境准备:

配置yum源

# service iptables stop            //关闭防火墙
# chkconfig iptables off            //关闭开机自启
# setenforce 0                            //设置SELinux 为宽松模式

网站服务器 pc51 / pc52 :

# yum -y install httpd
[root@pc51 ~]# echo '192.168.4.51' > /var/www/html/test.html
[root@pc52 ~]# echo "192.168.4.52" > /var/www/html/test.html
# service httpd start
# chkconfig httpd on
# yum -y install elinks
[root@pc51 ~]# elinks --dump http://localhost/test.html
  192.168.4.51
[root@pc52 ~]# elinks --dump http://localhost/test.html
  192.168.4.52

配置分发器 pc50:

# mount /dev/cdrom /mnt/
//安装 ipvsadm   rpm 包在光盘挂载文件下的LoadBalancer目录下
#cd /mnt/LoadBalancer/
#yum -y install ipvsadm-1.26-4.el6.x86_64.rpm 
//开启内核的路由转发功能
# sed -i '7s/0/1/' /etc/sysctl.conf
# sed -n '7p' /etc/sysctl.conf 
net.ipv4.ip_forward = 1

网站服务器 pc51 / pc52 :

指定网关地址 192.168.4.50

# route -n//查看路由
# route add default gw 192.168.4.50//临时配置网关 网卡重启后生效
//永久配置网关
# vim /etc/sysconfig/network-scripts/ifcfg-eth0
# sed -n '7p' /etc/sysconfig/network-scripts/ifcfg-eth0
GATEWAY=192.168.4.50
# ifdown eth0 ; ifup eth0      //重新加载网卡

客户端 192.168.2.253 配置

指定网关地址 192.168.2.50 :

# vim /etc/sysconfig/network-scripts/ifcfg-eth1
# sed -n '7p' /etc/sysconfig/network-scripts/ifcfg-eth1
GATEWAY=192.168.2.50
# ifdown eth1 ; ifup eth1
# ping -c 2 192.168.4.51
PING 192.168.4.51 (192.168.4.51) 56(84) bytes of data.
64 bytes from 192.168.4.51: icmp_seq=1 ttl=63 time=0.322 ms
64 bytes from 192.168.4.51: icmp_seq=2 ttl=63 time=0.503 ms

--- 192.168.4.51 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.322/0.412/0.503/0.092 ms
# yum -y install elinks

配置分发器 pc50 :

# yum -y install ipvsadm-1.26-4.el6.x86_64.rpm
# rpm -q ipvsadm
ipvsadm-1.26-4.el6.x86_64

添加虚拟服务

        # ipvsadm -L  //查看 IPVS
        IP Virtual Server version 1.2.1 (size=4096)
        Prot LocalAddress:Port Scheduler Flags
          -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
        # ipvsadm -A -t 192.168.2.50:80 -s rr//添加虚拟服务 调度算法为Round Robin
        # ipvsadm -L
        IP Virtual Server version 1.2.1 (size=4096)
        Prot LocalAddress:Port Scheduler Flags
          -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
        TCP  192.168.2.50:http rr
        # ipvsadm -Ln   //- n  数字显示
        IP Virtual Server version 1.2.1 (size=4096)
        Prot LocalAddress:Port Scheduler Flags
          -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
        TCP  192.168.2.50:80 rr
                //向虚拟服务器中加入节点
        # ipvsadm -a -t 192.168.2.50:80 -r 192.168.4.51:80 -m
        # ipvsadm -a -t 192.168.2.50:80 -r 192.168.4.52:80 -m
        # 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.2.50:80 rr
          -> 192.168.4.51:80              Masq    1      0          0         
          -> 192.168.4.52:80              Masq    1      0          0   
        # /etc/init.d/ipvsadm save//使配置永久生效
        ipvsadm: Saving IPVS table to /etc/sysconfig/ipvsadm:      [确定]
        # cat /etc/sysconfig/ipvsadm
        -A -t 192.168.2.50:80 -s rr
        -a -t 192.168.2.50:80 -r 192.168.4.51:80 -m -w 1
        -a -t 192.168.2.50:80 -r 192.168.4.52:80 -m -w 1

客户端测试

        # elinks --dump http://192.168.2.50/test.html
           192.168.4.51
        # elinks --dump http://192.168.2.50/test.html
           192.168.4.52
        //客户端 轮询到不同的后端真实服务器        

        [root@pc50 ~]# 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.2.50:80                 2       10       10      846     1098
          -> 192.168.4.51:80                     1        5        5        423      549
          -> 192.168.4.52:80                     1        5        5        423      549

        模拟pc51 web服务故障:
        [root@pc51 ~]# service httpd stop
        [root@pc50 ~]# ipvsadm -Z

         //客户端测试
        # elinks --dump http://192.168.2.50/test.html
           192.168.4.52
        # elinks --dump http://192.168.2.50/test.html
           192.168.4.52

        [root@pc50 ~]# 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.2.50:80                 3       11       11      906     1138
          -> 192.168.4.51:80                     1        1        1         60       40
          -> 192.168.4.52:80                     2       10       10      846     1098

会发现 LVS/NAT 单点故障时 并不能健康性检查

可以 编写一个脚本 监测两台Real Server 的服务 是否正常 如果监测到故障 将对应的服务在调度服务器 停掉

使用周期性计划任务 定时运行监测脚本 到达 健康检查的目的

RHEL6 搭建 keepalived + lvs/DR 集群

使用Keepalived为LVS调度器提供高可用功能,防止调度器单点故障,为用户提供Web服务:

  • LVS1调度器真实IP地址为192.168.4.50
  • LVS2调度器真实IP地址为192.168.4.55
  • 服务器VIP地址设置为192.168.4.252
  • 真实Web服务器地址分别为192.168.4.51、192.168.4.52

实验拓扑图:

未分类

实验步骤:

实验准备:

配置yum源

# service iptables stop            //关闭防火墙
# chkconfig iptables off            //关闭开机自启
# setenforce 0                            //设置SELinux 为宽松模式 

配置WEB服务器 pc51 / pc52

#yum -y install httpd  
#service httpd start 
#chkconfig httpd on
[root@pc51 ~] #echo " 192.168.4.51  " > /var/www/html/test.html
[root@pc52 ~] #echo " 192.168.4.52 " > /var/www/html/test.html

本次实验有些步骤就不详细介绍了,具体有关 keepalived 和 ipvsadm 的相关配置 可以参考

keepalived 配置高可用集群 : http://blog.51cto.com/13558754/2060950

ipvsadm 配置LVS/DR 负载均衡集群:http://blog.51cto.com/13558754/2060405

1、在web服务上 配置 VIP地址 pc51 / pc52

# ifconfig lo:1 192.168.4.252/32    //只拥有ip 就可以
# ifconfig lo:1
lo:1      Link encap:Local Loopback  
         inet addr:192.168.4.252  Mask:0.0.0.0
         UP LOOPBACK RUNNING  MTU:65536  Metric:1
# cd /proc/sys/net/ipv4/conf/
# echo 1 > lo/arp_ignore
# echo 2 > lo/arp_announce 
# echo 1 > all/arp_ignore 
# echo 2 > all/arp_announce 

2、配置分发器 50(主) 55(备) 分别安装keepalived软件 装包 ipvsadm

# rpm -q ipvsadm keepalived
ipvsadm-1.26-4.el6.x86_64
keepalived-1.2.13-5.el6_6.x86_64

3、修改配置文件

[root@pc50 ~]# vim /etc/keepalived/keepalived.conf 
 vrrp_instance VI_1 {
      state MASTER                 // 描述信息  MASTER为主服务器
      interface eth0                 // 定义网络接口
      virtual_router_id 51           //主 备VRID号必须一致 
      priority 150                   //服务器优先级
      advert_int 1
      authentication {
          auth_type PASS           //验证方式
          auth_pass 1111           //验证密码     主  备服务器密码必须一致 
      }
      virtual_ipaddress {
          192.168.4.252            //VIP地址
      }   
  }

  virtual_server 192.168.4.252 80 {        //配置 VIP为192.168.0.252  80 端口
      delay_loop 6
      lb_algo rr                            //设置LVS调度算法为RR
      lb_kind DR                            //设置LVS的模式为DR
      nat_mask 255.255.255.0
      persistence_timeout 50
      protocol TCP
      connect_timeout 3
      nb_get_retry 3
      delay_before_retry 3

     real_server 192.168.4.51 80 {
          weight 1                        //设置权重为1
     }   
     real_server 192.168.4.52 80 {
          weight 1                        //设置权重为1
      }   

  }

使用第一个虚拟服务的模版

其余的都删除

主机55

[root@pc55 ~]# vim /etc/keepalived/keepalived.conf 
  vrrp_instance VI_1 {
      state BACKUP                // 描述信息 BACKUP为备用服务器
      interface eth0
      virtual_router_id 51
      priority 100
      advert_int 1
      authentication {
          auth_type PASS
          auth_pass 1111
      }
      virtual_ipaddress {
          192.168.4.252
      }
  }

  virtual_server 192.168.4.252 80 {
      delay_loop 6
      lb_algo rr
      lb_kind DR
      nat_mask 255.255.255.0
      persistence_timeout 50
      protocol TCP
      connect_timeout 3
      nb_get_retry 3
      delay_before_retry 3

      real_server 192.168.4.51 80 {
          weight 1
      }
      real_server 192.168.4.52 80 {
          weight 1
      }
  }

4、启动服务

    # service keepalived start
    [root@pc50 ~]# 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.4.252:80 rr persistent 50
      -> 192.168.4.51:80              Route   1      0          0         
      -> 192.168.4.52:80              Route   1      0          0     
    [root@pc50 ~]# ip addr show | grep 192.168.4
        inet 192.168.4.50/24 brd 192.168.4.255 scope global eth0
        inet 192.168.4.252/32 scope global eth0

    [root@pc55 ~]# 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.4.252:80               0        0        0        0        0
      -> 192.168.4.51:80                     0        0        0        0        0
      -> 192.168.4.52:80                     0        0        0        0        0
    [root@pc55 ~]# ip addr show | grep 192.168.4
        inet 192.168.4.55/24 brd 192.168.4.255 scope global eth0

5、客户端访问

# elinks --dump 192.168.4.252
   192.168.4.52
[root@room1pc32 桌面]# elinks --dump 192.168.4.252
   192.168.4.51
[root@room1pc32 桌面]# elinks --dump 192.168.4.252
   192.168.4.52
[root@room1pc32 桌面]# elinks --dump 192.168.4.252
   192.168.4.51
[root@room1pc32 桌面]# elinks --dump 192.168.4.252
   192.168.4.52

# 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.4.252:80               5       25        0     2075        0
  -> 192.168.4.51:80                     2       10        0      830        0
  -> 192.168.4.52:80                     3       15        0     1245        0

[root@pc55 ~]# 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.4.252:80               0        0        0        0        0
  -> 192.168.4.51:80                     0        0        0        0        0
  -> 192.168.4.52:80                     0        0        0        0        0

模拟50 故障 验证Keepalived 高可用

[root@pc50 ~]#  service keepalived stop

[root@pc50 ~]# ip addr show | grep 192.168.4
    inet 192.168.4.50/24 brd 192.168.4.255 scope global eth0

[root@pc55 ~]# ip addr show | grep 192.168.4
    inet 192.168.4.55/24 brd 192.168.4.255 scope global eth0
    inet 192.168.4.252/32 scope global eth0

客户端访问

# elinks --dump 192.168.4.252
   192.168.4.52
# elinks --dump 192.168.4.252
   192.168.4.51
# elinks --dump 192.168.4.252
   192.168.4.52
# elinks --dump 192.168.4.252
   192.168.4.51
# elinks --dump 192.168.4.252
   192.168.4.52

# 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.4.252:80               5       25        0     2075        0
  -> 192.168.4.51:80                     2       10        0      830        0
  -> 192.168.4.52:80                     3       15        0     1245        0

LVS负载均衡+动静分离+高可用(nginx+tomcat+keepalived)

一、环境介绍

基于LVS(linux virtual server)linux虚拟服务器的http集群搭建
环境:使用VMware pro10,CentOS6.5
一共使用4台虚拟机,两台安装Ngnix,两台安装tomcat。
这四台服务器的作用分别是:其中一台nginx作为主服务器,另一台nginx_bk作为备用服务器,然后两台安装tomcat的虚拟机作为调度服务器。
安装并克隆虚拟机后,将四台虚拟机重新命名,分别命名为nginx, nginx_bk,server1,server2:

四台虚拟机的ip地址分别如下:

centOS_nginx 192.168.20.2.135
centOS_nginx_bk 192.168.20.2.139
CentOS_server1 192.168.20.2.134
CentOS+server2 192.168.20.2.137

未分类

二、环境安装

1、安装JDK

四台虚拟机均安装JDK,因安装过程是一样的,所以此处只截图一台虚拟机jdk安装过程。
首先查看jdk版本,centos默认安装openJDK:
未分类
检查可用的JDK版本:
[图片上传失败…(image-2ebecc-1512133579646)]

卸载原来openJDK
未分类
再次查看,已经卸载成功:
未分类
开始安装JDK,到oracle官网下载liunx jdk包,解压到当前目录下
解压好,进入目录查看:
未分类
配置JDK环境变量,修改/etc/profile
未分类
使环境变量生效:
未分类
参看结果:
未分类
此时可以看到jdk已经安装成功
这边liun下jdk的安装有很详细教程,可以去网上搜

2.两台服务器安装tomcat

下载tomcat,解压到/opt目录
解压后查看:
未分类
Root权限进入/bin目录,启动tomcat
未分类
配置防火墙端口:
未分类
未分类
重新加载防火墙配置:
未分类
未分类
启动tomcat访问,首页访问成功:

至此,tomcat安装完成,另一台server虚拟机可克隆该台虚拟机来实现。

3、nginx安装

下载nginx,解压到/usr/local目录下,解压后查看:
未分类
进入解压目录执行./configure命令进行安装
出现错误及解决方法:
错误1:
未分类
原因:缺少gc++
解决:
未分类
错误2:
未分类
解决:
未分类
错误3:
未分类
解决:
未分类
解决上述错误后,再执行安装命令:
未分类
查看nginx进程号:
未分类
启动nginx
未分类
关闭nginx命令是./nginx -s stop
默认端口是80,此时可在网页访问到:
未分类
至此,Nginx安装完成。

4、keepalive安装

Keepalived是一个基于VRRP协议来实现的服务高可用方案,作用是检测web服务器的状态,如果有一台web服务器死机,或工作出现故障,Keepalived将检测到,并将有故障的web服务器从系统中剔除,当web服务器工作正常后Keepalived自动将web服务器加入到服务器群中,这些工作全部自动完成,不需要人工干涉,需要人工做的只是修复故障的web服务器。
Keepalived实现服务的高可用(HA),应用已经非常广泛,很多软件都会和他搭配使,比如LVS,Nginx,Redis等
下载keepalie,解压到/opt/keepalive目录下
安装依赖插件:

yum install -y gcc openssl-devel popt-devel

编译安装:

./configure –prefix=/usr/local/keepalive
Make
Make install

编译之后的配置:
未分类
获得权限:
未分类
修改/etc/init.d/keepalived文件,将默认路径改成当前alive安装路径
未分类
即默认为前一行注释掉的路径,改为下一行,指向了正确的配置文件位置。

配置环境变量
未分类
建立软连接:
未分类
修改/usr/local/keepalive/etc/sysconfig/keepalived文件,修改正确的启动参数
未分类
启动Keepalived
未分类
设置keepalived服务为开机自启动
未分类
至此keepalived安装配置成功,另一两台nginx_bk可以克隆该台虚拟机。


其实在centos下可以直接用yum install keepalived来安装。默认安装路径为/etc/keepalived
用yum来装比较方便

三、负载均衡

现在有两台服务器192.168.204.134和192.168.204.137,服务器上各有一台tomcat,端口均为8080,在192.168.204上有Nginx
修改nginx安装目录中conf目录下的nginx.conf文件
主要配置信息如下:
未分类

补充知识了解:
nginx负载均衡到多台服务器上时,默认采用轮询策略:
常见策略:
1、轮询
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
2、weight
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况,数字越大命中率越高。
例如:轮询几率是2:1
upstream bakend {
server 192.168.0.14 weight=2;
server 192.168.0.15 weight=1;
}
2、ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
例如:
upstream bakend {
ip_hash;
server 192.168.0.14:88;
server 192.168.0.15:80;
}

启动两台tomcat,重新启动nginx,访问192.168.204.135就会随机访问192.168.204.134和192.168.204.137
测试:
在两台tomcat服务器下webapps目录下创建文件夹21751152,新建index.html文件,index.html文件内容分别如下:
Server1下index.html文件:
未分类
Server2下index.html文件:
未分类
首先测试在两台tomcat服务器下本地能访问这两个页面:
Server1下:
未分类
Server2下:
未分类
可以看到两台服务下均可正常访问
然后在安装Nginx服务器下测试:
未分类
未分类
可以看到,在nginx服务器下,在网页中每次刷新都会随机访问到两台Tomcat服务器中的任意一台,可以看出,已经完成了负载均衡的效果。

四、动静分离

为了提高网站的响应速度,减轻程序服务器(tomcat)的负载,对于js,css,图片等静态文件可以在nginx反向代理服务器中进行缓存,这样浏览器在请求一个静态资源的时候,代理服务器就可以直接处理,而不用将请求转发给后端服务器。而用户请求的动态文件比如jsp则会转发给tomcat服务器处理,这就是动静分离,也是反向服务器的一个重要作用。
在server1这台服务器webapp/21751152目录下建index.jsp文件:
Index.jsp内容如下:
未分类
然后进行Nginx.conf配置文件的修改:
主要修改内容如下:
未分类
Root /usr/local/webapps 这段代码的意思是指定Nginx访问的目录,即静态资源所在的目录。

Expires 30d.指这些资源文件在客户端浏览器的缓存时间,30d值30天,1h指一小时
开始测试:
首先在server1本地进行测试,页面可以正常访问:
未分类
然后在nginx服务器下进行测试:
未分类
可以看到,向日葵这张图片作为静态文件,没被加载出来。这是因为静态资源访问请求已经被Nginx拦截,由Nginx进行处理。但是Nginx服务器的 /usr/local/webapps 目录下并没有图片资源,所以图片没有加载出来。index.jsp页面能够显示,说明动态的请求已经转发到了Tomcat,Tomcat对index.jsp进行了解析。
在Nginx服务器 /usr/local/webapps 目录下放置图片文件,将tomcat上把21751152/img/flower.jpg整个目录拷贝到其中。然后再次刷新。
未分类
未分类
此时,图片就被加载出来了。至此,可以看出已经Nginx已经实现了动静分离的功能。
在配置动静分离后,用户请求你定义的静态资源,默认会去nginx的发布目录请求,而不会到后端请求,这样可以提高网站响应速度,减轻真实Web服务器的负载压力。
不过在开发环境下,为了便于开发,咱们的静态资源和代码还是放在一起的,等开发测试完成,才会将完成的完整程序部署到生成环境上,然而程序代码和静态资源是分别放置到不同的服务器上的。

五、keepalive高可用

编辑ngin服务器的keepalived.conf文件,keepalived.conf文件如下图所示:
未分类
未分类
画出红线部分是主要需要注意的地方
备份的nginx_bk配置文件与此类似
需要注意的以下几个点:
需要修改state为BACKUP , priority比MASTER低,virtual_router_id和master的值一致
配置文件如下:
未分类
未分类
注:在主备机中vip应设置一致

1、遇到的问题1及解决过程

用keepalived方式在主nginx服务器中添加了虚拟Ip,但是用ip addr查看发现仍然只有一个IP地址,即keepaLived.cof文件里面配置的vip没有起到效果
未分类
解决问题过程:
(1)尝试一:
可能是keepalived没有安装成功,所以采用yum重新安装keepalived
但是重装后还是发现VIP没有生效。
(2)最终解决:
后来在同学的提醒下,发现是自己的keepalived服务没有启动好,nginx服务也需要重启。这两个服务启动好后,就可以了。
开始测试:
在两台nginx和nginx_bk服务器中keepalived服务和nginx服务都开启的情况下:
首先测试nginx的IP:
未分类
可以看到在Nginx中已经有虚拟ip了
而在Nginx_bk服务器中:
未分类
可以看到没有绑定虚拟ip
访问192.168.204.177
未分类
未分类
这是访问虚拟ip地址,发现也被转发到了Nginx主机192.168.204.135指向的tomcat服务器上,同时也是随机分配到了两天Tomcat服务器上,即实现了负载均衡。

2、遇到的问题2及解决过程

Nginx主从机器没有顺利切换
在模仿Nginx主机宕机过程中:
用service keepalived stop 命令将Nginx主机服务的keepalived服务停止。
未分类
可以看到虚拟ip就没有绑在主机上
此时再去查看nginx_bk服务器,按道理来说此时Nginx_bk这台机器上应该会绑定vip,但实际查看的时候,发现并没有绑定过来
解决过程:
(1) 尝试1
因为nginx_bk这台服务器是我克隆nginx主机这台虚拟机得到的,所以存在mac地址冲突问题,猜想可能是这个原因导致的无法主从切换。
所以我对nginx_bk这台虚拟机重新生成了mac地址
过程如下:
首先关闭该虚拟机
然后选中该虚拟机点击“设置”,选择“网络适配器”,“高级”
未分类
然后点击“生成”
未分类
这样就重新生成了一个MAC地址。
然后对该虚拟重启后,重新启动keepalived,nginx等服务,发现还是无法正常切换
(2) 尝试2
因为我的几台虚拟机都没有设置静态IP,在同学的建议下,可能是没有设置静态IP导致的问题,所以我对nginx和nginx_bk这两台服务器都设置了静态ip,
设置过程如下:
Nginx主机:
未分类
未分类
对Nginx_bk服务器静态地址设置与此类似

如上设置了静态IP后,问题还是没有得到解决。
但是在多次尝试中,意外发现,当把nginx_bk这台虚拟机的nginx服务关闭后,两台虚拟机之间的主从关系是能够体现的
即当nginx主机中keepalive和nginx服务都正常开启的情况下,nginx主机下绑定了192.168.204.177这个Vip
未分类
当nginx_bk主机中keepaliv服务正常开启的情况下,而nginx服务停止的情况下,该虚拟机是没有绑定虚拟ip的
未分类
然后将nginx主机的keepalived服务停止时:
未分类
如上两张图所示:
主机下绑定的vip已经漂移到了nginx_bk这台主机上
然后此时把nginx_bk这台主机上的nginx服务启动,发现在浏览器上访问vip地址时也顺利转发到了两台tomcat服务器上。
未分类
这时再把nginx主机上的keepalive重新启动,同时关闭nginx_bk主机上的nginx服务
未分类
此时nginx主机上又重新绑定了vip,同时网页也恢复了访问。
再去查看nginx_bk主机情况:
未分类
Nginx_bk上仍然定着vip,当把nginx主机重启后,在该虚拟机上通过vip也能访问到两台tomcat上的内容。
未分类
所以在这种情况下相当于两台nginx都同时被作为了访问入口。
最终我没有把该问题很好的解决掉,猜测的原因可能与Nginx有关。可能会在后期继续研究这个问题

参考博客:
http://www.cnblogs.com/mrlinfeng/p/6146866.html
http://blog.csdn.net/u010028869/article/details/50612571
上述的实现过程我主要参照了这两篇博客,感谢他们的无私分享。

你真的掌握 LVS、Nginx 及 HAProxy 的工作原理吗

当前大多数的互联网系统都使用了服务器集群技术,集群是将相同服务部署在多台服务器上构成一个集群整体对外提供服务,这些集群可以是 Web 应用服务器集群,也可以是数据库服务器集群,还可以是分布式缓存服务器集群等等。

未分类

在实际应用中,在 Web 服务器集群之前总会有一台负载均衡服务器,负载均衡设备的任务就是作为 Web 服务器流量的入口,挑选最合适的一台 Web 服务器,将客户端的请求转发给它处理,实现客户端到真实服务端的透明转发。

最近几年很火的「云计算」以及分布式架构,本质上也是将后端服务器作为计算资源、存储资源,由某台管理服务器封装成一个服务对外提供,客户端不需要关心真正提供服务的是哪台机器,在它看来,就好像它面对的是一台拥有近乎无限能力的服务器,而本质上,真正提供服务的,是后端的集群。

LVS、Nginx、HAProxy 是目前使用最广泛的三种软件负载均衡软件。

一般对负载均衡的使用是随着网站规模的提升根据不同的阶段来使用不同的技术。具体的应用需求还得具体分析,如果是中小型的 Web 应用,比如日 PV 小于1000万,用 Nginx 就完全可以了;如果机器不少,可以用 DNS 轮询,LVS 所耗费的机器还是比较多的;大型网站或重要的服务,且服务器比较多时,可以考虑用 LVS。

目前关于网站架构一般比较合理流行的架构方案:Web 前端采用 Nginx/HAProxy+Keepalived 作负载均衡器;后端采用 MySQ L数据库一主多从和读写分离,采用 LVS+Keepalived 的架构。

LVS

LVS 是 Linux Virtual Server 的简称,也就是 Linux 虚拟服务器。现在 LVS 已经是 Linux 标准内核的一部分,从 Linux2.4 内核以后,已经完全内置了 LVS 的各个功能模块,无需给内核打任何补丁,可以直接使用 LVS 提供的各种功能。

LVS 自从1998年开始,发展到现在已经是一个比较成熟的技术项目了。

LVS 的体系结构

未分类

LVS 架设的服务器集群系统有三个部分组成:

  • 最前端的负载均衡层,用 Load Balancer 表示
  • 中间的服务器集群层,用 Server Array 表示
  • 最底端的数据共享存储层,用 Shared Storage 表示

LVS 负载均衡机制

LVS 不像 HAProxy 等七层软负载面向的是 HTTP 包,所以七层负载可以做的 URL 解析等工作,LVS 无法完成。

LVS 是四层负载均衡,也就是说建立在 OSI 模型的第四层——传输层之上,传输层上有我们熟悉的 TCP/UDP,LVS 支持 TCP/UDP 的负载均衡。因为 LVS 是四层负载均衡,因此它相对于其它高层负载均衡的解决办法,比如 DNS 域名轮流解析、应用层负载的调度、客户端的调度等,它的效率是非常高的。

所谓四层负载均衡 ,也就是主要通过报文中的目标地址和端口。七层负载均衡 ,也称为“内容交换”,也就是主要通过报文中的真正有意义的应用层内容。

未分类

LVS 的转发主要通过修改 IP 地址(NAT 模式,分为源地址修改 SNAT 和目标地址修改 DNAT)、修改目标 MAC(DR 模式)来实现。

NAT 模式:网络地址转换

NAT(Network Address Translation)是一种外网和内网地址映射的技术。

NAT 模式下,网络数据报的进出都要经过 LVS 的处理。LVS 需要作为 RS(真实服务器)的网关。

当包到达 LVS 时,LVS 做目标地址转换(DNAT),将目标 IP 改为 RS 的 IP。RS 接收到包以后,仿佛是客户端直接发给它的一样。RS 处理完,返回响应时,源 IP 是 RS IP,目标 IP 是客户端的 IP。这时 RS 的包通过网关(LVS)中转,LVS 会做源地址转换(SNAT),将包的源地址改为 VIP,这样,这个包对客户端看起来就仿佛是 LVS 直接返回给它的。

未分类

DR 模式:直接路由

DR 模式下需要 LVS 和 RS 集群绑定同一个 VIP(RS 通过将 VIP 绑定在 loopback 实现),但与 NAT 的不同点在于:请求由 LVS 接受,由真实提供服务的服务器(RealServer,RS)直接返回给用户,返回的时候不经过 LVS。

详细来看,一个请求过来时,LVS 只需要将网络帧的 MAC 地址修改为某一台 RS 的 MAC,该包就会被转发到相应的 RS 处理,注意此时的源 IP 和目标 IP 都没变,LVS 只是做了一下移花接木。RS 收到 LVS 转发来的包时,链路层发现 MAC 是自己的,到上面的网络层,发现 IP 也是自己的,于是这个包被合法地接受,RS 感知不到前面有 LVS 的存在。而当 RS 返回响应时,只要直接向源 IP(即用户的 IP)返回即可,不再经过 LVS。

未分类

DR 负载均衡模式数据分发过程中不修改 IP 地址,只修改 mac 地址,由于实际处理请求的真实物理 IP 地址和数据请求目的 IP 地址一致,所以不需要通过负载均衡服务器进行地址转换,可将响应数据包直接返回给用户浏览器,避免负载均衡服务器网卡带宽成为瓶颈。因此,DR 模式具有较好的性能,也是目前大型网站使用最广泛的一种负载均衡手段。

LVS 的优点

  • 抗负载能力强、是工作在传输层上仅作分发之用,没有流量的产生,这个特点也决定了它在负载均衡软件里的性能最强的,对内存和 cpu 资源消耗比较低。

  • 配置性比较低,这是一个缺点也是一个优点,因为没有可太多配置的东西,所以并不需要太多接触,大大减少了人为出错的几率。
    工作稳定,因为其本身抗负载能力很强,自身有完整的双机热备方案,如 LVS+Keepalived。

  • 无流量,LVS 只分发请求,而流量并不从它本身出去,这点保证了均衡器 IO 的性能不会受到大流量的影响。

  • 应用范围比较广,因为 LVS 工作在传输层,所以它几乎可以对所有应用做负载均衡,包括 http、数据库、在线聊天室等等。

LVS 的缺点

  • 软件本身不支持正则表达式处理,不能做动静分离;而现在许多网站在这方面都有较强的需求,这个是 Nginx、HAProxy+Keepalived 的优势所在。

  • 如果是网站应用比较庞大的话,LVS/DR+Keepalived 实施起来就比较复杂了,相对而言,Nginx/HAProxy+Keepalived就简单多了。

Nginx

Nginx 是一个强大的 Web 服务器软件,用于处理高并发的 HTTP 请求和作为反向代理服务器做负载均衡。具有高性能、轻量级、内存消耗少,强大的负载均衡能力等优势。

未分类

Nignx 的架构设计

相对于传统基于进程或线程的模型(Apache就采用这种模型)在处理并发连接时会为每一个连接建立一个单独的进程或线程,且在网络或者输入/输出操作时阻塞。这将导致内存和 CPU 的大量消耗,因为新起一个单独的进程或线程需要准备新的运行时环境,包括堆和栈内存的分配,以及新的执行上下文,当然,这些也会导致多余的 CPU 开销。最终,会由于过多的上下文切换而导致服务器性能变差。

反过来,Nginx 的架构设计是采用模块化的、基于事件驱动、异步、单线程且非阻塞。

Nginx 大量使用多路复用和事件通知,Nginx 启动以后,会在系统中以 daemon 的方式在后台运行,其中包括一个 master 进程,n(n>=1) 个 worker 进程。所有的进程都是单线程(即只有一个主线程)的,且进程间通信主要使用共享内存的方式。

其中,master 进程用于接收来自外界的信号,并给 worker 进程发送信号,同时监控 worker 进程的工作状态。worker 进程则是外部请求真正的处理者,每个 worker 请求相互独立且平等的竞争来自客户端的请求。请求只能在一个 worker 进程中被处理,且一个 worker 进程只有一个主线程,所以同时只能处理一个请求。(原理同 Netty 很像)

未分类

Nginx 负载均衡

Nginx 负载均衡主要是对七层网络通信模型中的第七层应用层上的 http、https 进行支持。

Nginx 是以反向代理的方式进行负载均衡的。反向代理(Reverse Proxy)方式是指以代理服务器来接受 Internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 Internet 上请求连接的客户端,此时代理服务器对外就表现为一个服务器。

Nginx 实现负载均衡的分配策略有很多,Nginx 的 upstream 目前支持以下几种方式:

  • 轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器 down 掉,能自动剔除。
  • weight:指定轮询几率,weight 和访问比率成正比,用于后端服务器性能不均的情况。
  • ip_hash:每个请求按访问 ip 的 hash 结果分配,这样每个访客固定访问一个后端服务器,可以解决 session 的问题。
    fair(第三方):按后端服务器的响应时间来分配请求,响应时间短的优先分配。
  • url_hash(第三方):按访问 url 的 hash 结果来分配请求,使每个 url 定向到同一个后端服务器,后端服务器为缓存时比较有效。

Nginx 的优点

  • 跨平台:Nginx 可以在大多数 Unix like OS编译运行,而且也有 Windows 的移植版本
  • 配置异常简单:非常容易上手。配置风格跟程序开发一样,神一般的配置
  • 非阻塞、高并发连接:官方测试能够支撑5万并发连接,在实际生产环境中跑到2~3万并发连接数
  • 事件驱动:通信机制采用 epoll 模型,支持更大的并发连接
  • Master/Worker 结构:一个 master 进程,生成一个或多个 worker 进程
  • 内存消耗小:处理大并发的请求内存消耗非常小。在3万并发连接下,开启的10个 Nginx 进程才消耗150M 内存(15M*10=150M)
  • 内置的健康检查功能:如果 Nginx 代理的后端的某台 Web 服务器宕机了,不会影响前端访问
  • 节省带宽:支持 GZIP 压缩,可以添加浏览器本地缓存的 Header 头
  • 稳定性高:用于反向代理,宕机的概率微乎其微

Nginx 的缺点

  • Nginx 仅能支 持http、https 和 Email 协议,这样就在适用范围上面小些,这个是它的缺点
  • 对后端服务器的健康检查,只支持通过端口来检测,不支持通过 ur l来检测。不支持 Session 的直接保持,但能通过 ip_hash 来解决

HAProxy

HAProxy 支持两种代理模式 TCP(四层)和HTTP(七层),也是支持虚拟主机的。

HAProxy 的优点能够补充 Nginx 的一些缺点,比如支持 Session 的保持,Cookie 的引导;同时支持通过获取指定的 url 来检测后端服务器的状态。

HAProxy 跟 LVS 类似,本身就只是一款负载均衡软件;单纯从效率上来讲 HAProxy 会比 Nginx 有更出色的负载均衡速度,在并发处理上也是优于 Nginx 的。

HAProxy 支持 TCP 协议的负载均衡转发,可以对 MySQL 读进行负载均衡,对后端的 MySQL 节点进行检测和负载均衡,大家可以用 LVS+Keepalived 对 MySQL 主从做负载均衡。

HAProxy 负载均衡策略非常多:Round-robin(轮循)、Weight-round-robin(带权轮循)、source(原地址保持)、RI(请求URL)、rdp-cookie(根据cookie)。

实现基于LVS负载均衡集群的电商网站架构

背景

随着业务的发展,网站的访问量越来越大,网站访问量已经从原来的1000QPS,变为3000QPS,网站已经不堪重负,响应缓慢,面对此场景,单纯靠单台LNMP的架构已经无法承载更多的用户访问,此时需要用负载均衡技术,对网站容量进行扩充,来解决承载的问题。scale out? scale up?

技术说明

集群(cluster)技术是一种较新的技术,通过集群技术,可以在付出较低成本的情况下获得在性能、可靠性、灵活性方面的相对较高的收益,其任务调度则是集群系统中的核心技术。

集群是一组相互独立的、通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理。一个客户与集群相互作用时,集群像是一个独立的服务器。

未分类

集群组成后,可以利用多个计算机和组合进行海量请求处理(负载均衡),从而获得很高的处理效率,也可以用多个计算机做备份(高可用),使得任何一个机器坏了整个系统还是能正常运行。集群在目前互联网公司是必备的技术,极大提高互联网业务的可用性和可缩放性。

负载均衡集群技术

负载均衡(Load Balance)负载均衡集群为企业需求提供了可解决容量问题的有效方案。负载均衡集群使负载可以在计算机集群中尽可能平均地分摊处理。

负载通常包括应用程序处理负载和网络流量负载。这样的系统非常适合向使用同一组应用程序的大量用户提供服务。每个节点都可以承担一定的处理负载,并且可以实现处理负载在节点之间的动态分配,以实现负载均衡。对于网络流量负载,当网络服务程序接受了高入网流量,以致无法迅速处理,这时,网络流量就会发送给在其它节点上运行的网络服务程序。也可根据服务器的承载能力,进行服务请求的分发,从而使用户的请求得到更快速的处理。

负载均衡集群技术实现

负载均衡(Load Balance)

  • 负载均衡技术类型:基于4层负载均衡技术和基于7层负载均衡技术
  • 负载均衡实现方式:硬件负载均衡设备或者软件负载均衡
  • 硬件负载均衡产品:F5 BIG-IP 、Citrix Netscaler 、深信服 、Array 、Radware
  • 软件负载均衡产品: LVS(Linux Virtual Server)、 Haproxy、Nginx、Ats(apache traffic server)

负载均衡技术演示图

未分类

lvs是实现负载均衡技术的一种,下面来介绍一下lvs

LVS是什么

LVS是Linux Virtual Server的简称,也就是Linux虚拟服务器, 是一个由章文嵩博士发起的自由软件项目,它的官方站点是www.linuxvirtualserver.org。现在LVS已经是 Linux标准内核的一部分,在Linux2.4内核以前,使用LVS时必须要重新编译内核以支持LVS功能模块,但是从Linux2.4内核以后,已经完全内置了LVS的各个功能模块,无需给内核打任何补丁,可以直接使用LVS提供的各种功能。

LVS自从1998年开始,发展到现在已经是一个比较成熟的技术项目了。可以利用LVS技术实现高可伸缩的、高可用的网络服务,例如WWW服务、Cache服务、DNS服务、FTP服务、MAIL服务、视频/音频点播服务等等,有许多比较著名网站和组织都在使用LVS架设的集群系统,例如:Linux的门户网(www.linux.com)、向RealPlayer提供音频视频服务而闻名的Real公司(www.real.com)、全球最大的开源网站(sourceforge.net)等。
LVS软件作用:通过LVS提供的负载均衡技术和Linux操作系统实现一个高性能、高可用的服务器群集,它具有良好可靠性、可扩展性和可操作性。从而以低廉的成本实现最优的服务性能。

LVS特性

高并发连接:LVS基于内核网络层面工作,有超强的承载能力和并发处理能力。单台LVS负载均衡器,可支持上万并发连接。稳定性强:是工作在网络4层之上仅作分发之用,这个特点也决定了它在负载均衡软件里的性能最强,稳定性最好,对内存和cpu资源消耗极低。

成本低廉:硬件负载均衡器少则十几万,多则几十万上百万,LVS只需一台服务器和就能免费部署使用,性价比极高。

配置简单:LVS配置非常简单,仅需几行命令即可完成配置,也可写成脚本进行管理。

支持多种算法:支持多种论调算法,可根据业务场景灵活调配进行使用
支持多种工作模型:可根据业务场景,使用不同的工作模式来解决生产环境请求处理问题。

应用范围广:因为LVS工作在4层,所以它几乎可以对所有应用做负载均衡,包括http、数据库、DNS、ftp服务等等

缺点:工作在4层,不支持7层规则修改,机制过于庞大,不适合小规模应用。

LVS工作流程图

未分类

LVS工作内核模型

未分类

1.当客户端的请求到达负载均衡器的内核空间时,首先会到达PREROUTING链。
2.当内核发现请求数据包的目的地址是本机时,将数据包送往INPUT链。
3.LVS由用户空间的ipvsadm和内核空间的IPVS组成,ipvsadm用来定义规则,IPVS利用ipvsadm定义的规则工作,IPVS工作在INPUT链上,当数据包到达INPUT链时,首先会被IPVS检查,如果数据包里面的目的地址及端口没有在规则里面,那么这条数据包将被放行至用户空间。
4.如果数据包里面的目的地址及端口在规则里面,那么这条数据报文将被修改目的地址为事先定义好的后端服务器,并送往POSTROUTING链。
5.最后经由POSTROUTING链发往后端服务器。

LVS负载均衡NAT工作流程

未分类

未分类

(a). 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP

(b). PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链

(c). IPVS比对数据包请求的服务是否为集群服务,若是,修改数据包的目标IP地址为后端服务器IP,然后将数据包发至POSTROUTING链。 此时报文的源IP为CIP,目标IP为RIP

(d). POSTROUTING链通过选路,将数据包发送给Real Server

(e). Real Server比对发现目标为自己的IP,开始构建响应报文发回给Director Server。 此时报文的源IP为RIP,目标IP为CIP

(f). Director Server在响应客户端前,此时会将源IP地址修改为自己的VIP地址,然后响应给客户端。 此时报文的源IP为VIP,目标IP为CIP

实验:负载均衡集群企业级应用实战-LVS-nat模式

实验环境:

一台DR负载均衡器,两块网卡,一块桥接172.17.253.132,一块仅主机192.168.10.200
两台后端服务器,一块网卡仅主机192.168.10.188和192.168.10.189,实现过基于lnmp的电子商务网站的服务器

1、在DR负载均衡器配置

  • yum install ipvsadm -y

  • grep -i -C 10 “ipvs” /boot/config-VERSION-RELEASE.x86_64,#查看内核是否支持ipvs模块

  • iptables -F ;setenf orce 0清空防火墙策略,关闭selinux策略

  • ipvsadm -A -t 172.17.253.132:80 -s wrr #开启一个基于80端口的虚拟web服务,调度算法为wrr

  • ipvsadm -a -t 172.17.253.132:80 -r 192.168.10.188:80 -m -w1 #配置web服务后端服务器为nat工作方式,权重为1

ipvsadm -a -t 172.17.253.132:80 -r 192.168.10.189:80 -m -w1

  • 修改内核配置,开启路由转发
vim /etc/sysctl.conf

net.ipv4.ip_forward=1

sysctl -p 使修改的内和配置参数生效

2、在real server配置

iptables -F ;setenforce 0清空防火墙策略,关闭selinux策略
配置网关指向192.168.10.200,开启nginx,php-fpm,mariadb服务
route add defult gw 192.168.10.200

3、验证

在浏览器上访问172.17.253.132

LVS负载均衡DR工作模式

Virtual Server via Direct Routing(VS-DR):用直接路由技术实现虚拟服务器。当参与集群的计算机和作为控制管理的计算机在同一个网段时可以用此方法,控制管理的计算机接收到请求包时直接送到参与集群的节点。直接路由模式比较特别,很难说和什么方面相似,前种模式基本上都是工作在网络层上(三层),而直接路由模式则应该是工作在数据链路层上(二层)。

工作原理 :DR和REAL SERVER都使用同一个IP对外服务。但只有DR对ARP请求进行响应,所有REAL SERVER对本身这个IP的ARP请求保持静默。也就是说,网关会把对这个服务IP的请求全部定向给DR,而DR收到数据包后根据调度算法,找出对应的 REAL SERVER,把目的MAC地址改为REAL SERVER的MAC并发给这台REAL SERVER。这时REAL SERVER收到这个数据包,则等于直接从客户端收到这个数据包无异,处理后直接返回给客户端。由于DR要对二层包头进行改换,所以DR和REAL SERVER之间必须在一个广播域,也可以简单的理解为在同一台交换机上。

未分类

未分类

数据包到后端服务器时经过负载均衡器,回来的时候,直接发送到客户端,不经过负载均衡器,大大提高了效率。

未分类

LVS负载均衡DR工作流程

(a) 当用户请求到达Director Server,此时请求的数据报文会先到内核空间的PREROUTING链。 此时报文的源IP为CIP,目标IP为VIP

(b) PREROUTING检查发现数据包的目标IP是本机,将数据包送至INPUT链

(c) IPVS比对数据包请求的服务是否为集群服务,若是,将请求报文中的源MAC地址修改为DIP的MAC地址,将目标MAC地址修改RIP的MAC地址,然后将数据包发至POSTROUTING链。 此时的源IP和目的IP均未修改,仅修改了源MAC地址为DIP的MAC地址,目标MAC地址为RIP的MAC地址

(d) 由于DS和RS在同一个网络中,所以是通过二层来传输。POSTROUTING链检查目标MAC地址为RIP的MAC地址,那么此时数据包将会发至Real Server。

(e) RS发现请求报文的MAC地址是自己的MAC地址,就接收此报文。处理完成之后,将响应报文通过lo接口传送给eth0网卡然后向外发出。 此时的源IP地址为VIP,目标IP为CIP

(f) 响应报文最终送达至客户端

特点:

1、保证前端路由将目标地址为VIP报文统统发给Director Server,而不是RS

2、RS可以使用私有地址;也可以是公网地址,如果使用公网地址,此时可以通过互联网对RIP进行直接访问

3、RS跟Director Server必须在同一个物理网络中

4、所有的请求报文经由Director Server,但响应报文必须不能进过Director Server

5、不支持地址转换,也不支持端口映射

6、RS可以是大多数常见的操作系统

7、RS的网关绝不允许指向DIP(因为我们不允许他经过director)

8、RS上的lo接口配置VIP的IP地址

实验:负载均衡集群企业级应用实战-LVS-DR模式:

实验环境:一台DR负载均衡器,一块网卡172.17.253.132,桥接,两台台后端服务器172.17.251.236和172.17.253.253,各一块网卡,桥接

1、在DR负载均衡器上

  • yum install ipvsadm -y

  • grep -i -C 10 “ipvs” /boot/config-VERSION-RELEASE.x86_64,#查看内核是否支持ipvs模块

  • iptables -F ;setenf orce 0清空防火墙策略,关闭selinux策略

  • ifconfig ens33:0 172.17.253.100 broadcast 172.17.253.100 netmask 255.255.255.255 up #配置VIP到本地网卡别名ens33:0上(vip地址可以是随意的),并且只广播自己,否则,将来会和后端服务器上回环网卡上配置的vip冲突,所以在后端服务器上配置的vip也只广播自己

  • route add -host 172.17.253.100 dev ens33:0 #配置vip路由

  • ipvsadm -A -t 172.17.253.100:80 -s wrr #开启一个基于80端口的虚拟web服务,调度方式为wrr

  • ipvsadm -a -t 172.17.253.100:80 -r 172.17.253.132:80 -g -w 1 #配置web服务后端real server 为DR工作方式 权重为1

ipvsadm -a -t 172.17.253.100:80 -r 172.17.253.253:80 -g -w 1

  • 修改内核配置,开启路由转发
vim /etc/sysctl.conf  
net.ipv4.ip_forward=1  
sysctl -p 使修改的内核配置参数生效 

2、在RS后端服务器上

iptables -F ;setenforce 0清空防火墙策略,关闭selinux策略

  • ifconfig lo:0 172.17.253.100 broadcast 172.17.253.100 netmask 255.255.255.255 up #配置VIP到本地回环网卡lo上,并只广播自己

  • route add -host 172.17.253.100 lo:0 #配置本地回环网卡路由

  • echo “1” > /proc/sys/net/ipv4/conf/lo/arp_ignore

只回答目标IP地址是来访网络接口本地地址的ARP查询请求

echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce 

对查询目标使用最适当的本地地址.在此模式下将忽略这个IP数据包的源地址并尝试选择与能与该地址通信的本地地址.

echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore  
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce 

关闭arp应答

(1): 仅在请求的目标IP配置在本地主机的接收到请求报文的接口上时,才给予响应
(2):必须避免将接口信息向非本网络进行通告

  • 开启web、php-fpm、mysql服务

3、验证

在浏览器上访问172.17.253.100(vip)

LVS+Keepalived实现前端高可用实现

一、Keepalived简介及VRRP原理

Keepalived 是一个基于VRRP协议来实现的LVS服务高可用方案,可以利用其来避免单点故障。一个LVS服务会有2台服务器运行Keepalived,一台为主服务器(MASTER),一台为备份服务器(BACKUP),但是对外表现为一个虚拟IP,主服务器会发送特定的消息给备份服务器,当备份服务器收不到这个消息的时候,即主服务器宕机的时候, 备份服务器就会接管虚拟IP,继续提供服务,从而保证了高可用性。Keepalived是VRRP的完美实现,因此在介绍keepalived之前,先介绍一下VRRP的原理。
VRRP原理
在一个VRRP虚拟路由器中,有多台物理的VRRP路由器,但是这多台的物理的机器并不能同时工作,而是由一台称为MASTER的负责路由工作,其它的都是BACKUP,MASTER并非一成不变,VRRP让每个VRRP路由器参与竞选,最终获胜的就是MASTER。MASTER拥有一些特权,比如,拥有虚拟路由器的IP地址,我们的主机就是用这个IP地址作为静态路由的。拥有特权的MASTER要负责转发发送给网关地址的包和响应ARP请求。
VRRP通过竞选协议来实现虚拟路由器的功能,所有的协议报文都是通过IP多播(multicast)包(多播地址224.0.0.18)形式发送的。虚拟路由器由VRID(范围0-255)和一组IP地址组成,对外表现为一个周知的MAC地址。所以,在一个虚拟路由 器中,不管谁是MASTER,对外都是相同的MAC和IP(称之为VIP)。客户端主机并不需要因为MASTER的改变而修改自己的路由配置,对客户端来说,这种主从的切换是透明的。
在一个虚拟路由器中,只有作为MASTER的VRRP路由器会一直发送VRRP通告信息(VRRPAdvertisement message),BACKUP不会抢占MASTER,除非它的优先级(priority)更高。当MASTER不可用时(BACKUP收不到通告信息), 多台BACKUP中优先级最高的这台会被抢占为MASTER。这种抢占是非常快速的(<1s),以保证服务的连续性。由于安全性考虑,VRRP包使用了加密协议进行加密。

二、LVS+Keepalived实现前端高可用实现

1、 实验环境

[root@localhost ~]# uname -r
2.6.32-696.el6.x86_64
[root@localhost ~]# rpm -q keepalived
keepalived-1.2.13-5.el6_6.x86_64

时间同步:

[root@node2 ~]# ntpdate 192.168.1.200

各主机添加host能相互解析

关闭iptables及selinux

未分类

2、配置Keepalived

1)、在192.168.1.200及192.168.1.201上安装Keepalived(yum install keepalived -y)

2)、配置Keepalived

192.168.1.200配置文档:

global_defs {               //全局配置段
   notification_email {        //管理员通知邮箱,可不填写

   }
   notification_email_from root
   smtp_server 127.0.0.1       //邮件服务器地址
   smtp_connect_timeout 30
   router_id LVS_10         //主调度路由器名称,需和备份服务器保持一致
}

vrrp_instance VI_1 {         //VRRPD配置段
    state MASTER         //设置MASTER或BACKUP         
    interface eth0         //设置VIP物理地址的接口
    virtual_router_id 51            //虚拟路由ID号,每组需保持一致
    priority 100                    //优先级,越大越有限
    advert_int 1                    //心跳频率(秒)
    authentication {        
        auth_type PASS          //组播认证方式
        auth_pass 1111
    }
    virtual_ipaddress {
        192.168.1.250/24 dev eth0 label eth0:1 //VIP配置,可以有多个VIP
    }
}

virtual_server 192.168.1.250 80 {        //LVS段配置,注意端口
    delay_loop 3                       //健康检测时间
    lb_algo wrr                        //算法rr,wrr,lc,wlc等
    lb_kind DR                        //集群工作模式(nat、dr、tunl、fullnat)
    persistence_timeout 0            //会话保持时间
    protocol TCP                     //协议

    real_server 192.168.1.202 80 {    //realserver配置
        weight 1                    //权重
        TCP_CHECK {                 //健康检查(多种方式)
            connect_port 80     //检测端口
            connect_timeout 3   //超时时间
            nb_get_retry 3      //重试次数
            delay_before_retry 3 //重试间隔
        }
    }

    real_server 192.168.1.203 80 {
        weight 1
        TCP_CHECK {
            connect_port 80
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }
    }
}

192.168.1.201配置与上面类似更改state及priority

3、配置realserver

192.168.1.202配置:

DR realserver脚本:

#!/bin/bash
#
#script to start LVS DR real server.   
# description: LVS DR real server   
#   
.  /etc/rc.d/init.d/functions
VIP=192.168.1.250 #修改你的VIP  
host=`/bin/hostname`
case "$1" in
start)
       # Start LVS-DR real server on this machine.   
        /sbin/ifconfig lo down
        /sbin/ifconfig lo up
        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
        /sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up  
        /sbin/route add -host $VIP dev lo:0
;;  
stop)
        # Stop LVS-DR real server loopback device(s).  
        /sbin/ifconfig lo:0 down   
        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
;;  
status)
        # Status of LVS-DR real server.  
        islothere=`/sbin/ifconfig lo:0 | grep $VIP`   
        isrothere=`netstat -rn | grep "lo:0" | grep $VIP`   
        if [ ! "$islothere" -o ! "isrothere" ];then
            # Either the route or the lo:0 device   
            # not found.   
            echo "LVS-DR real server Stopped."   
        else
            echo "LVS-DR real server Running."   
        fi
;;
*)
            # Invalid entry.   
            echo "$0: Usage: $0 {start|status|stop}"   
            exit 1
;;
esac

执行脚本:

[root@node2 ~]# chmod +x realserver.sh 
[root@node2 ~]# ./realserver.sh start

检查相关脚本配置是否正确

ifconfig及cat

在node2上安装httpd后添加测试网页

echo "<h1>node2.psemily.com</h1>" > /var/www/html/index.html

node3类似操作

4、验证

启动192.168.1.200及192.168.1.201上keepalived后访问VIP:192.168.1.250

下图:图一:调度情况,图二为正常访问,图三为192.168.1.202停止httpd后的访问,图四为停止192.168.1.200后,192.168.1.201的日志

未分类

未分类

未分类

未分类

5、Keepalived的健康检测

HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK

1)HTTP_GET|SSL_GET

这里有几个要点:

a、两者都有两种检测方式,一种是简单的基于返回码确认;另一种是基于确认后端页面内容hash值,确认前后是否发生变化(是不是感觉有点高端,还有简单的防止页面被篡改的作用,当然,动态页面显然不行);

b、两者都是处理简单的GET请求,基于post返回值确认是否正常,这种方法显然不适用 ,不过POST方式是可以通过MISC_CHECK方式进行支持检测的;

c、两者配置语法上相同,只不过类型名不同而已 。同属于大的web请求范畴,只不过一个走的HTTP协议,一个走的HTTPS协议;

基于状态码检测,配置如下:

real_server 192.168.1.250 80 {
      weight 1
      HTTP_GET {
          url {
          path /index.html
          status_code 200      #http://192.168.1.250/index.html的返回状态码
            }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }

基于后端页面内容检测,配置如下:

real_server 192.168.1.250 80 {
     weight 1
     HTTP_GET {
       url {
       path /index.html
       digest 1366dcc22ca042f5e6a91232bc8f4c9f #http://192.168.1.202/index.html的digest值
        }
            connect_timeout 3
            nb_get_retry 3
            delay_before_retry 3
        }

digest是由genhash(通过该命令可以获取页面的hash串)生成,语法如下:

[root@localhost keepalived]# genhash -s 192.168.1.202 -p 80 -u /index.html
MD5SUM = 1366dcc22ca042f5e6a91232bc8f4c9f

2)TCP_CHECK

基于TCP的检测,配置如下:

real_server 192.168.1.250 80 {
        weight 100
        TCP_CHECK {
            connect_timeout 3  
            nb_get_retry 3  
            delay_before_retry 3  
            connect_port 80    //检测端口
        }
    }

3)MISC_CHECK

调用外部配置文件进行检测,配置如下:

MISC_CHECK {
    misc_path <STRING>|<QUOTED-STRING># 外部程序或者脚本路径
    misc_timeout <INT># 执行脚本的超时时间
    misc_dynamic #如果设置了misc_dynamic,healthchecker程序的退出状态码会用来动态调整服务器的权重(weight).
    #返回0:健康检查OK,权重不被修改
    #返回1:健康检查失败,权重设为0
    #返回2-255:健康检查OK,权重设置为:退出状态码-2,比如返回255,那么weight=255-2=253
}

脚本是可以选择传参数还是不传参数的,示例如下:

#不传参配置
real_server 192.168.1.250 80 {
    weight 1
    MISC_CHECK {
      misc_path /usr/local/bin/script.sh
    }
}
#传参配置
real_server 192.168.1.250 80 {
    weight 1
    MISC_CHECK {
      misc_path "/usr/local/bin/script.sh  arg1  arg2"
    }
}

6、实验中遇到的问题

实验中用当所有配置都配置完成后,有浏览器访问VIP时,出现了只调度到一个realserver上的情景,过一段时间后能调度到另外一个realserver上,停止其中一个httpd,浏览器访问时出现不能访问,过段时间才能访问运行的另一个realserver上。

查找网上资料后有以下两种方案:

1、修改persistence_timeout 0 将连接保持时间设置为0,修改后用浏览器访问还是没能解决。用curl可以看出效果

2、ipvsadm的时间

[root@localhost keepalived]# ipvsadm -l --timeout
Timeout (tcp tcpfin udp): 900 120 300

修改时间后访问仍然不行

[root@localhost keepalived]# ipvsadm --set 1 1 1

上述两种方法均不能解决浏览器访问调度到一个realserver上的问题,但是用curl能看出效果,在此先做个记录。

浅析负载均衡及LVS实现

负载均衡(Load Balance,缩写LB)是一种网络技术,它在多个备选资源中做资源分配,以达到选择最优。这里有三个关键字:

  • 网络技术,LB要解决的问题本质上是网络的问题,所以它实际上就是通过修改数据包中MAC地址、IP地址字段来实现数据包的“中转”;

  • 资源,这里的资源不仅仅是计算机也可以是交换机、存储设备等;

  • 最优,它则是针对业务而言最优,所以一般负载均衡有很多算法;轮询、加权轮询、最小负载等;

LB是网络技术所以业内就参考OSI模型用四层负载均衡、七层负载均衡进行分类。四层负载均衡工作在OSI的四层,这一层主要是TCP、UDP、SCTP协议,这种类型的负载均衡器不管数据包是什么,只是通过修改IP头部或者以太网头部的地址实现负载均衡。七层负载均衡工作在OSI的七层,这一层主要是HTTP、Mysql等协议,这种负载均衡一般会把数据包内容解析出来后通过一定算法找到合适的服务器转发请求。它是针对某个特定协议所以不通用。比如Nginx只能用于HTTP而不适用于Mysql。
四层负载均衡真正传统意义上的负载均衡,它通过修改网络数据包“中转”请求;一般工作在操作系统的内核空间(kernel space),比如通过Linux的netfilter定义的hook改变数据包。七层负载均衡并不是严格意义上的负载均衡,它必须解析出数据包的内容,根据内容来做相关的转发(比如做Mysql的读写分离);一般工作在用户空间(user space),比如通过Nginx、Mysql Proxy、Apache它们都是实现某个具体协议,很多资料都称这种软件叫代理(Proxy)。

实现LB的问题

无论哪种负载均衡都可以抽象为下面的图形:

未分类

任何负载均衡都要解决三个问题:

  • 修改数据包,使得数据包可以发送到backend servers;

  • frontend server要维护一个算法,可以选出最优的backend server

  • frontend server要维护一张表记录Client和backend servers的关系(比如TCP请求是一系列数据包,所以在TCP关闭所有的数据包都应该发送到同一个backend server)

以Nginx为例,forntend server收到HTTP数据包后会通过负载均衡算法选择出一台backend server;然后从本地重新构造一个HTTP请求发送给backend server,收到backend server请求后再次重新封装,以自己的身份返回给客户端。在这个过程中forntend server的Nginx是工作在用户空间的它代替Client访问backend server。

LVS的实现

LVS( Linux Virtual Server)是国产开源中非常非常非常优秀的项目,作者是章文嵩博士(关于章博的简历各位自行搜索)。它是一款四层负载均衡软件,在它的实现中forntend server称为director;backend server称为real server,它支持UDP、TCP、SCTP、IPSec( AH 、ESP两种数据包 )四种传输层协议的负载。

未分类

LVS以内核模块的形式加载到内核空间,通过netfilter定义的hook来实现数据包的控制。 它用到了三个Hook(以Linux 4.8.15为例)主要“挂在”:local_in、inet_forward、local_out;所有发送给本机的数据包都会经过local_int,所有非本机的数据包都会经过forward,所有从本机发出的数据包都会经过local_out。

LVS由两部分组成(很像iptables),用户空间提供了一个ipvsadm的命令行工具,通过它定义负载均衡的“规则”;内核模块是系统的主要模块它包括:

  • IP包处理模块,用于截取/改写IP报文;

  • 连接表管理,用于记录当前连接的Hash表;

  • 调度算法模块,提供了八种负载均衡算法——轮询、加权轮询、最少链接、加权最少链接、局部性最少链接、带复制的局部性最少链接、目标地址哈希、源地址哈希;

  • 连接状态收集,回收已经过时的连接;

  • 统计,IPVS的统计信息;

LVS实战

LVS术语定义:

  • DS:Director Server,前端负载均衡器节点(后文用Director称呼);

  • RS:Real Server,后端真实服务器;

  • VIP:用户请求的目标的IP地址,一般是公网IP地址;

  • DIP:Director Server IP,Director和Real Server通讯的内网IP地址;

  • RIP:Real Server IP,Director和Real Server通讯的内网IP地址;

很多文章都罗列了一大堆LVS三种模式之间的区别,我最讨厌的就是简单的罗列——没有什么逻辑性很难记忆。其实LVS中三种模式只有一个区别——谁来返回数据到客户端。在LB架构中客户端请求一定是先到达forntend server(LVS中称为Director),那么返回数据包则不一定经过Director。

  • NAT模式中,RS返回数据包是返回给Director,Director再返回给客户端;

  • DR(Direct Routing)模式中,RS返回数据是直接返回给客户端(通过额外的路由);Director通过修改请求中目标地址MAC为选定的RS实现数据转发,这就要求Diretor和Real Server必须在同一个广播域内(关于广播域请看《程序员学网络系列》)。

  • TUN(IP Tunneling)模式中,RS返回的数据也是直接返回给客户端,这种模式通过Overlay协议(把一个IP数据包封装到另一个数据包内部叫Overlay)避免了DR的限制。

以上就是LVS三种模式真正的区别,是不是清晰多了?^_^

NAT模式

未分类

NAT模式最简单,real_server只配置一个内网IP地址(RIP),网关指向director;director配置连个IP地址分别是提供外部服务的VIP和用于内部通讯的DIP。

  • 配置IP地址

VIP:10.10.10.10,

DIP:192.168.122.100

RS1-DIP:192.168.122.101

RS2-DIP:192.168.122.102

未分类

注意:Director配置了双网卡,默认路由指向10.10.10.1。即——VIP所在的网卡设置网关,DIP所在的网卡不要设置网关。

  • 配置director

Linux默认不会“转发”数据包,通过echo 1 > /proc/sys/net/ipv4/ip_forward开启forward功能。开启forward后Linux表现的就像一个路由器,它会根据本机的路由表转发数据包。

ipvsadm -A -t 10.10.10.10:80 -s rr       # 添加LVS集群,负载均衡算法为轮询(rr)
ipvsadm -a -t 10.10.10.10:80 -r 192.168.122.101 -m -w 1   # 添加LVS集群主机(10.10.10.10:80),VS调度模式为NAT(-m)及RS权重为1
ipvsadm -a -t 10.10.10.10:80 -r 192.168.122.102 -m -w 1   # 同上
  • 验证

通过client访问10.10.10.10的HTTP服务

未分类

NAT模式原理解析

  • client发送数据包,被路由到director服务器上;

  • director的netfilter local_in hook被触发,lvs模块收到该请求

  • lvs查询规则库(ipvsadm生成的规则),发现10.10.10.10:80端口被定义为NAT模式,执行轮询算法

  • IP包处理模块修改数据包,把目标IP地址修改为192.168.122.101,从DIP的所在网卡发送出去(所以源MAC是DIP网卡的MAC)。此时的数据包是:源MAC地址变成了00:01:3a:4d:5d:00(DIP网卡的MAC地址)源IP地址是172.10.10.10(client的IP地址),目标MAC和目标IP地址是本机地址。通过在RS1上抓包验证这一点

未分类

注意,Linux不会“校验”源IP地址是否是本机IP地址所以即便172.10.10.10不在DIP上数据包也是可以被发送的,此时的行为相当于“路由”(想一下“网关”如何给你发送某个公网返回的数据包)。

  • RS1收到请求目标MAC和IP都是本机,所以直接交给Nginx处理

  • Nginx的返回数据包交给Linux协议栈,系统发现目标地址是172.10.10.10和自己不在同一个网段,则把数据包交给网关——192.168.122.100(director)。这就是Real Server必须把网关指向Director Server的原因

  • director上的lvs再次触发,发现是返回数据包是:源MAC地址和IP地址是VIP网卡的MAC地址

这种模式虽然叫NAT模式,其实和NAT关系并不大,只是借用NAT的概念而已(发送到RS的源IP地址还是客户端的IP地址而不是DIP)。

DR模式

未分类

DR(Direct Route,直接路由)和NAT模式最大的区别是RS返回数据包不经过Director而是直接返回给用户。用户到达Director后,LVS会修改用户数据包中目标MAC地址为Real Server然后从DIP所在网卡转发出去,RS的返回数据包直接从单独的链路(拓扑图中是SW2R1)返回给用户。

所以DR模式中要求

  1. Director和RS必须在同一个广播域中,也就是二层可达(实验的拓扑中是通过SW2实现的) ,因为Director要修改目标MAC地址所以数据包只能在广播域内转发;

  2. RS必须可以路由到用户,也就是三层可达(实验的拓扑中Director和Real server共享同一个路由),因为Real Server的返回数据包是直接返回给用户的不经过Director;

  3. 配置IP

VIP:10.10.10.10,

DIP:192.168.122.100

RS1-DIP:192.168.122.101

RS2-DIP:192.168.122.102

  • 配置Real Server
#绑定VIP到本机的环回口
ifconfig lo:0 10.10.10.10 netmask 255.255.255.255  broadcast 10.10.10.10 up
#禁用ARP响应
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

RS是直接返回数据给用户,所以必须绑定VIP地址;因为Director和Real Server都绑定了VIP所以RS必须禁用ARP信息否则可能导致用户请求不是发送给Director而是直接到RS,这和LVS的期望是不相符的。。不同于NAT,在DR模式下RS的网关是指向默认网关的也就是能“返回”数据到客户端的网关(试验中R1充当默认网关)。

  • 配置Director
ipvsadm -A -t 10.10.10.10:80 -s rr       # 添加LVS集群,负载均衡算法为轮询(rr)
ipvsadm -a -t 10.10.10.10:80 -r 192.168.122.101 -g -w 1   # 添加LVS集群主机(10.10.10.10:80),VS调度模式为DR(-g)及RS权重为1
ipvsadm -a -t 10.10.10.10:80 -r 192.168.122.102 -g -w 1   # 同上
  • 验证

通过client访问10.10.10.10的HTTP服务

未分类

DR模式原理解析

  • client发送数据包,被路由到director服务器上;

  • director的netfilter local_in hook被触发,lvs模块收到该请求

  • lvs查询规则库(ipvsadm生成的规则),发现10.10.10.10:80端口被定义为DR模式,执行轮询算法

  • IP包处理模块修改数据包,把目标MAC修改为选中的RS的MAC地址,从DIP的所在网卡发送出去(所以源MAC是DIP网卡的MAC)。此时的数据包是:源MAC地址变成了00:01:3a:4d:5d:00(DIP网卡的MAC地址)源IP地址是172.10.10.10(client的IP地址),目标MAC是00:01:3a:f4:c5:00(RS的MAC)目标IP地址10.10.10.10(VIP)。通过在RS1上抓包验证这一点

未分类

  • RS1收到请求目标MAC和IP都是本机(VIP配置在本机的环回口),所以直接交给Nginx处理

  • Nginx的返回数据包交给Linux协议栈,系统发现目标地址是172.10.10.10和自己不在同一个网段,则把数据包交给网关——192.168.122.1。在我们的试验中R1是网关,它是可以直接返回数据给客户端的,所以数据被成功返回到客户端。

注意:在操作系统中(无论是Linux或者Windows)返回数据的时候是根据IP地址返回的而不是MAC地址,RS收到数据包MAC地址是Director的而IP地址则是客户端的RS如果按MAC地址返回那么数据包就发送到Director了,很显然是不正确的。而LVS的DR模式正是利用了这一点。

TUN模式

未分类

TUN(IP Tunneling,IP通道)是对DR模式的优化。和DR一样,请求数据包经过Director到Real Server返回数据包则是Real Server直接返回客户端。区别是:DR模式要求Director和Real Server在同一个广播域(通过修改目标MAC地址实现数据包转发)而TUN模式则是通过Overlay协议。
Overlay协议就是指把一个IP数据包封装在另一个数据包里面,LVS里面的Overlay协议属于比较原始的实现叫IP-in-IP,目前常见的Overlay协议包括:VxLAN、GRE、STT之类的。
T
UN模式要求

  1. Director和Real Server必须三层可达,拓扑图中故意加上一个R2用于分割两个广播域;

  2. Real Server必须可以路由到用户,也就是三层可达(实验的拓扑中Director和Real server共享同一个路由),因为RS的返回数据包是直接返回给用户的不经过Director;

  3. 因为采用Overlay协议,Real Server的MTU值必须设置为1480(1500-20)——即实际上能发送的数据要加上外层IP头部

TUN模式和DR模式没有本质区别(配置是一摸一样的,只是网络要求不一样),两者都不是特别实用所以本文就不展开介绍了。

总结

LVS的基本原理是利用Linux的netfilter改变数据包的流向以此实现负载均衡。基于性能考虑LVS提供了二种模式,请求和返回数据包都经过Director的NAT模式;请求经过Director返回数据包由Real Server独立返回的是DR和TUN模式(DR和TUN的区别是网络二层可达还是三层可达)。
DR和TUN理论上可能性能更高一些,但是这种假设的前提是——性能是出现在数据包转发,而以目前软硬件的架构而言数据转发已经不成问题了。原因有两点:首先Linux引入的NAPI可以平衡网卡中断模式和Polling的性能问题,所以内核本身的转发能力已经不是1998(LVS设计的时间)的情况,一般而言千兆的网络转发是不成问题的;其次大量的“数据平面加速”方案喷涌而出如果真是数据转发的问题我们有智能网卡、DPDK等方案能很好解决。
那么比较实用的只剩下NAT模式了,但是LVS的NAT模式有一个很大的缺陷——Real Server的网关是指向Director。

LVS NAT的改进

一般面向外部提供服务的集群环境中网络工程师会给我们一个外部IP,它可能是一个公网IP也可能是躲在防火墙后面的“私网IP”。总之只要我们把这个IP地址配置在某个机器上就能正常对外提供服务了。
这种环境中LVS的DR模式、TUN模式显的都比较繁琐(需要满足一定网络条件),所以NAT模式是最合适的,但是LVS中的NAT要求Real Server必须把网关指向Director,这就意味着Real Server之前可以三层可达的网络现在全部不行了(比如之前可以通过网关上网,现在则不行了)
回忆一下问题:当Director发送数据包的时候源地址是客户端IP地址,所以Real Server会把返回数据发送给网关,如果不把Director设置为Real Server的网关那么返回数据就“丢”了。改进方法也呼之欲出了,让Director发送数据包的时候使用DIP而不是客户端的IP地址就可以了。
按道理说通过LVS+SNAT可以实现,遗憾的是LVS和Iptables是不兼容的,LVS内部处理完数据包后Iptables会忽略这个数据包,所以解决办法只剩下两个:

  1. 在用户空间实现一个反向代理,比如Nginx;

  2. 修改LVS代码重新编译内核

第一种方法操作非常简单,在Director上安装一个反向代理,LVS配置的VIP和DIP保持一致就可以了,比如:

ipvsadm -A -t 192.168.122.100:80 -s rr
ipvsadm -a -t 192.168.122.100:80 -r 192.168.122.101 -m -w 1 
ipvsadm -a -t 192.168.122.100:80 -r 192.168.122.102 -m -w 1 

第二种方法就是阿里后来贡献的FullNat模式。

两个疑问

  • 为啥LVS不直接做彻底的NAT而直接使用客户端IP地址呢?改进后的NAT怎么规避这个问题?

这是由于LVS追求的是透明,试想Real Server如何拿到客户端的IP地址?改进后的NAT Real Server只能看到Director的IP地址,客户端的IP地址通过“额外途径”发送。反向代理方案中直接通过应用层的头部(比如HTTP的 x-forwarded-for);FullNAT方案中则通过TCP的Option带到Real Server。

  • Linux内核为什么不吸纳FullNAT模式?

是的,FullNAT配置简单速度也不慢所以是非常好的选择。Linux Kernel没有把它合并到内核代码的原因是认为:FullNAT本质上是LVS+SNAT,当我们提到SNAT的时候其实就是在说“用户空间”它不应该属于内核。这是Linux的一大基本原则。https://www.mail-archive.com/lvs-users@linuxvirtualserver.org/msg06046.html 这里你可以看到撕逼过程。