LVS集群的负载调度算法

时间:2022-10-04 09:53:04

参考文章出处:http://tech.ccidnet.com/art/302/20050609/265435_1.html

注:LVS -- Linux Virtual Server ( 可以实现Linux平台下简单的负载均衡 )

 

1.  内核中的连接调度算法

    在内核中的连接调度算法上,IPVS已实现了一下八种调度算法:

    轮叫调度(Round-Robin Scheduling)

    加权轮叫调度(Weighted Round-Robin Scheduling)

    最小连接调度(Last-Connection Scheduling)

    加权最小连接调度(Weighted Last-Connection Scheduling)

    基于局部性的最小连接(Locality-Based Least Connection Scheduling)

    带复制的基于局部性最小连接(Locality-Based Least Connection with Replication Scheduling)

    目标地址散列调度(Destination Hashing Scheduling)

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

 

1.1.  轮叫调度

    轮叫调度(Round-Robin Scheduling)算法就是以轮叫的方式依次将请求调度不同的服务器,即每次调度执行 i = ( i+1) mod n,并选出第 i 台服务器。算法的优点是其简洁性,它无需记录当前所有的连接状态,所以它是一种无状态调度

    在系统实现时,我们引入了一个额外条件,当服务器的权值为零时,表示该服务器不可用而不被调度。这样做的目的是将服务器切出服务(如屏蔽服务器故障和系统维护),同时与其他加权算法保持一致。所以,算法要做相应的改动,它的算法流程如下:

    假设有一组服务器S = {S0, S1,  ... , Sn-1},一个指示变量i表示上一次选择的服务器,W(Si) 表示服务器Si的权值。变量i被初始化为n-1,其中n>0。

 

   j = i;

do{

j = ( j+1 ) mod n;

if( W(Sj) > 0 ){

i = j;

return Si;

}

} while( j != i );

return NULL;

    轮叫调度算法假设所有服务器处理性能均相同,不管服务器的当前连接数和响应速度。该算法相对简单,不适用于服务器中处理性能不一的情况,而且当请求服务时间变化比较大时,轮叫调度算法容易导致服务器间的负载不平衡。

    虽然Round-Robin DNS方法也是以轮叫调度的方式将一个域名解析到多个IP地址,但轮叫DNS方法的调度粒度是基于每个域名服务器的,域名服务器对域名解析的缓存会妨碍轮叫解析域名生效,这会导致服务器间负载的严重不平和。这里,IPVS轮叫调度算法的粒度是基于每个连接的,同一用户的不同连接都会被调度到不同的服务器上,所以这种细粒度的轮叫调度要比DNS轮叫调度优越很多。

 

1.2.  加权轮叫调度

    加权轮叫调度(Weighted Round-Robin Scheduling)算法可以解决服务器间性能不一的情况,它用相应的权值表示服务器的处理性能,服务器的缺省权值为1。假设服务器A的权值为1,B的权值为2,则表示服务器B的处理性能是A的两倍。加权轮叫调度算法是按权值的高低和轮叫方式分配请求到各服务器。权值高的服务器先收到连接,权值高的服务器比权值低的服务器处理更多的连接,相同权值的服务器处理相同数目的连接。加权轮叫调度算法流程如下:

    假设有一组服务器S = {S0, S1,  ... , Sn-1},W(Si) 表示服务器Si的权值,一个指示变量i表示上一次选择的服务器,指示变量cw表示当前调度的权值,max(S)表示集合S中所有服务器的最大权值,gcd(S)表示集合S中所有服务器权值的最大公约数。变量i被初始化为-1,变量cw最初被初始化为零。

