负载均衡工具

基于工作协议层次来划分:

        传输层:lvs、haproxy(mode tcp)

        应用层:haproxy、nginx、ats、perlbal

        lvs工作tcp/ip协议栈上的,依附于netfilter在内核中工作的,lvs不需要监听在套接字文件上。lvs简称Linux Vitual Server。

021217_0051_6.png

netfilter:
        PREROUTING --> INPUT

        PREROUTING --> FORWARD --> POSTROUTING

        OUTPUT --> POSTROUTING

        LVS工作在INPUT链上,只要发现在INPUT链上的请求被定义成集群服务就强行将请求转到POSTROUTING上了,到达POSTROUTING上就会经由网卡取出报文转发到后面的Real Server。

        在INPUT链上ipvs需要有规则要定义几个东西,要定义TCP/UDP上的那些端口要定义成集群服务和这个集群后面到底要提供多少个real server。

        LVS有两段组成,一段是ipvsadm工作在用户空间,用来定义规则,定义谁是集群服务,这个集群服务用那种算法,有多少个集群服务。工作在INPUT链上的叫ipvs。所以ipvsadm用来定义集群服务写规则,然后把规则直接通过系统调用送给内核中的ipvs。其实只要在编译内核时把ipvs编译了ipvs就在INPUT链上了只是没有使用,只要ipvs上有规则就会工作。

使用前提:

        在用户空间安装ipvsadm工具,用来定义和管理集群服务,包括增删查改等操作;内核中必须编译了IPVS功能。

查看内核是否编译了IPVS:

grep -i -A 5 'IPVS' /boot/config-3.10.0-693.el7.x86_64

# IPVS transport protocol load balancing support
#
CONFIG_IP_VS_PROTO_TCP=y    # 基于TCP协议的负载均衡调度功能
CONFIG_IP_VS_PROTO_UDP=y    # 基于UDP协议
CONFIG_IP_VS_PROTO_AH_ESP=y
CONFIG_IP_VS_PROTO_ESP=y
CONFIG_IP_VS_PROTO_AH=y
CONFIG_IP_VS_PROTO_SCTP=y

LVS类型:

        lvs-nat:RIP与DIP必须在同一网段中,修改VIP,CIP不修改。

        lvs-dr:Director与RS必须在同一物理网络中。通过MAC地址通信。

        lvs-tun:ip tunneling,在原有的IP首部再封装一个IP首部。

        lvs-fullnat:同时修改CIP和VIP。


LVS-nat


        目标地址转换:客户端请求后到达调度器,调度器从后端的realserver中挑选一个来响应请求,并将目标地址修改为RIP,realserver响应的请求要再次经过调度器,将原地址改为VIP,因为客户端请求的是VIP所以响应请求的也要是VIP。

15358710964442_upload.png

实验环境:CentOS7 要有两个网卡,CentOS6 两台作为web服务。

        先在CentOS7中再添加一块网卡,一块网卡配置VIP,为公网IP,另一块为DIP为私网IP用来与后端的Real server通信。

15359854223452_upload.png

在虚拟机设置中添加好网卡后到linux中设置网卡。

vim /etc/sysconfig/network-scripts/ifcfg-ens37

TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens37
DEVICE=ens37
ONBOOT=yes
GATEWAY0=192.168.96.2
IPADDR0=192.168.20.1
PREFIXO0=24
DNS1=180.168.255.118

然后重启网卡。

安装ipvsadm:

yum install ipvsadm

将 ReadServer1 和 ReadServer2 的网络连接通道改为和调度器网卡相同的通道VMnet2。

15360704143324_upload.png

        然后将两个RealServer的网关指向调度器的IP:192.168.20.1 ,这时候xshell工具可能连接不到虚拟机,因为跟真实机通信的是VMnet8。

调度器的两个IP:

vip:192.168.96.135
DIP:192.168.20.1

RS1:

IP:192.168.20.7
网关:192.168.20.1

RS2:

IP:192.168.20.8
网关:192.168.20.1

