LVS(2)之调度算法介绍及使用ipvsadm构建集群实例

LVS(2)之调度算法介绍及使用ipvsadm构建集群实例

微信搜索 zze_coding 或扫描 👉 二维码关注我的微信公众号获取更多资源推送:

调度算法介绍

LVS 有两种类型的调度算法,其一就是静态的调度算法,这种算法一经实现,后续就不会发生变化,是既定的规则,后续数据包的流转都会按照这种规则进行按部就班的流转;其二就是动态的调度算法,这种算法是基于网络状况,或者后端服务器的状况,连接的状况等来进行实时的调整,算法的规则会根据实际情况而发生一定的变化。

静态调度算法

常用的静态调度算法有以下几种:

  • RR:轮叫调度(Round Robin)
    调度器通过”轮叫”调度算法将外部请求按顺序轮流分配到集群中的真实服务器上,它均等地对待每一台服务器,而不管服务器上实际的连接数和系统负载。

  • WRR:加权轮叫(Weight RR)
    调度器通过“加权轮叫”调度算法根据真实服务器的不同处理能力来调度访问请求。这样可以保证处理能力强的服务器处理更多的访问流量。

  • DH:目标地址散列调度(Destination Hash )
    根据请求的目标 IP 地址,作为散列键(HashKey)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器。

  • SH:源地址 hash(Source Hash)
    源地址散列”调度算法根据请求的源 IP 地址,作为散列键(HashKey)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器。

动态调度算法

  • LC:最少连接(Least Connections)
    Overhead = Active * 256,调度器通过”最少连接”调度算法动态地将网络请求调度到已建立的链接数最少的服务器上。如果集群系统的真实服务器具有相近的系统性能,采用”最小连接”调度算法可以较好地均衡负载。

  • WLC:加权最少连接(Weighted Least Connections)
    Overhead = (Active * 256) / weight,在集群系统中的服务器性能差异较大的情况下,调度器采用“加权最少链接”调度算法优化负载均衡性能,具有较高权值的服务器将承受较大比例的活动连接负载。调度器可以自动问询真实服务器的负载情况,并动态地调整其权值。

  • SED:最短延迟调度(Shortest Expected Delay)
    Overhead = (Active + 1) * 256 / weight,在 WLC 基础上改进,不考虑非活动状态,Overhead 最小的,接受下次请求。

  • NQ:永不排队/最少队列调度(Never Queue Scheduling NQ)
    无需队列。在遍历 RS 列表时,首先选择还没有任何活动连接的真实服务器。否则,选择负荷最小的真实服务器,每个真实服务器负荷的计算与 SED 调度器相同。

  • LBLC:基于本地最少连接数(Locality-Based Least-Connection)
    LBLC 算法是基于 LC 算法的一个变种,其实是一种动态的 DH 算法,它会对 LC 算法调度的目的服务器进行缓存,对于后续的连接如果其目的 IP 可在缓存中找到目的服务器,使用其处理新连接。

  • LBLCR:带复制的 LBLC(Locality-based Least-Connection with Replication)
    基于 LBLC 算法添加了缓存复制的功能,当两台服务器负载差距过于悬殊时,低负载的服务器会从高负载的服务器复制一部分目的缓存数据,后续此部分目的的连接将会请求到低负载的服务器。

ipvsadm 使用

ipvsadm 的使用情形分两类:

  • 一是管理集群服务;
  • 二是管理集群服务中的 RS;

首先我们需要定义出来的哪个协议的哪个端口用来代理集群服务,再对这个集群服务中的 RS 进行管理,每一类服务及服务中的 RS 都可进行增删查改操作。

其有如下特点:

  • 一个 ipvs 主机可以同时定义多个 cluster service;
  • 一个 cluster service 上至少有一个 real server;

定义时,要指明集群的 lvs-type(类型)以及 lvs scheduler(调度器)。

前面有说过 LVS 已经是标准内核的一部分,所以我们无需安装它,所以我们仅需要安装它的管理工具 ipvsadmin,使用 yum 安装即可:

$ yum install ipvsadm -y

那下面说一下 ipvsadm 命令常用的使用规则吧~~

