ADC产品(应用交付控制器)主要实现负载均衡、应用和协议优化、安全防护等功能,其目的是实现服务器和应用系统的高可靠可用性。其中负载均衡功能是ADC的基本功能也是最重要的功能,但是基本不代表简单,在实际使用中,我们总是会发现用了负载均衡设备,但负载均衡并不均衡的现象。
为什么负载会不均衡呢?请让我们从技术角度来仔细探讨,相信大家会有清晰的认识。
欲要实现服务器分配均衡,大家第一个想到的选项是什么?很多人肯定回答是算法,没错,是负载分配的算法,但一台负载均衡设备提供了很多的算法,具体算法应该如何选择呢?
我的回答是具体需求具体考虑,我们来一一讨论。
负载均衡的分配算法分为静态算法、动态算法以及根据具体需求特定分发三大类。
静态算法包含论询,比例(权重)等。
动态算法包含最小连接数,最快响应速度等
具体需求特定分发则包含各种各样的情况,例如针对某些源IP,分发到指定的服务器,针对某些请求内容,分发到指定的服务器等。
配置过负载均衡设备的人最熟悉的算法应该是轮询(Round Robin:对每个新建连接依次分发到服务组中的每台服务器)。轮询是静态算法,也是大家配置设备时,往往会默认选择的算法。轮询的结果是每台服务器上连接的总数是一致的,但服务器的硬件和软件性能可能会不同,导致服务器当前处理能力差别很大,也就是服务器的负载差别很大,而随着分发到服务器的用户连接越来越多,导致某些性能差的服务器上当前处理的连接数越积越多,最终将导致该服务器崩溃,而其他服务器却相对空闲,这显然不是客户想看到的。
这个时候有人会考虑选择比例(Ratio), 例如两台服务器一台性能是另一台的两倍,那么在分发的时候设定一个比例2:1,性能高的服务器分发到的连接数是性能低服务器的两倍。但是比例算法仍然是一个静态算法,比例的设定取决于人的经验感知,不能代表设备的真正负载和性能,导致实际的运行结果仍然会有比较大的偏差,服务器负载仍然不均衡。
通过上面可以看出,静态算法无法实时感知服务器的运行状态,是一种比较死板的算法,无法动态调整。因此对于处理起来比较复杂的应用,最好是考虑动态的算法,例如最小连接数(Least Connection:ADC实时统计当前每台服务器上的连接数,新的连接将传递给当前连接数最少的服务器),上面说过,轮询是保证每台服务器处理过的总连接数是均衡的,而最小连接数与轮询恰好相反,最小连接数是保证每台服务器当前正在处理的连接数是均衡的,这种动态算法反映了服务器的性能情况,例如服务器1当前正在处理的连接数为50,服务器2为49, 那么下一个新建连接会发给服务器2,此时两台服务器都是50, 假设服务器1处理比较慢,服务器2处理比较快,那么下一时刻可能服务器2的当前连接数又变得比服务器1少,结果新建连接会继续发给服务器2。所以从总数上来看,服务器2处理过的连接数会远远高于服务器1,但正在处理的连接数总是均衡的。
还有一种动态算法是最快响应速度(Fastest Response : 新的连接传递给那些响应最快的服务器)。这种算法把新建连接总是发送给响应最快的服务器,它的表现是,各台服务器上的总连接数和当前连接数从统计上都不一致,但是处理的连接数最多的那台,肯定是性能最好的服务器。
通过以上的分析,通过配置最优的负载均衡算法看似能够保证服务器的负载均衡,但实际上还不够,现实中有很多情况会导致服务器的负载失衡。有以下几种情况:
1)应用无需配会话保持的情况,ADC设备把连接均衡分发到服务器,但是某些连接访问量比较大,有些连接访问量比较小,导致的结果是服务器上连接数看似均衡,但服务器负载差别比较大。
解决办法:基于请求来分发,用户访问的最小颗粒度是请求而不是连接(一个连接中可能有N个请求),如果基于请求来分发,自然可以更深一步来均衡服务器的负载。
2)应用需要配置会话保持的情况,很多应用都需要配置会话保持,假设配置的是源IP会话保持,那么同一个源IP的所有连接都会保持在一台服务器上,假设某些源IP访问量特别大,某些源IP访问量比较少,就会导致某些服务器负载比较高,某些又比较低?尤其是某些用户的地址在出口是做了NAT的,ADC设备看到的源IP是这个NAT IP,但后面其实有很多个用户在访问,会导致服务器连接数不均衡,并且负载差别很大。
解决办法:
a)采用基于Cookie的会话保持,Cookie会话保持主要用于HTTP协议的应用,使得每隔客户端带着相同Cookie的会话才会分发并保持在一台服务器上,它可以细分开同一源IP的多个连接,所以可以使得服务器的负载更均衡。
b)基于session-id的会话保持,有些客户端不支持Cookie或者应用不支持Cookie或者使用Cookie会话保持后,服务器负载仍然不均衡,我们可以考虑采用脚本编程分析数据包的内容取得会话的session-id并以此做为保持选项,这是一种比Cookie会话保持要求更高的保持策略,只有比较灵活的ADC设备才能实现。
c)基于用户的某个关键字信息进行保持,例如手机的应用,用户的数据包中会带有手机号信息,通过编程分析数据包取得这个关键字信息进行分发和保持,将使得服务器的负载更均衡。
3)使用了各种方法负载都不均衡的情况,服务器的负载高低不仅仅跟CPU,内存的使用率高低有关系,同时也跟应用系统程序的实现细节息息相关。这里有一个真实案例:客户的应用部署多台小型机,同时每台小型机又划分出多个虚拟机,每台虚拟机都安装了一个应用系统,通常负载均衡分发自然是针对这些虚拟机进行分发,但是每台虚拟机的应用系统有一些资源使用的上限,例如每台虚拟机最多可运行50个应用线程,结果在CPU,内存占用并不高的情况下,线程用满了,导致虚拟机无法继续处理新的请求。
解决办法:这种情况极其特殊,任何ADC设备都无法设计出标准感知应用程序是否可用的选项。但是,是否无法解决呢?还是有办法的,一个人累不累自己最知道,应用系统自己是可以知道能否处理更多东西的,那么办法就是应用程序自己做一个监控,把监控的结果写到一个文件中,ADC设备通过健康检查的功能定时取这个文件判断里面的内容,如果内容指示为不可用,那么后续用户的访问将发送到其他的服务器,当检查到该台服务器又可用了,可以把新的用户请求继续发送到该台服务器。这种方法同样要求ADC设备能够编程定制一个健康检查,这也是对ADC设备的更高要求。