两台RS和DIP要在同一个网段中,RS的网关要指向DIP,VIP是用来与外界通信的,关闭SElinux和防火墙。

[root@node5 ~]# cat /proc/sys/net/ipv4/ip_forward
0
[root@node5 ~]# vim /etc/sysctl.conf 
net.ipv4.ip_forward = 1

运行如下命令:

[root@node5 ~]# sysctl -p
net.ipv4.ip_forward = 1
[root@node5 ~]# cat /proc/sys/net/ipv4/ip_forward
1

定义ipvsadm规则:

[root@node5 ~]# ipvsadm -A -t 192.168.96.135:80 -s rr
[root@node5 ~]# ipvsadm -a -t 192.168.96.135:80 -r 192.168.20.7 -m
[root@node5 ~]# ipvsadm -a -t 192.168.96.135:80 -r 192.168.20.8 -m

查看定义好的规则:

[root@node5 ~]# ipvsadm -L -n
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.96.135:80 rr
  -> 192.168.20.7:80              Masq    1      0          0         
  -> 192.168.20.8:80              Masq    1      0          0

打开浏览器访问VIP:192.168.96.135 这时就可以看到负载均衡效果了。

保存已经配置的规则:

[root@node5 ~]# ipvsadm -S > /etc/sysconfig/ipvsadm
[root@node5 ~]# cat /etc/sysconfig/ipvsadm
-A -t node5:http -s rr
-a -t node5:http -r 192.168.20.7:http -m -w 1
-a -t node5:http -r 192.168.20.8:http -m -w 1

清除规则:

ipvsadm -C

还原规则:

ipvsadm -R < /etc/sysconfig/ipvsadm

修改规则:

ipvsadm -E -t 192.168.96.135:80 -s sh

删除某个RS:

ipvsadm -d -t 192.168.96.96.135:80 -r 192.168.20.7:80

删除集群规则:

ipvsadm -D -t 192.168.96.135:80


LVS-dr模型


        在dr模型中只有请求报文才会经过调度器,响应报文不会经过调度器。客户端请求的是VIP所以客户端只会接收VIP的响应报文,这样实现的方法只有在每一个RIP服务器上配置VIP才可行。

15364211086173_upload.png

        当请求通过交换机到达调度器,调度器将会修改这个请求报文,将报文中的目标MAC地址修改为real server的MAC地址,再将报文返回给交换机,交换机发现目标MAC是real server的,就将请求发给real server来处理,real server拆掉发来的请求报文发现目标IP为VIP,因为real server上配置有VIP所以real server要响应服务。

        RIP要和VIP不在同一个网络中,所以RIP的网关不能和VIP指向同一个网关。

15364222927757_upload.png

        在real server内部RIP是配置在物理网卡上的,VIP是配置在lo别名上的(本地回环接口)。请求到达real server后发现目标IP是VIP将接受请求,由物理网卡RIP转到lo接口VIP,再发给web服务,web服务的响应报文先经过lo接口的VIP,再转发给物理网卡出去。因为只有经过VIP响应报文中的源地址才是VIP。

        要想达到lo配置的地址不为外界所知需要修改内核参数使其配置上IP后不通告。

        arp_igonre           定义是否响应别人的arp请求。

        arp_announce     是否接收并记录别人的通告,和是否通告给别人。

        arp_announce=2 时只是通告本地最佳网络,其他的不通告。也就是只通告RIP的,lo的不通告。

        arp_ignoce=1      时请求的地址必须配置在响应的接口上,否者不与响应。也就是请求RIP时只有配置了RIP的网卡接口才会响应,请求VIP的时候因为VIP没有配置在网卡接口上所以不会响应。

IP分配:

DIP    192.168.96.135
DIP    192.168.96.136
RS1    192.168.96.7
RS2    192.168.96.8

在real server上配置内核参数:先修改内核参数再在RS上配置VIP

~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
~]# echo 1 > /proc/sys/net/ipv4/conf/eth0/arp_ignore
~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
~]# echo 2 > /proc/sys/net/ipv4/conf/eth0/arp_announce