while(true){

i = ( i+1 ) mod n;
if( i==0 ){
cw = cw - gcd(S);
if( cw<=0 ){
cw = max(S);
if( cw==0 ) // (max(S)==0)
return NULL;
}
}

if( W(Si) >= cw )
return Si;
}

 (注:开始执行调度时,首先返回权值最高的一台或几台服务器(cw=max(s)),一次遍历之后将返回所有权值最高的服务器,并且重新开始遍历(i=0),同时将当前权值降低一个档次(cw=cw-gcd(S)),返回权值最高和次高的若干台服务器 ... ,最终可以保证服务器被选中的频率与其权值成正比(gcd(S)的作用)。例如,测试中使用权值W[Si]={3, 4, 2, 1},调度结果返回1,0, 1, 0, 1, 2,0, 1, 2, 3 ...(重复循环,不同颜色代表了一次遍历能取出的服务器))

    例如,有三个服务器A、B和C分别有权值4、3和2,则在一个调度周期内(mod sum(W(Si)))调度序列为AABABCABC(权值之和为9,所以以9为周期)。加权轮叫调度算法还是比较简单和高效。当请求的服务时间变化很大,单独的加权轮叫调度算法依然会导致服务器间的负载不平衡。

    从上面的算法流程中,我们可以看出当服务器的权值为零时,该服务器不被调度;当所有服务器的权值为零,即对于任意i有W(Si)=0,则没有任何服务器可用,算法返回NULL,所有新的连接都会被丢掉。加权轮叫调度也无需记录当前所有连接的状态,所以它也是一种无状态调度

 

1.3.  最小连接调度

    最小连接调度(Least-Connection Scheduling)算法是把新的连接请求分配到当前连接数最小的服务器。最小连接调度是一种动态调度算法,它通过服务器当前所活跃的连接数来估计服务器的负载情况。调度器需要记录各个服务器已建立连接的数目,当一个请求被调度到某台服务器,其连接数加1;当连接终止或超时,其连接数减一。

    在系统实现中,我们也引入当服务器的权值为零时,表示该服务器不可用而不被调度,它的算法流程如下:

    假设有一组服务器S = {S0, S1,  ... , Sn-1},W(Si) 表示服务器Si的权值,C(Si)表示服务器Si的当前连接数。

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;

 (注:该算法每次从0开始,遍历寻找当前连接数最小的服务器并返回)

    当各个服务器有相同的处理性能时,最小连接调度算法能把负载变化大的请求分布平滑到各个服务器上,所有处理时间比较长的请求不可能被发送到同一台服务器上。但是,当各个服务器的处理能力不同时,该算法并不理想,因为TCP连接处理请求后会进入TIME_WAIT状态,TCP的TIME_WAIT状态一般为2分钟,此时连接还占用服务器的资源,所以会出现这样的情形,性能高的服务器已处理所收到的连接,连接处于TIME_WAIT状态,而性能低的服务器已经忙于处理所收到的连接,还不断地收到新的连接请求。

 

1.4.  加权最小连接调度

    加权最小连接调度(Weighted Least-Connection Scheduling)算法是最小连接调度的超集,各个服务器用相应的权值表示其处理性能。服务器的缺省权值为1,系统管理员可以动态地设置服务器的权值。加权最小连接调度在调度新连接时尽可能使服务器的已建立连接数和其权值成比例。加权最小连接调度算法流程如下:

    假设有一组服务器S = {S0, S1,  ... , Sn-1},W(Si) 表示服务器Si的权值,C(Si)表示服务器Si的当前连接数。所有服务器当前连接数的总和为CSUM = sum C(Si) (i = 0, 1, ... n-1)。当前的新连接请求会被发送服务器Sm,

    当且仅当服务器Sm满足一下条件

    ( C(Sm) / CSUM ) / W(Sm) = min { ( C(Sm) / CSUM ) / W(Sm) } ( i = 0, 1, ... , n-1),其中W(Si)不为零

  (注:相当于性价比最高)

    因为CSUM在这一轮查找中是个常数,所以判断条件可以简化为

    C(Sm) / W(Sm) = min { C(Si) / W(Si) }  ( i = 0, 1, ... n-1),其中W(Si)不为零

    因为除法运算所需的CPU周期比乘法多,且在Linux内核不允许浮点除法,服务器的权值都大于零,所以判断条件C(Sm) / W(Sm) > C(Si) / W(Si)可以进一步优化为C(Sm) * W(Si) > C(Si) * W(Sm),同时保证服务器的权值为零时,服务器不被调度。所以,算法只要执行以下流程。

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;


