集群的可扩展性及其分布式体系结构之七--网络负载平衡常见问题![]() | ![]() |
![]() |
级别: 初级 林凡 (iamafan@21cn.com)厦门大学 2003 年 4 月 09 日 阔别已久的集群系列终于又和大家见面了,埋头研究了一段时间,也实现了一些系统的具体实现,从中获得了不少体验。接下来准备就遇到的问题和体会同广大爱好者一同交流。这一章主要介绍了在进行一个负载平衡项目中遇到的一些错误。 集群系统的设计是复杂的,特别在处理通信和软件架构上面,有很多令人意想不到的问题,层出不穷。以下是笔者在部署集群系统的时候遇到的频率较高的问题,且作为抛砖引玉,希望广大爱好者可以加以讨论: 如果有太多网络流量要处理,就会导致包丢失和发往目的节点的包阻塞,这时就会导致溢出。溢出可能发生在主控平衡器,也可能是在各服务节点。由于平衡器在处理能力上往往比节点的要大的多,就很可能是平衡器的流量很平稳但是某些较弱的节点溢出;反过来平衡器如果超载则会导致将要转发的数据流丢失或阻塞。
在处理TCP/IP协议是最常见的溢出错误就是TCP包超时。由于发送的TCP包需要等待确认信息,溢出错误使得确认信息无法返回,引发用户程序的再次尝试发送相同的请求包(这会产生更多的流量),最终造成恶性循环直至这个连接不可用。 如果有太多网络流量要处理,就会导致包丢失和发往目的节点的包阻塞,这时就会导致溢出。溢出可能发生在主控平衡器,也可能是在各服务节点。由于平衡器在处理能力上往往比节点的要大的多,就很可能是平衡器的流量很平稳但是某些较弱的节点溢出;反过来平衡器如果超载则会导致将要转发的数据流丢失或阻塞。 在集群内部,一个节点如果和其他节点相比,没有得到足够的流量,或者这个节点总是处于比较空闲的状态没有什么负载,就说明集群的负载出现不平衡,这个节点正在"挨饿"。事实上,这表明了集群节点的计算资源没有被充分的利用,负载均衡的作业分配效率很低。这是典型的负载均衡算法使用或者系统配置不当的问题;有的时候,没有充分考虑集群节点性能差异,采用"一视同仁"的分配算法也会引起挨饿。 举例来说,一个仅根据加权算法来分配的系统,节点很容易"挨饿":高权值的节点比其他节点更容易分配到任务,这就是为什么加权方法和其他方法要联合使用的原因。在节点处理能力非对称的集群中,能力强的节点处理请求更快,应答如果简单处理也很快,因此,在这种集群下最少连接法和最快响应法也可能导致节点"挨饿"(那些处理能力比较弱的节点总是分配不到任务)。比如,最快响应法受到平衡器和节点之间的网络连接影响,千兆以太网连接的节点比100兆标准以太网的响应速度自然快得多。 网络不可达一般由于路由问题或者网络的暂时性错误引起的。他们对于访问者而言体现为一致的错误:"主机或网络不可达"。但是作为负载均衡器要有能力识别出其错误的区别,因为这将导致在集群管理上的差异。
对于一个集群系统而言,不可避免的要考虑系统中的数据存贮问题。一般来说,包括海量数据库系统和大规模电子邮局,一旦采用了分布式计算的构架,就一定要解决数据存储的容量和一致性两个方面的问题。 采用了分布式架构,海量存储自然变为可能。通过人工的方法或者预设的策略,可以将数据按照一定的单位分割(比如说块),分别存放在不同的物理存储设备上。典型的如大多数的数据库管理系统,借助文件组和跨磁盘存储能力,将大容量的数据信息存放在不同的磁盘分区,以提高整体的存储容量。像微软的Sql Server 中的文件组,或者是UDB2里面的TableSpace,可以跨磁盘分区存放表和其他数据库对象。 但是对于集群系统而言,尤其是网络负载平衡系统,集群内的节点被均衡器无差别地对待(就数据访问能力而言),均衡器假定所有的节点能够对同一数据进行一致读写。而同时出于容量的考虑又需要将数据分布式存储。那么如何保存各个节点的有效副本,如何对共享数据进行一致访问,就成为多数的负载平衡系统中至关重要的问题。 以目前比较流行的LVS(Linux Virtual Server)负载平衡系统为例。LVS通过linux的核心数据包投递程序,将进入集群系统的IP包按照既定规则转发到相应的集群节点进行处理。注意:这里处理的对象是网络数据包而不是具体的磁盘数据 ,那么意味着LVS假设所有的节点访问同一个一致的、可靠的、大容量的磁盘共享系统。当然,NAS或者共享RAID阵列等硬件上可以实现这一点,但是在兼顾效率和容量的分布式存储环境下,要求每一个节点保存部分数据,而且不同结点的数据互相不交叉或者交叉比较少。就难免出现数据读写不一致的情况。 而解决这类问题一般方法,要么是集中存储,使用共享的存储服务器或者存储设备;要么采用分布式文件系统,将文件分块存放在不同的节点磁盘上;再不然就是通过人工的手段对访问数据的应用程序进行改写,人为的设定程序的数据访问策略,在应用层实现分布式存储。各种方法都有有缺点: 方法一比较简单,找一台I/O处理能力强的服务器作为NFS服务器,提供唯一的数据存储入口即可解决,但是容易造成瓶颈;方法二兼顾了性能和容量,但是需要SAN这样的专有系统,实现复杂造价高;最后一种方法需要定制特定的应用层代码,大大增加了项目的开发成本和风险。 由于负载平衡集群的运转,完全依赖于均衡器的正常执行,而且多数集群对外体现的单一系统映像也必须通过均衡器这一角色来实现。因此,一旦均衡器失效,整个集群也就无法使用。提高集群的可用性,重点是解决核心部件的单点实效。 常见的方法就是冗余。这里通过一个特殊的"备份"节点,定期对均衡器进行监控,一旦发现均衡器无法正常访问,就立刻向所有的节点发出广播消息,告知错误,并且把均衡器上最近的有效数据加载到OS的内核,接管失效均衡器的任务。 监控的信息通过"心跳线路"传递,可以是专用的串口通信线路、红外设备,也可以是单独的局域网线,或者仅仅是逻辑上存在的信道。不管使用哪种连接,心跳信号的传递本身是要可靠的,而这一点只能依赖于监控机制和心跳线路的选择。 失效过后的替换过程不一而足,主要看均衡器是位于哪一层次上实现SSI(单一系统映像)。网络负载平衡集群中,均衡器一般都要承担一个虚拟IP管理者的角色。所以,备份节点在进行失效处理的时候,需要把虚拟IP地址接管过来,必要的话还需进行ARP响应欺骗的修改工作,告知路由器新的ARP映射列表。而更为常见的双机数据库热备份系统,需要处理数据库的名字替换工作,同时接管必要的在处理进程和联机事务操作。
从上面的几点分析看来,集群的负载平衡诸多问题主要集中在:负载平衡机制的有效性、通信机制的效率、集群I/O的一致性等几个方面上。 一、集群能否在真正意义上对任务进行"平均分配"以实现负载平衡,其中最为关键的就是对节点当前状态信息的动态获取以及利用。实际上,理想的最优负载共享策略是很难实现的: a) 在一个给定的时刻获得系统全局状态的精确信息是不可能的,由此引发分配算法的行为也是不稳定的。 b) 复杂分配算法和全局信息采集程序的执行可能会产生很大的系统开销。 c) 进程和数据迁移所带来的收益与开销比例难以准确估计。 由于上述的不可预测性,导致了在设计以及实现网络负载平衡集群时,尽量使用适合网络平衡条件的轮询或者最少连接算法,简单有效;并且,无论采用基于算法预测还是负反馈动态权值的机制,都要尽量避免通信包的泛滥。此外,在平衡算法和权值动态调整机制之间寻求一个合理的参数模型,需要在具体的集群中通过不断的试验来应证。 二、节点需要定时向均衡器报告当前负载状况,备份均衡器需要定时监听均衡器的心跳信号。这些需要都会导致频繁的通信在集群内发生。因此使用高效率的、可定制的网络消息协议就成了解决的关键。TCP/IP作为传统协议,本身存在一定的局限。设计开发一套适合的快速消息协议,可以从底层上解决大部分的通信效率问题。一般的思路是:在假定通信信道是可靠稳定的前提下,简化通信原语的设定,减少握手和确认消息,使用大的滑动窗口和收发缓冲区,甚至使用burst发送模式。关于消息通信的具体技术我们将在后续的篇章进行讨论。 三、对于数据一致存储的问题,现今比较成熟的技术有NAS和文件服务器。NAS其实是一种装有嵌入式系统的高效的文件服务器,一般提供大容量的可靠的磁盘存取服务,对外提供NFS的标准访问方式,兼容多数的OS。这样在集群中通过部署NAS实现集中存储保证节点的数据一致访问。但是改方法容易造成I/O瓶颈,不适合数据存取量比较大的集群系统。比较兼顾性能的做法有SAN系统,但是非常昂贵,在成本上救违背了集群的基本初衷。现在出现新的做法是在工作站部署分布式文件系统,利用节点本地磁盘组合全集群的大容量存储设备,即满足了容量的要求,在性能上又避免了传输瓶颈。比较好的有Lustre、GFS等。
集群的问题其实远远不只这些。我仅就一个网络负载平衡集群项目的实施,提供一些经验和个人观点。在后续的篇章中,将在一些专题上继续开展讨论,也算是目前这些问题的一个延伸。 |