在RS上配置VIP:

~]# ifconfig lo:0 192.168.96.136/32 broadcast 192.168.96.136 up
~]# route add -host 192.168.96.136 dev lo:0  #限定目标地址为 192.168.96.136 的请求都要经过 lo:0

Director:

DIP   ens33    192.168.96.135
VIP   ens33:0  192.168.96.136
~]# ifconfig ens33:0 192.168.96.136/32 broadcast 192.168.96.136 up  #只广播给自己
~]# route add -host 192.168.96.136 dev ens33:0

此时可以测试请求两个web服务:

~]# curl http://192.168.96.7
<h1>RS7</h1>
~]# curl http://192.168.96.8
<h1>RS8</h1>

然后添加ipvs规则:

~]# ipvsadm -A -t 192.168.96.136:80 -s rr
~]# ipvsadm -a -t 192.168.96.136:80 -r 192.168.96.7 -g
~]# ipvsadm -a -t 192.168.96.136:80 -r 192.168.96.8 -g

这时访问VIP 192.168.96.136 即可看到负载均衡的效果了。


LVS-tun


        LVS-tun模型中客户端请求VIP,VIP在原来的请求报文基础上再封装一个IP首部,新首部中请求地址是DIP,目标地址是RIP,然后再通过层层路由到达RIP,Real Server拆掉报文后发现本机的lo接口上有VIP所以接受请求并响应,然后在通过lo接口转发到物理网卡通过互联网到达客户端。经过lo接口的目的是让响应请求的源地址为VIP,这样客户端才能响应请求。

IPIP.png

        lvs-tun类型的特性有:RIP、DIP、VIP全部都是公网地址,RS的网关不能只想DIP即请求报文经过调度器响应报文不能经过调度器;不支持端口映射;RS的OS必须支持隧道功能,即在原有IP上再封装一个IP首部报文的功能。


LVS-fullnat


        当需要主机不在同一个网络内且不想让RS在公网中,这时候就需要使用到lvs-fullnat模型了。fullnat和net模型的区别在于nat只是单边做nat,只是将目标地址做nat,fullnat是将请求地址和目标地址都做nat。这样director和Real Server可以不在同一个网络中;但是响应报文会经过调度器,并由调度器对响应报文做nat。

fullnat.png

        fullnat的特点:VIP是公网地址,RIP和DIP是私网地址二者无需在同一个网络中;支持端口映射,可以使用任意OS。


http stateless

session保持:

        session绑定:将来自于同一个用户的请求始终调度到同一个real server上。自行维护一个会话追踪表来追踪每一个请求的客户端,同时有一个倒计时的计时器,在倒计时结束之前这个IP的请求都会分发到这个服务器,这种机制叫做source ip hash 源地址hash机制;基于ip作为hash方式粒度过于粗糙,因为有很多上网方式是使用snat的的方式。所以就有了基于cookie的hash机制,不过lvs实现不了,nginx等应用层的服务可以实现。

        session集群:每一个real server都把自己的session同步给另外的主机一份,这样每一个real server都拥有全部的session,当其中一个主机宕机了其他的主机任然拥有全部的session。但是浪费带宽占用内存。

        session服务器:将session放在指定的服务器上,当real server需要session时就去session服务器上去找;但是会网络延迟需要集群等。


lsv scheduler


        lvs scheduler调度器算法,根据算法来挑选下一次要响应的服务器。

查看支持的调度算法:

grep -i -A 10 'IPVS' /boot/config-3.10.0-693.el7.x86_64

#
# IPVS scheduler
#
CONFIG_IP_VS_RR=m
CONFIG_IP_VS_WRR=m
CONFIG_IP_VS_LC=m
CONFIG_IP_VS_WLC=m
CONFIG_IP_VS_LBLC=m
CONFIG_IP_VS_LBLCR=m
CONFIG_IP_VS_DH=m
CONFIG_IP_VS_SH=m
CONFIG_IP_VS_SED=m
CONFIG_IP_VS_NQ=m