1.5.  基于局部性的最小连接调度

    基于局部性的最小连接调度(Locality-Based Least Connection Scheduling,以下简称为LBLC)算法是针对请求报文的目标IP地址的负载均衡调度,目前主要用于Cache集群系统,因为在Cache集群中客户请求报文的目标IP地址是变化的。这里假设任何后端服务器都可以处理任一请求,算法的设计目标是在服务器的负载基本平衡的情况下,将相同目标IP地址的请求调度到同一台服务器,来提高各个服务器的访问局部性和主存Cache命中率,从而提高整个集群系统的处理能力。

    LBLC调度算法先根据请求目标IP地址找出该目标IP地址最近使用的服务器,若该服务器是可用的且没有超载,将请求发送到服务器;若服务器不存在,或者该服务器超载且有服务器处于其一半的工作负载,则用“最少连接”的原则选出一个可用的服务器,将请求发送到该服务器。该算法的详细流程如下:

    假设有一组服务器S = {S0, S1,  ... , Sn-1},W(Si) 表示服务器Si的权值,C(Si)表示服务器Si的当前连接数。ServerNode[dest_ip]是一个关联变量,表示目标IP地址所对应的服务器结点,一般来说它是通过Hash表实现的。WLC(S)表示在集合S中的加权最小连接服务器,即前面的最小加权连接调度。Now为当前系统时间。

