集群的可扩展性及其分布式体系结构之九面向内容的负载平衡集群 ![]() | ![]() |
![]() |
级别: 初级 林凡 (iamafan@21cn.com)厦门大学 2003 年 6 月 09 日 上文主要讨论了基于IP包转发和TCP连接调度的负载平衡集群技术的主要缺陷。这里针对前面的问题,提出面向数据内容调度的负载平衡技术,是对原有三层和四层交换的一种改进,旨在提高集群的总体吞吐性能和复杂应用的适应能力。 三层和四层的负载平衡器实现了对IP数据包的投递选择,将客户端发送的请求报文分布到集群的节点中。我们可以把这种形式看作是一种作业调度,其调度的粒度是报文或者是连接。分布式系统中,作业调度的粒度选择一直是影响性能和吞吐量的关键因素:大粒度的调度往往性能不高,而细粒度的调度开销又比较大。显然三层交换技术由于采取IP报文作为调度的基本单位,可以最小化调度算法的复杂性,给各种优化性能的高效技术提供扩展的空间。我们如果抽象的看待三层调度,其模型可以描述如下: 〔图一〕:集群调度模型 ![]() 均衡器从IP层开始,截获所有的流入报文,并按照报文调度策略进行服务节点选择、报文修改、报文重新投递三项工作。此外,对于错误的报文以及超时等网络上常见的异常也需要进行处理。由于报文仅仅是网络通信过程中的数据片断,因此对于完整的通信来说,TCP/IP采用了连接这一更大的任务粒度来描述通信。连接引入了状态:起始、消亡、异常等,将无续的报文组织起来,满足了通信会话的功能要求。 三层交换基础到目前为止已经非常成熟,因为处理器仅需要识别报文的地址相关信息,利用快速查找表即可以实现报文交换。软件方面,Windows下的NLB集群以及Linux下的LVS都是典型的代表,它们都在核心层的TCP/IP协议栈实现报文的快速处理,并且尽可能避免耗时的上下文交换(上下文交换用于核心进程和用户进程之间交换处理的数据,实现了对数据更为复杂的处理)。而硬件方面对于报文交换的实现更为成熟,借助专用的并行处理器实现对报文的线速处理。这方面有Cisco、Intel、F5等多家厂商实现的高性能集群产品。 四层交换对TCP连接进行调度,粒度更大。原则上粒度大的调度在分配算法本身的开销相对更小,因为调度算法的执行频度因为粒度的不同降低几个数量级。但是,维护大粒度任务所需的状态集合可能要比小粒度的任务大的多,状态的切换也更加复杂,特别是对于异常状态和边界状态的处理,这对平衡器的逻辑设计提出更高的要求。 三层交换,在后端服务节点内容全镜像的情况下,均衡器仅需要记录一张报文的来源-目的映射表即可,查表算法可以使用快速的搜索算法进行,已经应答的报文只需要简单的从映射表中删除。核心进程的维护工作比较轻松。而对于连接调度,均衡器"表"中的项目可以小一些,但是表中每一个连接任务的状态信息都必须维护,对于任务单位而言需要消耗更多的空间存储任务状态,而且任务的生存周期变长。因此一段时间下来,均衡器就会维护着大量的有状态的连接任务调度信息。 这里并不是说明三层和四层交换孰优孰劣,他们各自有自己的适用面。我们需要知道的是,选择了不同的调度粒度,直接导致整体调度策略的变化,以及对于集群调度性能影响的关键因素也将发生改变。三层调度中,快速的查表和避免上下文交换是提高性能的关键;四层交换中,CPU还需要足够的内存维护大量的活跃连接,每个连接所管理的报文构成二级查找结构――这需要更快的CPU搜索算法,甚至需要利用多CPU和多线程技术。 面向内容的交换,严格上讲,并没有脱离四层交换的范畴。是四层调度技术的一种补充――毕竟没有什么比网络连接更为根本了。但是,从调度的角度来理解,面向内容的交换技术必须跨越连接而面向会话。 众所周知,TCP/IP的设计中没有严格的定义会话,仅仅是在OSI模型中给出会话的规范并未具体实现。联系一下现实的情况,我们把Http协议中一次Session过程认为是一次TCP上的会话,Session由多个连接的通信活动构成,有起始状态,和异常状态。因此,本文对于会话的理解,是基于实际的应用层协议定义进行的。 面向内容的交换仅仅是一个笼统的概念。可以针对HTTP的Session应用进行交换基本单位的定义;或者是根据请求报文的内容分类定义交换策略;甚至可以在自定义的UDP协议上处理会话级别的调度(UDP是无状态协议,但是在应用层上我们可以通过通信语义将它实现为有状态协议)。无论哪一种策略,都会导致调度算法的实现大不相同。但是,万变不离其宗,所有的面向内容的交换技术必然遵循这一根本原则: 面向内容交换的集群技术,处理模式的核心是,针对请求报文中所包含的重要关键域(也可以理解为Keyword),对之进行分析、分类和策略化处理。以达到有效的按照应用层的协议特点特别是集群的调度需要,对调度策略进行灵活的调整。 这样,面向内容的均衡工作理论上可以在不同的网络层次进行。协议层均衡需要对所有经过的IP包头进行协议检验,按照已定义的规则进行转发。同样,集群的负载均衡器可以实现高层次的流量分配。特别是针对特殊要求设计的Web站点、视频服务器等。更需要这种特殊优化的负载平衡。
面向内容交换技术的设计初衷,就是为了解决高层通信协议中会话应用的问题(在本系列 文章之八 中,我们讨论过这种情况)。 由于集群的设计直接面向具体的协议。关键是通过数据请求解析模块和可扩展的报文分类机制,可以灵活的针对目前主流的协议进行定制,提供基于协议的会话级交换。 以HTTP为例,不论是客户端的Cookie还是服务端的Cookie,都可以直接从HTTP协议的URL字符串获得。以PHP中的Session为例,当客户端浏览器与集群的服务器节点建立了Session之后,由服务器端产生的Session标识符会伴随整个Session过程的始末,集群均衡器负责记录这个Session标识与这个服务节点之间的映射关系,表示该会话属于某一节点,并将后续的同样带有该Session标识信息的Request定向到这个服务器,保证了会话的正确运行。 Session ID Session ID客户端――――――――――>服务节点x 会话中,客户端可能有多次的连接发往服务节点x,都被均衡器调度到同一台节点上。这里,调度的粒度变成了会话(等效于Session ID),均衡器除了第一次的连接需要进行调度处理之外,后续的同一会话的连接只要简单的按照映射表项进行转发即可,不需要复杂的调度算法。已存在的会话可以复用旧的连接,以避免不断开辟新的TCP连接导致的三次握手的开销过大问题;新的会话则根据负载平衡原则,在会话初建期先选择负载最轻的节点,而后产生新的会话连接。 面向会话负载平衡的核心,实际上集中在如何更加有效的进行协议解析(URL解析)和快速分类,以及如何指定分发策略上。 本质上,把协议解析看作是负载平衡集群的前置工作,由均衡器中特定的预处理模块担当,而后续的平衡策略实施与原有的面向连接的负载平衡技术也就大同小异了。 ![]() 由于会话的定义在具体的协议中依据有所不同。对于SSL等基于ID的会话应用,可以使用上面的方法实现。对于本来就是无状态的UDP通信而言,会话的定义隐含在UDP包头中,这要具体按照应用中对会话的定义进行前置处理程序的修改。总而言之,会话级调度的支持,满足了负载平衡功能上的需要,特别对于某些应用层协议。 三层交换和四层交换中,由于采取面向数据包调度,无法区分数据包的业务意义。因此只能假设后端服务器能够提供一致的内容。对于集群的服务节点群来说,可以完全复制一样的数据内容或者是访问一个共享的磁盘来实现。但是对于性能和存储能力都有较大的影响。 〔图二:〕三层和四层交换需要一致存储镜像支持 ![]() 采用面向协议的负载平衡,在后端文件系统的要求上,允许更好的扩展性。请求往往是直接面向数据的,而数据大多数以文件的形式存在,在Web类型的应用中尤其明显。不管是Web站点还是视频点播服务器,对信息的获取都是通过获取文件进行。因此,HTTP协议中包含的文件相关信息(相对路径以及文件名)足以提供负载平衡的解析支持。 通过文件存储的分区,按照文件类型(通过文件名后缀)、不同文件的读写频度差异,或者不同文件的功能进行区分,将文件分散到不同的服务节点或者是服务结点组上。物理上文件是分散的,但是逻辑上多个服务器的存储在内容可以构成一个单一的系统存储映像,这一点类似windows里面的逻辑卷的概念,对外提供一致的访问服务。一方面将负载静态的分布到不同的节点,提高整体的吞吐量;另一方面避免了完全镜像中,多点同步引发的开销问题。 〔图三〕根据HTTP请求中文件类型进行负载平衡的面向内容交换 ![]() 负载平衡器需要在请求分发这一环节支持内容分区。通过解析后的请求分类,将指定类型的请求发往特定的节点或者节点组。当然,这必然要求负载平衡器保留一份全集群的内容索引镜像,并且在内容有更新的时候同步这个镜像。镜像可以是简单的hash表,记录每个节点所能处理的请求类型或者文件类型;如果支持节点组的话,还可以扩展该映射表,用二级的索引结构来支持节点集。 对于以静态内容为主的大型站点,可以很简单的修改负载平衡器的规则集就能支持内容分区,借助节点的本地硬盘组合,就可以实现大容量的服务站点。 XML作为现今最为通用的数据格式交换标准,必将逐步替代HTML。而具备对协议的深入解析的能力,就能够按照预定的样式(Schema)分析HTTP协议数据中的XML数据。典型的EDI服务环境中,EDI服务属于计算密集和通信密集的应用,XML应用在EDI中有着天然的优势。然而,如果仅仅依赖单一的计算系统提供大规模的数据交换显然是存在很多弊病的。 面向XML交换的集群技术,可以允许将后端的交换服务器按照不同的交换职责或者是不同的交换类型进行划分。例如,贸易类企业数据交换和工业企业数据交换的格式及表示习惯有很大的区别,而日常中也体现出不同的流量峰值。因此,将不同类型的数据交换任务静态地划分到服务结点上,可以提高集群整体的吞吐量和通信效率。负载平衡器需要分析带有XML请求的数据包,获得有效的负荷信息,分析XML中的关键域(Key Field),并根据已定义的模式将数据转发到有对应处理能力的节点组中。 我们假设这样的一个应用:一个集群系统,提供了基于XML的服务。服务是同时面向企业用户和个人用户,并且在功能上相当。但是企业用户需要支付更高的服务费用,并且享受更好的服务质量和性能;同时,企业日常的请求中,存在部分"紧急请求"的请求需要优先完成。因此,下图所示,集群将企业的"紧急请求"发往集群中的高速主机节点进行服务,保证质量和任务的优先级;企业的一般请求发往相对普通的服务器节点;而一般个人用户因为支付较少的费用享受相对较差的服务(往往是需要更长的服务等待时间),所有的个人请求发往普通服务节点(选取性能权值最低的节点)。 〔图四〕基于XML调度的集群应用 ![]() 服务节点的好坏可以根据配置和当前处理负载进行排队,权值高的节点表明处理能力强,用于服务"紧急请求"或者高优先级用户(例如企业用户)。另外均衡器判断请求可以根据URL中,包含的XML域进行解析:
这里的表格用于 均衡器进行XML解析调度的参考,可以看出,将表格中的条件转换为具体的语言并不难。其中MinWeight和MaxWeight分别表示取节点群中权值最小和最大的节点。 面向XML解析的实现方法并不难,关键在于XML解析所带来的额外的消耗是否会使集群的均衡器成为系统的性能瓶颈。关于这一点我们将在后续篇章中讨论。 根据HTTP协议的URL信息进行负载平衡还有一个非常重要的应用,就是缓冲交换(Cache Switching)。大型ISP 为了加速网络的响应都会架设大量的前置高速缓冲服务器(forward proxy cache server),但是,对于无法识别内容的缓存集群来说,所有的缓存服务器节点都必须保存整个被访网络的全部内容(理论上,所有的网络中的站点都被缓存过的话)。显然,缓存服务器的存储能力无法满足这一点要求,势必导致大量的页面无法被及时缓存而进行缓存更新,用户访问网络的速度反而变慢。 如果使用面向URL内容的集群调度技术,可以设定每一台集群节点负责部分URL的缓冲请求的任务,由于每个节点所缓存的内容完全不同,集群整体构成一个大的内容超集,提高了总体存储能力。而Cache集群缓冲命中率的提高,也大大降低了用户请求的页面出现缺失的情况,改善了集群的吞吐能力和性能。这一点,也被称为Locality――局部特性。
分析了面向内容负载平衡集群技术的特点之后,我们将就面向内容交换的核心处理技术进行分析,并在后续的篇章中进一步讨论其体系结构、网络模式、调度算法、性能比较等几大方面的内容。
|