调度算法:http://linuxvirtualserver.org/docs/scheduling.html
十种:
轮叫调度rr
加权轮叫调度wrr
最小链接调度lc
加权最小链接调度wlc
基于局部的最少链接 lblc
带复制的基于局部的最少链接 lblcr
目标地址散列调度 dh
源地址散列调度 sh
最短预期延时调度 sed
不排队调度 nq
静态调度:rr wrr dh sh
动态调度:lc wlc lblc lblcr sed nq
在各种调度算法中,LVS的ipvs默认使用的是WLC。这种算法在大量请求时的性能是最理想的,但是一般如果要实现粘性session,则一般使用SH算法。
按依次循环的方式将请求调度到不同的服务器上,该算法最大的特点就是简单。轮询算法假设所有的服务器处理请求的能力都是一样的,调度器会将所有的请求平均分配给每个真实服务器,不管后端 RS 配置和处理能力,非常均衡地分发下去。
i = (i + 1) mod n
流程
j = i;
do {
j = (j + 1) mod n;
if (W(Sj) > 0) {
i = j;
return Si;
}
} while (j != i);
return NULL;
这种算法比 rr 的算法多了一个权重的概念,可以给 RS 设置权重,权重越高,那么分发的请求数越多,权重的取值范围 0 – 100。主要是对rr算法的一种优化和补充, LVS 会考虑每台服务器的性能,并给每台服务器添加要给权值,如果服务器A的权值为1,服务器B的权值为2,则调度到服务器B的请求会是服务器A的2倍。权值越高的服务器,处理的请求越多。
流程
while (true) {
i = (i + 1) mod n;
if (i == 0) {
cw = cw - gcd(S);
if (cw <= 0) {
cw = max(S);
if (cw == 0)
return NULL;
}
}
if (W(Si) >= cw)
return Si;
}
这个算法会根据后端 RS 的连接数来决定把请求分发给谁,比如 RS1 连接数比 RS2 连接数少,那么请求就优先发给 RS1
流程
for (m = 0; m < n; m++) {
if (W(Sm) > 0) {
for (i = m+1; i < n; i++) {
if (W(Si) <= 0)
continue;
if (C(Si) < C(Sm))
m = i;
}
return Sm;
}
}
return NULL;
当各个服务器有相同的处理性能时,最小连接调度算法能把负载变化大的请求分布平滑到各个服务器上,所有处理时间比较长的请求不可能被发送到同一台服务器上。但是,当各个服务器的处理能力不同时,该算法并不理想,因为 TCP 连接处理请求后会进入 TIME_WAIT 状态,TCP 的 TIME_WAIT 一般为 2 分钟,此时连接还占用服务器的资源,所以会出现这样情形,性能高的服务器已处理所收到的连接,连接处于 TIME_WAIT状态,而性能低的服务器已经忙于处理所收到的连接,还不断地收到新的连接请求。
这个算法比 lc 多了一个权重的概念。
流程
for (m = 0; m < n; m++) {
if (W(Sm) > 0) {
for (i = m+1; i < n; i++) {
if (C(Sm)*W(Si) > C(Si)*W(Sm))
m = i;
}
return Sm;
}
}
return NULL;
这个算法是请求数据包的目标 IP 地址的一种调度算法,该算法先根据请求的目标 IP 地址寻找最近的该目标 IP 地址所有使用的服务器,如果这台服务器依然可用,并且有能力处理该请求,调度器会尽量选择相同的服务器,否则会继续选择其它可行的服务器
目前主要用于 Cache 集群系统
流程
if (ServerNode[dest_ip] is NULL) then {
n = WLC(S);
if (n is NULL) then return NULL;
ServerNode[dest_ip].server = n;
} else {
n = ServerNode[dest_ip].server;
if ((n is dead) OR (C(n) > W(n) AND
there is a node m with C(m) < W(m)/2))) then {
n = WLC(S);
if (n is NULL) then return NULL;
ServerNode[dest_ip].server = n;
}
}
ServerNode[dest_ip].lastuse = Now;
return n;
此外,对关联变量 ServerNode[dest_ip]要进行周期性的垃圾回收(Garbage Collection),将过期的目标 IP地址到服务器关联项进行回收。过期的关联项是指哪些当前时间(实现时采用系统时钟节拍数 jiffies)减去最近使用时间超过设定过期时间的关联项,系统缺省的设定过期时间为 24 小时。
记录的不是要给目标 IP 与一台服务器之间的连接记录,它会维护一个目标 IP 到一组服务器之间的映射关系,防止单点服务器负载过高。
流程
if (ServerSet[dest_ip] is NULL) then {
n = WLC(S);
if (n is NULL) then return NULL;
add n into ServerSet[dest_ip];
} else {
n = WLC(ServerSet[dest_ip]);
if ((n is NULL) OR (n is dead) OR (C(n) > W(n) AND
there is a node m with C(m) < W(m)/2))) then {
n = WLC(S);
if (n is NULL) then return NULL;
add n into ServerSet[dest_ip];
} else
if (|ServerSet[dest_ip]| > 1 AND
Now - ServerSet[dest_ip].lastmod > T) then {
m = WGC(ServerSet[dest_ip]);
remove m from ServerSet[dest_ip];
}
}
ServerSet[dest_ip].lastuse = Now;
if (ServerSet[dest_ip] changed) then
ServerSet[dest_ip].lastmod = Now;
return n;
目标地址散列调度算法先根据请求的目标 IP 地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。
该算法是根据目标 IP 地址通过散列函数将目标 IP 与服务器建立映射关系,出现服务器不可用或负载过高的情况下,发往该目标 IP 的请求会固定发给该服务器。
流程
n = ServerNode[hashkey(dest_ip)];
if ((n is dead) OR (W(n) == 0) OR (C(n) > 2*W(n))) then
return NULL;
return n;
与目标地址散列调度算法类似,但它是根据源地址散列算法进行静态分配固定的服务器资源。
希望在请求少的时候将请求尽可能转发到性能高的服务器上,sed这种调度算法为了解决WLC的缺点而生,它不再考虑非活动连接。
sed这种算法也有一定缺陷,在请求量比较少的时候,某个权重下的节点可能一个请求都没有轮到,而权重大的节点却轮到了比较多的请求。
(活动连接数+1)*256/权重
当有空闲服务器可用时,作业将被发送到空闲服务器,而不是等待快速的服务器。当没有可用的空闲服务器时,作业将被发送到服务器,以最小化其预期延迟(最短预期延迟调度算法)。
这种算法在请求量比较小的时候可以避免sed算法存在的问题,也就是会将请求在sed的结果上进行轮询调度。例如sed算法的结果当前已经
将请求有转发到A、B节点,新的请求又被计算到A节点,此时如果有C节点,则NQ算法会将这个新的请求调度到C节点而不是继续调度到A节点而
不会理会此时A的权重问题,权重的判断仅仅在sed算法这个步骤进行考虑。也就是NQ算法在sed算法的结果之后增加了轮询的机制(也会考虑一定程度的权重),
因此这种算法就会尽量不然请求出现排队的情况,即避免了某个节点非常繁忙而其他节点相对空闲的情况。避免了权重小的节点不会出现没有请求被调度的情况。
wrr
wlc
lblc
lblcr
sh