管理集群服务:
	>: 下面 service-address 表示集群服务的地址。
	增加和修改:
		ipvsadm -A|E -t|u|f service-address [-s scheduler]
			-A:增加;
			-E:修改;
			-t service-address:基于 tcp 协议,此时 service-address 为 ip:port;
			-u service-address:基于 udp 协议,此时 service-address 为 ip:port;
			-f service-address:基于 fwm(防火墙标记),此时 service-address 为一个数字,-f mark;
			-s scheduler:指明调度算法,可选值参见文章开头的「调度算法介绍」,默认值为 wlc;
	删除:
		ipvsadm -D -t|u|f service-address
			-D:删除;
			-t|u|f:同增加和修改;

管理集群服务中的 RS:
	>: 这里的 service-address 一定是已定义的,这里的重点是 server-address,它表示集群服务中 RS 的地址。
	增加和修改:
		ipvsadm -a|e -t|u|f service-address -r server-address
               		[-g|i|m] [-w weight] [-x upper] [-y lower]
			-a:增加;
			-e:修改;
			-r server-address:指明 RS 的地址,格式为 -r ip[:port];
			-g:gateway,dr 模型,也是默认值;
			-i:ipip,tun 模型;
			-m:masquerade,nat;
			
	删除:
		ipvsadm -d -t|u|f service-address -r server-address

管理集群服务或集群服务中的 RS(通用):
	清空:
		ipvsadm -C
	查询:
		ipvsadm -L|l [options]
			-n:基于数字格式显示地址和端口;
			-c:显示当前已建立的 IPVS 连接;
			--stats:显示统计数据;
			--rate:显示速率统计数据;
			--exact:显示精确值,不做单位换算;
重载:
	ipvsadm -R
保存:
	ipvsadm -S [-n]
置零计数器:
	ipvsadm -Z [-t|u|f service-address]

下面直接来构建实例演示一下 ipvsadm 命令的使用~~

构建集群实例

开始之前要确保几个主机中是不存在 iptables 规则的。

lvs-nat

首先需准备如下图三台测试主机:

image.png

其地址规划如图:

  • Director 的 VIP 为 10.0.1.200,内网地址 DIP 为 172.16.1.200
  • RS1 的内网地址 RIP 为 172.16.1.201
  • RS2 的内网地址 RIP 为 172.16.1.202

1、给 Director 主机开启核心转发:

$ sysctl -w net.ipv4.ip_forward=1

2、设定 RS1 和 RS2 的默认网关为 Director 的内网地址 172.16.1.200

$ ip route add default via 172.16.1.200
$ route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.16.1.200    0.0.0.0         UG    0      0        0 eth0

3、配置 RS1 和 RS2 的 Web 服务,测试使用 Director 访问 RS1 和 RS2:

$ curl 172.16.1.201
<h1>test page on node2.zze.xyz</h1>
$ curl 172.16.1.202
<h1>test page on node3.zze.xyz</h1>

这里的 Web 服务就随便使用 httpd 或者 Nginx 啦,返回的内容能区分是不同 RS 返回即可。

4、添加使用 rr 算法的集群服务以及集群服务中的 RS:

$ ipvsadm -A -t 10.0.1.200:80 -s rr
$ ipvsadm -a -t 10.0.1.200:80 -r 172.16.1.201:80 -m
$ ipvsadm -a -t 10.0.1.200:80 -r 172.16.1.202:80 -m 

5、测试使用浏览器访问 Director:
lvs-nat-test1

可以看到负载均衡的效果已经实现啦,并且是基于 lvs-nat 的 rr 轮询算法~~~

lvs-dr

这里假设 VIP、DIP 以及 RIP 都在同一个网段,规划主机如下:

image.png

说明:

  • Director 和 RS 都处于同一个网络并且指向同一个网关;
  • Director 的 VIP 以别名形式配置在它的 eth0 接口上;
  • RS 的 VIP 以别名形式配置在它的 lo 接口上;

做下面操作之前需要同 lvs-nat 实例中启动 RS 的 Web 服务哦。

1、配置 Director 的 VIP:

$ ifconfig eth0:0 10.0.1.199/32 broadcast 10.0.1.199 up

VIP 仅作为 Director 被请求的目标地址,所以掩码给 32 位即可;
broadcast 10.0.1.199 设定只给自己广播,此项可选,目的是不主动干预网关的路由表;

2、设定两个 RS 的内核参数:

$ 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

关于这两个参数的使用说明可参考:『Linux内核参数之arp_ignore和arp_announce』。

3、给两个 RS 的本机回环接口上配置上 VIP:

$ ifconfig lo:0 10.0.1.199/32 broadcast 10.0.1.199 up
$ route add -host 10.0.1.199 dev lo:0