if( ServerNode[dest_ip] is NULL ) then{ // 该目的IP节点不存在

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 = WLS(n);
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小时。

 

1.6.  带复制的基于局部性最小连接调度

    带复制的基于局部性最少连接调度(Locality-Based Least Connection with Replication Scheduling,以下简称为LBLCR)算法也是针对目标IP地址的负载均衡,目前主要用于Cache集群系统。它与LBLC算法的不同指出是它要维护一个从目标IP地址到一组服务器的映射,而LBLC算法维护从一个目标IP地址到一台服务器的映射。对于一个“热门”站点的服务请求,一台Cache服务器可能会忙不过来处理这些请求。这时,LBLC调度算法会从所有的Cache服务器中按“最小连接”原则选出一台Cache服务器,映射该“热门”站点到这台Cahce服务器,很快这台Cache服务器也会超载,就会重复上述过程选出新的Cache服务器。这样,可能会导致该“热门”站点映射到一组Cache服务器(服务器集合),当该“热门”站点的请求负载增加时,会增加集合里的Cache服务器,来处理不断增长的负载;当该“热门”站点的请求负载降低时,会减少即合理的Cache服务器数目。这样,该“热门”站点的映像不太可能出现在所有的Cache服务器上,从而提高Cache集群系统的使用效率。

    LBLCR算法先根据请求的目标IP地址找出该目标IP地址对应的服务器组,按“最小连接”原则从该服务器组中选出一台服务器,若服务器没有超载,将请求发送到该服务器;若服务器超载,则按“最小连接”原则从整个集群中选出一台服务器,将该服务器加入到服务器组中,将请求发送到该服务器。同时,当该服务器组中有一段时间没有被修改,将最忙的服务器从服务器组中删除,以降低复制的程度。LBLCR调度算法的流程如下:

    假设有一组服务器S = {S0, S1,  ... , Sn-1},W(Si) 表示服务器Si的权值,C(Si)表示服务器Si的当前连接数。ServerSet[dest_ip]是一个关联变量,表示目标IP地址所对应的服务器集合,一般来说它是通过Hash表实现的。WLC(S)表示在集合S中的加权最小连接服务器,即前面的加权最小连接调度;WGC(S)表示在集合S中的加权最大连接服务器。Now为当前系统时间,lastmod表示集合的最近修改时间,T为对集合进行调整的设定时间。

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;

    此外,对关联变量ServerSet[dest_ip]也要进行周期性的垃圾回收(Garbage Collection),将过期的目标IP地址到服务器关联项进行回收。过期的关联项是指那些当前时间(实现时采用系统时钟节拍数jiffies)减去最近使用时间(lastuse)超过设定过期时间的关联项,系统缺省的设定过期时间为24小时。

 

1.7.  目标地址散列调度

    目标地址散列调度(Destination Hashing Scheduling)算法也是针对目标IP地址的负载均衡,但它是一种静态映射算法,通过一个散列(Hash)函数将一个目标地址映射到一台服务器。

    目标地址散列调度算法先根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。该算法的流程如下:

    假设有一组服务器S = {S0, S1,  ... , Sn-1},W(Si) 表示服务器Si的权值,C(Si)表示服务器Si的当前连接数。ServerNode[]是一个有256个桶(Bucket)的Hash表,一般来说服务器的数目会远小于256,当然表的大小也是可以调整的。算法的初始化是将所有服务器顺序、循环地放置到ServerNode中。若服务器的连接数目大于2倍的权值,则表示服务器已超载。

n = ServerNode[hashkey(dest_ip)];
if( (n is dead) OR (W(n)==0) OR ( C(n)>2*W(n) ) ) then
return NULL;
return n;

    在实现时,我们采用素数乘法Hash函数,通过乘以素数使得散列键值尽可能地达到较均匀的分布。所采用的素数乘法Hash函数如下:

static inline unsigned hashkey( unsigned int dest_ip ){

return (dest_ip*2654435761UL) & HASH_TAB_MASK;

}

    其中,2654435761UL是2到2^32(4294967296)间接近于黄金分割的素数,

    ( sqrt(5) - 1 ) / 2 = 0.618033989

    2654435761 / 4294967296 = 0.618033987

 

1.8.  源地址散列调度

    源地址散列调度(Source Hashing Scheduling)算法正好与目标地址散列调度算法相反,它根据请求的源IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。它采用的散列函数与目标地址散列调度算法的相同。它的算法流程与目标地址散列调度算法基本相似,除了将请求的目标IP地址换成请求的源IP地址,所以这里不一一叙述。

    在实际应用中,源地址散列调度和目标地址散列调度可以结合使用在防火墙集群中,它们可以保证整个系统的唯一出入口。


2.  动态反馈负载均衡算法

    动态反馈负载均衡算法考虑服务器的实时负载和响应情况,不断调整服务器间处理请求的比例,来避免有些服务器超载时依然收到大量请求,从而提高整个系统的吞吐率。下图显示了该算法的工作环境,在负载调度器上运行Monitor Daemon进程,Monitor Daemon来监视和收集各个服务器的负载信息。Monitor Daemon可根据多个负载信息算出一个综合负载值。Monitor Daemon将各个服务的综合负载值和当前权值算出一组新的权值,若新权值和当前权值的差值大于设定的阀值,Monitor Daemon将该服务器的权值设置到内核中的IPVS调度中,而在内核中连接调度一般采用加权轮叫调度算法或者加权最小连接调度算法。

 

 

 LVS集群的负载调度算法

2.1.  连接调度

    当客户通过TCP连接访问网络访问时,服务器所需的时间和所要消耗的计算资源是千差万别的,它依赖于很多因素。例如,它依赖于轻轻的服务类型、当前网络带宽的情况、以及当前服务器资源利用的情况。一些负载比较重的请求需要进行计算密集的查询、数据库的访问、很长响应数据流;而负载比较轻的请求往往只需要读一个HTML页面或者进行很简单的计算。

    请求处理时间的千差万别可能会导致服务器利用的倾斜(Skew),即服务器间的负载不平衡。例如,有一个WEB页面有A、B、C和D文件,其中D文件是大图像文件,浏览器需要建立四个连接来读取这些文件。当多个用户通过浏览器同时访问该页面时,最极端的情况是所有D文件的请求被发到同一台服务器。所以说,有可能存在这样情况,有些服务器已经超负荷运行,而其他服务器基本是闲置着。同时,有些服务器已经忙不过来,有很长的请求队列,还不断的收到新的请求。反过来,这会导致客户长时间的等待,觉得系统的服务质量差。

2.1.1  简单连接调度

    简单连接调度可能会使得服务器倾斜的发生。在上面的例子中,若采用轮叫调度算法,且集群中正好有四台服务器,必须有一台服务器总是收到D文件的请求。这种调度策略会导致系统资源的低利用率,因为有些资源被用尽导致客户长时间的等待,而其他资源空闲着。

2.1.2  实际TCP/IP流量的特征

    文献[1]说明网络流量是呈波浪型发生的,在一段较长时间的小流量后,会有一段大流量的访问,然后是小流量,这样跟波浪一样周期性地发生。文献[2、3、4、5]揭示在WAN和LAN上网络流量存在自相似的特征,在WEB访问流也存在自相似性。这就需要一个动态反馈机制,利用服务器组的状态来应对访问流的自相似性。

2.1.3  动态反馈负载均衡机制

    TCP/IP流量的特征通俗的说是由许多短事务和一些长事务组成,而长事务的工作量在整个工作量中占有较高的比例。所以,我们要设计一种负载均衡算法,来避免长事务的请求总被分配到一些机器上,而是尽可能将带有毛刺(Burst)的分布分割成相对较均匀的分布。

    我们提出基于动态反馈负载均衡机制,来控制新连接的分配,从而控制各个服务器的负载。例如,在IPVS调度器的内核中使用加权轮叫调度(Weighted Round-Robin Scheduling)算法来调度新的请求连接;在负载调度器的用户空间中运行Monitor Daemon。Monitor Daemon定时地监视和收集各个服务器的负载信息,根据多个负载信息算出一个综合负载值。Monitor Daemon将各个服务器的综合负载值和当前权值算出一组新的权值。当综合负载值表示服务器比较忙时,新算出的权值会比其当前权值要小,这样新分配到该服务器的请求数就会少一些。当综合负载值表示服务器处于低利用率时,新算出的权值会比其当前权值要大,来增加新分配到服务器的请求数。若新权值和当前权值的差值大于设定的阀值,Monitor Daemon将该服务器的权值设置到内核中的IPVS调度中。过了一定的时间间隔(如2秒钟),Monitor Daemon再查询各个服务器的情况,并相应调整服务器的权值;这样周期性的进行。可以说,这是一个负反馈机制,使得服务器保持较好的利用率。

    在加权轮叫调度算法中,当服务器的权值为零,已建立的连接会继续得到该服务器的服务,而新的连接不会分配到该服务器。系统管理员可以将一台服务器的权值设置为零,使得该服务器安静下来,当已有连接全部结束后,他可以将该服务器切出,对其进行维护。维护工作对系统都是不可少的,比如硬件升级和软件更新等,零权值使得服务器安静的功能很重要。所以,在动态反馈负载均衡机制中我们要保证该功能,当服务器的权值为零时,我们不对服务器的权值进行调整。

 

参考文献:

    William Stalling, Viewpoint: Self-similarity upsets data traffic assumptions, IEEE Spectrum, January 1997.
    Kihong Park, Gitae Kim, Mark Crovella, "On the Effect of Traffic Self-similarity on Network Performance", In Proceedings of the 1997 SPIE International Conference on Performance and Control of Network Systems, 1997.
    Nicolas D. Georganas, Self-Similar ("Fractal") Traffic in ATM Networks, In Proceedings of the 2nd International Workshop on Advanced Teleservices and High-Speed Communications Architectures (IWACA'94), pages 1-7, Heidelberg, Germany, September 1994.
    Mark Crovella and Azer Besavros, Explaining World Wide Web Traffic Self-Similarity. Technical report, Boston University, October 1995, TR-95-015.
 Bruce A. Mah. An Empirical Model of HTTP Network Traffic. In Proceedings of INFOCOM 97, Kobe, Japan, April 1997.
 Red Hat High Availability Server Project, http://ha.redhat.com/ The Linux Virtual Server Project, http://www.LinuxVirtualServer.org/