静态方法:仅根据算法本身调度。

        RR:round robin,论调

        WRR:weighted rr,加权伦调,设置权重,性能好的权重大。

        SH:source hash,源地址hash实现session保持;来自同一个用户的请求将被调度到同一个real server。

        DH:destination hash,不管哪一个请求,只要请求同一个东西就定位到同一个server上,用来提高缓存命中,根据请求的目标来决定RS。lvs不支持这样的功能,这个算法是在当RS为防火墙时,由于防火墙有连接追踪功能保证从哪进来要从哪出去。

动态方法:根据算法及各个RS的当前负载状态进行调度。

        LC:Least Connection 当前服务器哪一个负载比较小就调度哪一个。算法为Overhead = Active*256 + Inactive,计算结果较小的即为挑中的那台主机,Overhead为当前负载。

        WLC:Weighted LC 加权活动链接,Overhead = (Active * 256 + Inactive) / weight 。

        SED:Shortest Expect Delay 最短期望延迟,Overhead = (Active + 1) * 256 / weight 。

        NQ:Never Queue,当用户请求较少时按照权重大小分,一个服务至少分一个,分完后再根据SED算法往下分配。SED的算法改进。

        LBLC:Locality-Based LC,即为动态的DH算法。提高缓存命中率的算法,DH因为不考虑负载情况,所以在DH的基础上加入了负载情况,使其在某台服务负载高的情况下让新的请求到其他服务器上。

        LBLCR:在LBLC的基础上加入了可以从其他主机上复制内容到本台主机上的功能。如有两台服务器,第一台负载已近非常高了这时有新的请求过来,根据算法这个请求应该被分到第二台上,但是第二台服务器上没有要请求的内容所以要重新去远程取数据缓存到本地,为了避免远程请求直接从第一台服务器上去复制请求的内容。

ipvs的集群服务:

        tcp、udp、ah、esp、ah_esp、sctp

        一个ipvs主机可以同时存在多个集群服务。

        一个集群服务上至少有一个real server。

        定义时指明LVS的类型,以及lvs scheduler。


ipvsadm的用法

管理集群服务:

        ipvsadm -A|E -t|u|f service-address [-s scheduler]

                -A aappend

                -E edit

                service-address 集群服务地址:

                        tcp:-t    ip:port

                        udp:-u  ip:port

                        fwm:-f   mark    防火墙标记

                -s scheduler 指明调度器算法,默认为wlc算法

ipvsadm -A -t IP地址 -s wlc

删除集群:

        ipvsadm -D -t|u|f service-address

                -D delete

ipvsadm -D -t IP:PORT

管理集群服务中的RS:

        ipvsadm -a|e -t|u|f service-address -r server-address [-g|i|m] [-w weight] [-x upper] [-y lower]

                server-address 指定RS服务器地址

                        ip[:port]

                lvs-type:

                        -g:gateway,dr 默认

                        -i: ipip,tun

                        -m:masquerade,nat

ipvsadm -A -t IP地址 -s 调度算法 -r RS服务器 -g 调度模型

删除某个RS主机:

        ipvsadm -d -t|u|f service-address -r server-address

ipvsadm -d -t IP:PORT -r IP:PORT

清理规则:

        ipvsadm -C

查看信息:

        ipvsadm -L|l [options]

                -n: numeric 基于数字格式显示地址和端口

ipvsadm -L -n

                -c:connection 显示当前的连接

ipvsadm -L -c

                --stats:统计数据

ipvsadm -L -n --stats

                --rate:统计速率

ipvsadm -L -n --rate

                --sort:排序

                --exact:显示精确值,不做单位换算

保存和重载:

       ipvsadm -S [-n]

ipvsadm -S > /etc/sysconfig/ipvsadm

       ipvsadm -R

ipvsadm -R < /etc/sysconfig/ipvsadm

置零计数器:

        ipvsadm -Z [-t|u|f service-address]