第二条路由配置可选,目的是让 10.0.1.199 作为本地回环地址使用,而不去请求外部主机;。

4、在客户端主机(宿主机)上 ping 一下 VIP,然后查看一下 ARP 表:

$ ping 10.0.1.199
PING 10.0.1.199 (10.0.1.199): 56 data bytes
64 bytes from 10.0.1.199: icmp_seq=0 ttl=64 time=0.405 ms
64 bytes from 10.0.1.199: icmp_seq=1 ttl=64 time=0.491 ms
^C
$ arp -a
? (10.0.1.199) at 0:c:29:ec:96:39 on vmnet2 ifscope [ethernet]
? (10.0.1.200) at 0:c:29:ec:96:39 on vmnet2 ifscope [ethernet]

可以看到给我们响应的 10.0.1.199 对应的 MAC 地址的确是 Director 主机,即两个配置了同样 VIP 的 RS 没有响应,说明我们给 RS 配置的内核参数是生效的。

5、添加 IPVS 规则:

 $ ipvsadm -A -t 10.0.1.199:80 -s rr
 $ ipvsadm -a -t 10.0.1.199:80 -r 10.0.1.201 -g
 $ ipvsadm -a -t 10.0.1.199:80 -r 10.0.1.202 -g

6、测试使用浏览器访问 VIP:

2020-03-19 18.17.22

可以看到负载均衡的效果已经实现啦,并且是基于 lvs-dr 的 rr 轮询算法~~~

其它操作

修改与删除规则

这里就以 lvs-nat 实例为基础演示一下集群服务以及集群服务中的 RS 的规则的修改与删除操作。

如果我们需要修改集群服务的调度算法为 sh,则可以使用 -E 选项了,如下:

$ ipvsadm -E -t 10.0.1.200:80 -s sh

我们已经知道 sh 算法是基于源地址哈希,所以我们现在使用同一个主机的浏览器访问 Director 肯定是一直返回同一个 RS 的页面,这里我就不做演示啦。

同理,如果我们需要修改集群服务中的 RS 的规则,则需要使用 -e 选项,下面以修改集群服务中 RS 的映射端口为 8080 为例:

$ ipvsadm -e -t 10.0.1.200:80 -r 172.16.1.201:8080 -m
$ ipvsadm -e -t 10.0.1.200:80 -r 172.16.1.202:8080 -m

我这里不知道为啥一直报错:Memory allocation problem。。。如果你也和我一样,那就直接修改 /etc/sysconfig/ipvsadm 然后恢复,或者删了重新添加规则。

如果我们需要删除集群服务中的 RS2 则可使用 -d 选项,执行下面命令即可:

$ ipvsadm -d -t 10.0.1.200:80 -r 172.16.1.202:8080

如果要直接删除集群服务,使用 -D 选项即可,如下:

$ ipvsadm -D -t 10.0.1.200:80

保存与重载规则

执行 systemctl stop ipvsadm 时 ipvsadm 默认保存规则到 /etc/sysconfig/ipvsadm
而执行 systemctl start ipvsadm 时 ipvsadm 默认会从 /etc/sysconfig/ipvsadm 中恢复规则。

它们执行的命令可以在 /usr/lib/systemd/system/ipvsadm.service 中看到:

$ cat /usr/lib/systemd/system/ipvsadm.service                     
[Unit]
Description=Initialise the Linux Virtual Server
After=syslog.target network.target

[Service]
Type=oneshot
ExecStart=/bin/bash -c "exec /sbin/ipvsadm-restore < /etc/sysconfig/ipvsadm"
ExecStop=/bin/bash -c "exec /sbin/ipvsadm-save -n > /etc/sysconfig/ipvsadm"
ExecStop=/sbin/ipvsadm -C
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

当然我们也可以手动执行保存或重载操作。

下面命令用来保存当前规则到 /etc/sysconfig/ipvsadm

$ ipvsadm-save -n > /etc/sysconfig/ipvsadm
$ ipvsadm -S -n > /etc/sysconfig/ipvsadm

下面命令用来从 /etc/sysconfig/ipvsadm 中恢复规则:

$ ipvsadm-restore < /etc/sysconfig/ipvsadm
$ ipvsadm -R < /etc/sysconfig/ipvsadm

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可

Links: https://www.zze.xyz/archives/lvs2.html

Buy me a cup of coffee ☕.