Linux集群

   一: 什么叫集群

   所谓的集群就是将一组计算机作为一个整体,为用户提供可靠的计算机资源,作为一组计算机的单个叫做集群的节点,一个理想的集群是,用户从来不会意识到集群系统底层的节点,在他/她们看来,集群是一个系统,而非多个计算机系统。并且集群系统的管理员可以随意增加和删改集群系统的节点。

   集群并不是一个全新的概念,其实早在七十年代计算机厂商和研究机构就开始了对集群系统的研究和开发。由于主要用于科学工程计算,所以这些系 统并不为大家所熟知。直到Linux集群的出现,集群的概念才得以广为传播。集群系统主要分为高可用(High Availability)集群,简称 HA 集群,和高性能计算(High Perfermance Computing)集群,简称 HPC 集群。

二:集群分类

   集群系统分为两类:

三:基于Linux的系统集群

  

1.Lsf

如何管理各种各样的计算资源(如:CPU时间、内存空间、网络带宽、应用程序等)是许多企业当前都很头疼的问题。尤其是对于那些员工遍布全球的公司而言,如何充分利用有限的计算资源是非常关键的问题。由platform公司开发的lsf 多集群系统使多个异构的计算机能够通过局域网或广域网共享计算资源,并能够为用户提供对资源的透明访问。Lsf现在主要支持以下三种大规模资源共享:

  1. 一个大企业中的多个部门,每个部门可以有一个或多个集群,这样就使得部门内部和部门之间可以共享资源。
  2. 较小部门的数据中心。大的昂贵的计算资源如超级计算机可以透明地与远方较小的部门直接进行共享。
  3. 通过松散连接的站点共享资源。

Lsf将多个集群连接在一起,一个集群往往是企业中的一个部门,每个集群中有一个主控机,此主控机负责收集该集群系统中的各台主机的负载信息,并且根据各 主机的负载信息情况对作业进行调度。各个集群系统之间根据一定的策略进行资源共享。在每个主控机上定义了该集群能共享哪些集群系统中的资源。当用户发送了 一个任务请求时,lsf系统能将此任务发送到对应的资源所在地,并根据调度策略选择负载较轻的机器对此任务进行处理。当多个用户请求同一个资源时,根据用 户的请求优先级来确保优先级高的用户的紧急任务能首先得到满足。Lsf还具有以下特点:

  1. 提供了增强的计算能力。
    通过全局资源共享,用户可以访问各种各样的计算资源,许多闲置的计算机现在都可以充分利用起来进行任务处理,许多机器也可以并行地执行同一个任务,这样就大大增强了用户的计算能力。
  2. lsf提供了用户可配置的安全策略。
    通过让用户使用RFC931协议、Kerberos、和DCE认证等策略,系统保证了远方的任务来自授权的用户。
  3. 每一个集群都是一个自治的系统。
    每个集群中的主控机的配置文件中记录了如下信息:如允许在多个集群系统之间传输的任务的数量与类型,允许在多个集群 之间共享资源的用户名。
  4. 提供非共享的用户账号和文件系统。
    当任务在多个集群之间进行传输时,用户的账号可以根据配置文件进行映射。为了支持异构的系统,lsf通过在任务执行前后将文件在集群系统之间传递来提供对非共享的文件系统的支持。
  5. 良好的可扩展性。
    在单一的集群系统中通过主控机进行管理,所有的配置信息都在主控机上,多个集群系统之间信息的传递主要是与主控机有关,而与集群中的其它主机无关。因此lsf的集群能非常容易地扩展到成百甚至上千台。
  6. lsf系统支持多种操作系统平台。
    如主要的UNIX平台:Sun Solaris、 HP-UX、 IBM AIX、 Digital UNIX/Compaq Tru64 UNIX、SGI IRIX以及 Red hat Linux、 Windows NT、Windows 2000等。

 

2.TurboCluster

TurboCluster是一个企业级的集群方案,它允许在多个计算机上构建高可用的、可扩展的网络。它支持Intel和Alpha芯片,支持Linux 、Windows NT 和Solaris操作系统平台。使用TurboCluster系统可以显著地提高基于TCP/IP协议的多种网络服务的服务质量,这些服务包括Web、 Mail、News和Ftp等。TurboCluster具有良好的可用性、可扩展性和可管理性,集群内部的实际服务器的数量可以扩充到无限台。 TurboCluster是一种基于软件的集群系统解决方案,它还能够支持异构的网络环境。它的结构如图2-1所示。

当客户向集群系统发送一个请求时,该请求首先到达高级流量管理器,高级流量管理器通过一定的调度策略将此请求转发到集群中的某一台实际服务器上对此请求进 行处理,最终的回应请求将直接发送给客户。由于最终的回应请求没有通过高级浏览管理器而是直接发送给客户,这样大大减轻了高级浏览管理器上的负载,从而降 低了瓶颈产生的可能。TurboCluster中采用的调度策略有:轮回(Round Robin)、加权轮回(Weighted Round Robin)、最少连接(Least Connection)。为了减少高级流量管理器产生失效的可能,TurboCluster为高级流量管理器准备了一个备份机。该备份机不断询问管理器来 确认它正在正常工作,一旦发现主管理器已经失效,备份机将接替它继续工作。


图2-1 turbocluster结构图

TurboCluster具有如下一些增强的性能。

  1. 通过heartbeat在备份机上监测流量管理器的运行状态来提供更高的可用性。
  2. 对不可预测的系统或应用程序的失效进行自动管理。
  3. 提供动态的负载平衡,它能够消除瓶颈并且处理峰值负载。
  4. 高级流量管理器只转发已经授权的请求,通过在实际的应用程序服务器的前端增加虚拟防火墙来提高网络的安全性。
  5. TurboCluster对外只显现出流量管理器的IP,而集群系统中的实际服务器的IP地址对外界而言是不可见的。
  6. 当实际服务器正在对外界提供服务时就可以对它进行维护工作。

3.Linux Virtual Server

Linux虚拟服务器(Linux Virtual Server, LVS)建筑于实际的服务器集群之上,用户看不到提供服务的多台实际服务器,而只能看见一台作为负载平衡器的服务器。实际的服务器通过高速局域网或地理上 分散的广域网连接。实际服务器的前端是一台负载平衡器,他将用户的请求调度到实际服务器上完成,这样看起来好像所有服务都是通过虚拟服务器来完成的。 Linux虚拟服务器能够提供良好的可升级性、可靠性和可用性。用户可以透明地增加或减少一个节点,可以对实际服务器进行监测,如果发现有节点失败就重新 配置系统。

Linux Virtual Server的结构如图3-1所示。


图3-1 Linux虚拟服务器结构图

3.1 调度算法

LVS提供了四种调度算法:轮转调度,加权轮转调度,最少连接调度,加权最少连接调度。

  1. 轮转调度(Round Robin Scheduling)
    轮转调度不考虑服务器的连接数和响应时间,它将所有的服务器都看作是相同的。当以轮转的形式将连接分发到不同的服务器上。
  2. 加权轮转调度(Weighted Round Robin Scheduling)
    根据每个机器的处理能力的不同给每个机器分配一个对应的权重,然后根据权重的大小以轮转的方式将请求分发到各台机器。这种调度算法的耗费比其它的动态调度算法小,但是当负载变化很频繁时,它会导致负载失衡,而且那些长请求会发到同一个服务器上。
  3. 最少连接调度(Least Connection Scheduling)
    最少连接调度将用户请求发送到连接数最少的机器上。最少连接调度是一种动态调度方法,如果集群中各台服务器的处理能力相近,则当负载的变化很大时也不会导 致负载失衡,因为它不会把长请求发送到同一台机器上。但是当处理器的处理能力差异较大时,最少连接调度就不能很好的发挥效能了。
  4. 加权最小连接调度(Weighted Least Connection Scheduling)
    根据服务器的性能不同而给它们分配一个相应的权重,权重越大,获得一个连接的机会就越大。有如下的运算方法:(假设共有n台机器,每一台服务器i的权重为Wi (i=1,..,n),活跃连接数为Ci (i=1,..,n), 所有的连接数为Ci (i=1,..,n)的总和,下一个连接会发送给服务器j,服务器j满足以下的要求): (Cj/ALL_CONNECTIONS)/Wj = min { (Ci/ALL_CONNECTIONS)/Wi } (i=1,..,n) 由于ALL_CONNECTIONS是一个常数,因此上面的式子可以优化为: Cj/Wj = min { Ci/Wi } (i=1,..,n)

3.2 负载平衡方法

LVS提供了三种IP级的负载平衡方法:Virtual Server via NAT 、Virtual Server via IP Tunneling、Virtual Server via Direct Routing。

Virtual Server via NAT方法使用了报文双向重写的方法, Virtual Server via IP Tunneling采用的是报文单向重写的策略, Virtual Server via Direct Routing采用的是报文转发策略,这些策略将在以后的文章中详细描述。

4.MOSIX

MOSIX为Linux核心增添了集群计算的功能。它支持的操作系统平台有BSD/OS 和Linux,它允许任意多个基于X86/Pentium的服务器和工作站协同工作。在MOSIX集群环境中,用户无需对应用程序进行修改,或将应用程序与库连接起来,或将应用程序分配到不同的节点上运行。MOSIX会自动将这些工作透明地交给别的节点来执行。

MOSIX的核心是适应性的资源管理算法,它对各节点的负载进行监测并做出相应的回应,从而提高所有进程的整体性能。它使用抢先的进程迁移方法来在各节点 中分配和再分配进程,从而充分利用所有的资源。适应性的资源管理算法具体上又包括适应性的负载平衡算法、内存引导算法和文件I/O的优化算法。这些算法都 对集群中的资源使用情况的变化做出响应。如:节点上的不平衡的负载分布或由于内存不足而导致的过多的磁盘换入换出。在这种情况下,MOSIX将进程从一个 节点迁移到另外一个节点上,从而来均衡负载或将进程迁移到有足够的内存空间的节点上。

由于MOSIX是在Linux的核心中实现的,因此它的操作对应用程序而言是完全透明的。可以用它来定义不同的集群类型,这些集群中的机器可以相同也可以不同。

与Turbocluster、Linux Virtual Server、Lsf等集群系统不同的是,MOSIX集群中的每个节点既是主节点又是服务节点,不存在主控节点。对于那些在本地节点创建的进程而言,该节 点就是一个主节点;对于那些从远方节点迁移过来的进程而言,该节点就是服务节点。这意味着可以在任意时刻向集群中增加节点或从集群中删除节点,而不会对正 在运行的进程产生不良的影响。MOSIX的另外一个特性就是它的监测算法能够监测每个节点的速度、负载、可用内存、IPC 以及I/O rate 。系统使用这些信息来决定将进程发送到哪个具体的节点上。当在某个节点上创建了一个进程以后,该进程就在这个节点上执行。当该节点的负载超过了一定的阀值 以后,就将该进程透明地迁移到别的节点上继续执行。

MOSIX文件系统采用直接文件系统访问的方法,它可以允许迁移到别的节点的进程在本地进行I/O操作。这样就减少了需要进行I/O操作的进程与创建该进 程的节点之间的通讯,从而允许这些进程更加自由地在集群中的节点中进行迁移。MOSIX文件系统使所有节点都可以像访问本地文件系统一样透明地访问其它节 点上的所有目录和文件。

一个低端的MOSIX配置可以包含通过以太网连接起来的多台PC机。一个较大的配置可以包含通过快速以太网连接起来的多台工作站和服务器。高端的MOSIX配置可以包含通过Gigabit-Ethernet连接起来的多台SMP 或非SMP工作站和服务器。

5.EDDIE

Eddie的主要目的是提供一些供那些进行重要任务处理的网站使用的工具,从而使这些网站能够提供持续的高级服务。Eddie创建了一个真正的分布式web服务器结构,它支持分布于不同的物理地点的web服务器。它的结构如图5-1所示。

图5-1所示的分布式服务器包含两个集群,它们分别是site 1 和site 2。每个集群都包含着一台域名服务器和若干台运行web服务器软件的实际的服务器。当用户敲入一个域名时,首先在Local DNS上对这个域名进行解析,找出与其对应的IP地址。如果Local DNS无法对这个域名进行解析,就将此域名发送到Authoritative DNS上,Authoritative DNS返回应该访问的服务器的IP地址,然后用户就可以访问指定的服务器上的内容了。


图5-1 Eddie集群结构图

Eddie主要包含两个软件包:HTTP网关和增强的DNS服务器。如图5-2所示,在每个站点上增加一个新的服务器(即前端机),在其上运行HTTP网 关来接受外界发来的请求并且将请求调度到合适的后端机上执行,DNS服务器上运行增强的DNS服务器软件,通过该软件可以在多个地理上分散的网址上均衡负 载。

Eddie主要有以下与众不同的特点:

  1. 提高了web服务器的吞吐量。通过提供强大的负载平衡能力,Eddie使用户可以充分利用分布式web服务器中的所有资源。主要在两个地方使用了负载平 衡。首先后端机将本机上的负载信息如CPU负载、内存、磁盘延迟、运行队列数据以及页面错等信息发送给前端机,前端机根据负载轻重将外界请求发送到合适的 服务器上。另外在增强DNS服务器软件中也提供了负载平衡的功能,前端机和后端机的综合负载信息都发送到Authoritative DNS服务器上,然后Local DNS可以根据各个Authoritative DNS上的负载的轻重来决定将域名解析的任务发送到哪一台Authoritative DNS上。这样就可以充分利用分布式服务器环境中的所有资源,增强了web服务器的吞吐量。
  2. 提供很好的服务质量。首先Eddie通过使用静态和动态负载平衡策略提高了web服务器的吞吐量,减少了用户请求的响应时间;其次,当用户发一个请求时, 系统就要检查是否来自该用户的连接已经存在,如果存在,就将请求继续发送到上次对该请求提供服务的服务器上,这样就保证了用户对web访问的持续性。如果 没有足够的资源,则将用户请求加入等待队列,并且告诉用户它的请求要等待一会儿才会被处理。


图5-2 Eddie功能结构图

典型集群系统小结

典型的集群共有的特点是:

  1. 集群都是将普通PC 工作站、工作站或服务器通过某种方式连接起来构成的多机系统。连接方式可以采取通过网络适配器和网络集线器,或通过将各个机器的RS-232串口直接连接起来,还可以通过内存通道卡和内存通道集线器的方式连接各台机器。
  2. 集群系统都具有良好的可用性。即它们都能够在集群的某部分资源出故障的情况下继续向用户提供持续的服务。几乎所有的典型集群都拥有灾难恢复功能。
  3. 集群系统有良好的可扩展性。只需很少的配置工作就可以方便地向集群中加入或删除工作节点。
  4. 典型的集群系统提供了良好的可管理性。管理人员通过简单的操作就可以对集群中的工作节点或控制节点进行配置工作。
  5. 集群系统一般都提供了负载平衡功能。负载平衡包括静态负载平衡和动态负载平衡,为了最大程度地利用集群中的一切资源,集群需要具有动态负载平衡功能,它能够通过监视集群中的实际节点的负载情况并动态地进行调度的改变。
  6. 大部分集群系统都有一个主控机,它能够对集群中的机器的运行状态进行监视,而且能够根据各机器的负载轻重进行任务的调度。

评测标准

检验集群系统的主要指标是可靠性(reliability)、高可用性(availability)、可维护性(serviceablity)和其它相关特点和功能。

可靠性主要指集群中的软件、节点计算机和共享存储设备的可靠和稳定程度。

高可用性(High Availabity,HA)要求当硬件系统发生故障时,运行在该系统上的数据不会丢失,而且在尽可能短的时间内恢复应用系统的正常运行,能够满足上述要求的系统称为高可用性系统。

在美国D.H.Brown Association 公司的集群系统评测报告中,将集群系统的测试项目分为11个大项,即:

  1. 集群内备份与恢复:考察集群对故障和条件变化的检测和响应能力。
  2. 集群可配置性:考察集群硬件和软件配置的灵活性。
  3. 节点内故障恢复:考察独立节点硬件和软件故障条件下的恢复能力。
  4. 集群并行数据库可存取性:考察集群对并行数据库的支持程度和效率,即集群内各节点同时访问同一数据库的能力和效率。
  5. 集群内高可用性可管理能力:考察集群系统提供的集群管理工具和界面的易使用性和友好性。
  6. 集群单一系统映像:考察集群在分布式环境中对客户端提供的单一系统的形象。完美的情况就是为了管理和使用方便,集群提供分布式集群资源就像单机系统一样。
  7. 灾难恢复能力:考察集群在地理数据镜像、远程数据复制、远程自动故障处理等方面的能力,即集群在火灾、洪水和地震等条件下保持正常运行和自动故障恢复的能力。
  8. 硬件和软件RAID功能:考察集群对硬件和软件RAID(Redudant Array of Independent Disks)的支持程度,从而保证数据的安全性和可恢复性。
  9. 节点内故障预防:考察节点对故障的预警能力和节点内故障的易分辨性。
  10. 节点故障在线维护:考察节点在不停机条件下增加或更换部件的能力以及节点内软件的可管理性(如软件升级)。
  11. 节点维护特征:考察集群在重启动自动配置(在部分部件失效或增加冗余部件的情况下)、远程操作和远程故障通知等方面的能力。

进程的放置

在集群系统中,进程的到达时间和新到达进程所需的资源量都是不可预测的,因此进程的放置和迁移是非常重要的问题。由于集群系统中的不可预测性,进程有时就 会被放置在不合适的机器上,进程迁移就给了系统一个弥补这样的错误的机会。通过较好的算法将新创建的进程放置到合适的节点上执行,并且对某些进程进行迁移 可以缩短任务的平均执行时间,因此从整体上提高了系统的性能。

进程的放置问题是非常复杂的,因为集群中的资源是异构的,如:内存、CPU、进程间通讯等等。衡量这些资源耗费的方法也是不同的:内存的单位是字节,CPU的单位是循环、通讯资源的单位是带宽。

进程的放置策略分为静态放置策略和动态放置策略。静态放置策略通过预先定义的规则对新创建的进程进行分配,它不使用运行时的信息。而动态放置策略则根据系统状态的变化将进程重新放置到最适宜的节点上。

常见的静态放置策略由三种:Round Robin(RR)、Best-Fit(BF)、Round Robin Next-Fit (NF)。

Round Robin将新创建的进程以轮转的形式放置到集群中的各节点上。这种方法的缺陷在于如果新创建的进程所需的内存量大于将要分配到其上的节点的可用内存大小,则会导致算法的失败。

一种改进的方法是使用Best-Fit方法,进程将被放置到具有最大可用内存的节点上。

Round Robin Next-fit以Round Robin的方式扫描各节点,并且将进程发送到第一个有足够大内存的节点上。它的缺点就是可能会导致负载不均衡地分配到各个节点。

三种进程放置策略的性能如图1-1所示。(进程的平均大小是16MB)

从该图可以看出,NF算法能够最充分地利用内存资源。当集群中的节点数增加时,BF算法和RR的算法的性能也随之有明显的下降,之所以产生这种情况是因为 当节点数增加时,集群中的内存总量也随之成比例地增加,而且新增加的节点也会创建新的进程,这也就意味着大进程的数量也会随之增多,这些大进程对于BF算 法和RR算法而言是很难放置的,因此会导致它们的性能的下降。

一种动态的进程放置策略叫做MS(Migrate the Smallest process),它以Round Robin的形式扫描所有的节点,并且将新进程放置到下一个节点上。与Round Robin不同的是,如果要放置的节点的内存不足以提供给新来的进程使用,则MS算法将迁移走一个进程。将要被迁移的进程是该节点上所有进程中最小的一个 但是迁移走它刚好能满足新进程所需内存,而且也有其它的节点能够容纳这个将被迁移的节点,这种方法有较小的网络开销,如果不存在这样的节点,如其它的所有 节点都没有足够大的内存空间,则算法失败。MS算法和NF算法的比较如下图所示。当进程的平均大小为1M时,两种算法都取得了将近100%的内存利用率, 但是如图1-2所示当进程的平均大小为16M时,MS 算法比NF 算法高了20多个百分点。

以上各种算法都是集中式的进程放置策略,都需要使用全局信息来决定放置策略,不利于可扩展性,不能有效地在拥有多个节点的集群上执行。一种基于MS的分布式进程放置算法(Windowed MS)是这样实现的:它将迁移的进程放置到从信息窗口中选出的具有最大可用内存的节点上。所谓信息窗口指的是一个缓冲区,里面保存着其它节点的可用内存的信息。每隔一定的时间就会将其它各节点的内存信息收集到信息窗口中,并对信息窗口进行更新。

图1-1 进程放置策略性能比较图 图1-1 进程放置策略性能比较图 图1-2 进程放置策略性能比较图 图1-2 进程放置策略性能比较图

进程的迁移

早在20世纪80年代,人们就开始了进程迁移的研究。大多数的研究主要着眼于如何用更好的方法在机器之间传送进程的状态。同构的进程迁移指的是进程迁移的 原始和目标机器的体系结构相同,而异构的进程迁移指的是不同体系结构的机器之间的进程迁移。同构的进程迁移系统的例子有:V Charllote 、DEMOS/MP、 Sprite、 Condor、 Accent ;异构的进程迁移系统有:Tui、Emerald、HMF(Heterogeneous Migration Facility )等。进程迁移主要用于以下几种情况下。

  1. 当失效的机器修复了错误,重新进入集群系统时,需要将某些该机器上原来运行的进程重新迁移回来。
  2. 在集群系统中进行负载共享。为了让一个进程使用尽可能多的CPU时间,需要将它迁移到能提供大部分指令和I/O操作的机器上执行。但是有时候负载共享也有 缺陷,因为大部分的进程只需一少部分的CPU时间,考虑到进程迁移的开销,如果对那些简单的可以在本地运行的进程进行迁移是得不偿失的,但是对于那些需要 大量的处理时间的程序如仿真程序,迁移进程是非常有效的。
  3. 提高通讯性能。如果一个进程需要与其它进程频繁地进行通讯,这时将这些进程放置得近一些就会减少通讯的开销。具体的迁移方法就是将一个进程迁移到其它进程所在的CPU上。
  4. 可用性。当网络上的某台机器失效时,通过进程迁移可以将进程迁移到其它机器上继续执行,这样就保证了系统在遇到灾难时的可用性。
  5. 重新配置。当对集群进行管理时,有时需要将服务从一个节点移到另一个节点,透明的进程迁移可以在不停机的情况下迁移服务。
  6. 使用集群中的某些机器的特殊能力。如果某个进程能够从集群中的某台特定机器上受益,它就应该在那台机器上执行。如进行数值计算的程序能够通过使用数学协处理器或超级计算机中的多个处理器来大大缩短程序执行时间。

尽管进程迁移已经在实验环境中成功地实现了,但是它还没有被广泛地接受。一个原因是占主流的平台如MSDOS、 Microsoft Windows以及许多种类的UNIX操作系统都没有对进程迁移的支持。另一个原因是因为进程迁移开销可能比不迁移进程时的开销还要大。但是当前,两种新 的计算领域又促进了进程迁移的发展,一个是移动计算,另一个是广域计算。移动计算指的是那些便携式的小型计算机的计算问题。而广域计算是指广域网中的机器 的计算问题。

进程迁移将一个正在执行的进程从一个节点迁移到通过网络连接的另一个节点上(也就是说,不使用本地共享内存机制)。进程所在的原始节点上的操作系统应该将进程的所有状态都包装起来,这样目的机就可以继续执行此进程。

要完成进程迁移需要迁移进程的状态,尤其是进程的地址空间,对其它进程的访问(如套接口、管道等),代码(可以组成地址空间的一部分)以及执行状态(寄存 器、堆栈等)。除了这些,还需要将那些对原始的进程所有访问都重新链接到新的进程拷贝上,不然迁移就不是无缝的,就会导致错误。整个进程迁移操作必须是原 子操作,这样才能避免进程的丢失或者是有两个拷贝。

为了进行进程迁移需要再进行以下的修改:

  1. 必须对文件系统进行一定的修改使每个机器看到相同的名字空间。
  2. 必须传送足够的状态从而确保正常的核心调用能够在远端机器上正常执行。
  3. 一些特殊的核心系统调用如gettimeofday 、getpgrp应该发回到原始节点执行。

 

下面通过一个异构进程迁移的例子来说明进程迁移的整个过程。图1-3说明了进程是如何在Tui进程迁移系统中从一个机器上迁移到另一个机器上的。

  1. 首先是对一个程序进行编译,针对Tui支持的四种体系结构,将程序分别编译四次。
  2. 程序在原始机上以普通方式执行。(如命令行方式)
  3. 当选定一个迁移的进程时,migrout程序首先为进程设置检查点,然后挂起进程,然后进行内存映像,接着扫描全局变量、堆栈和堆来定位所有的数据。再把所有的这些都转化为一种中介的格式传送给目标机。最后,杀死原始机器上的进程。
  4. 在目标机上,migrin程序取得中介值并创建新的进程,由于程序已经根据目标机的体系结构进行了编译,因此正文段的信息和数据报的类型信息都是可用的。然后通过重新创建全局变量、堆和堆栈,程序从检查点处继续执行。

 

经过统计,选择空闲主机并且开始一个新的进程需要0.1秒的时间,平均迁移时间是330毫秒。通过进程迁移可以将性能提高近5倍。


图1-3 进程迁移过程示意图
图1-3 进程迁移过程示意图

计算机系统的可靠性用平均无故障时间(MTTF)来度量,即计算机系统平均能够正常运行多长时间,才发生一次故障。系统的可靠性越高,平均无故障时间越 长。可维护性用平均维修时间(MTTR)来度量,即系统发生故障后维修和重新恢复正常运行平均花费的时间。系统的可维护性越好,平均维修时间越短。计算机 系统的可用性定义为:MTTF/(MTTF+MTTR) * 100%。由此可见,计算机系统的可用性定义为系统保持正常运行时间的百分比。

计算机产业界通常用如下表所示的"9"的个数来划分计算机系统可用性的类型。

可用性分类 可用水平 每年停机时间
容错可用性 99.9999 < 1 min
极高可用性 99.999 5 min
具有故障自动恢复能力的可用性 99.99 53 min
高可用性 99.9 8.8 h
商品可用性 99 43.8h

通过硬件冗余或软件的方法都可以从很大程度上提高系统的可用性。硬件冗余主要是通过在系统中维护多个冗余部件如硬盘、网线等来保证工作部件失效时可以继续 使用冗余部件来提供服务;而软件的方法是通过软件对集群中的多台机器的运行状态进行监测,在某台机器失效时启动备用机器接管失效机器的工作来继续提供服 务。

一般来说,需要保证集群管理器的高可用性和节点的高可用性。Eddie、Linux Virtual Server、Turbolinux、Piranha和Ultramonkey 都采用了类似于图1的高可用性解决方案。


图1 高可用性解决方案示意图
图1 高可用性解决方案示意图

集群管理器的高可用性

为了屏蔽集群管理器的失效,需要为它建立一个备份机。主管理器和备份管理器上都运行着heartbeat程序,通过传送诸如"我活着"这样的信息来监测对 方的运行状况。当备份机不能在一定的时间内收到这样的信息时,它就激活fake程序,让备份管理器接管主管理器继续提供服务;当备份管理器又从主管理器收 到"我活着"这样的信息时,它就使fake程序无效,从而释放IP地址,这样主管理器就开始再次进行集群管理的工作了。

节点的高可用性

节点的高可用性可以通过不断监视节点的状态以及节点上的应用程序的运行状态来实现,当发现节点已经失效时,可以重新配置系统并且将工作负载交给那些运行正 常的节点来完成。如图1所示,系统通过在集群管理器上运行mon精灵程序来监视集群中的实际服务器上的服务程序的运行状况。例如使用 fping.monitor 以一定的时间间隔来监视实际服务器是否还在正常运转;使用http.monitor 来监测http服务,使用ftp.monitor来监测ftp服务等等。如果发现某个实际服务器出了故障,或者是其上的服务已失败,则在集群管理器中删除 有关这个实际服务器的所有规则。反之,如果不久以后发现系统已经重新能够提供服务,则增加相应的所有规则。通过这种方法,集群管理器可以自动屏蔽服务器和 其上运行的服务程序的失效,并且当实际服务器正常运转时能将它们重新加入到集群系统中。

集群计算的发展需要发展并升级文件系统,此文件系统不仅能够对多个文件提供并行的访问,而且能在对同一文件进行访问的进程间提供cache一致性。大多数 传统的网络文件系统如NFS、AFS、Coda对于并行处理而言是远远不够的,因为它们都依赖中心文件服务器。但是,随着越来越多的客户的加入,服务器的 cpu很快就成为了性能的瓶颈。为了解决这个问题,处理能力更强的服务器已经被制造了出来,而且文件系统的设计者们也试图将更多的工作交给客户来完成,但 是即使是这样,服务器的速度仍然是文件系统可升级性的瓶颈。新一代的文件系统如Global File System(GFS) 、XFS和 Frangipani 比较适合于集群系统。因为这些系统都在集群系统中的机器上分配存储器、cache 和控制权,并且提供了并行文件访问和cache一致性的解决方法。

Coda文件系统

Coda文件系统(Coda File System)适用于分布式网络环境。它是在1987年在卡耐基梅隆大学以AFS2为原型开发出来的。Linux Virtual Server就采用了Coda文件系统。Coda提供了以下适用于网络文件系统的特性。

  1. 为移动的客户提供了断开操作。
  2. 它是一种自由软件。
  3. 通过客户访问的持续缓存提供了高可用性。
  4. 服务器复制功能。
  5. 提供了认证的安全模型、加密和访问控制。
  6. 部分网络失效后能够继续工作。
  7. 具有网络带宽适应性。
  8. 较好的可扩展性。
  9. 即使在网络失效时也为共享定义了良好的语法。

AFS和Coda文件系统都将所有的文件放于同一个目录下,如AFS 是/afs,Coda是 /coda,这意味着所有的客户都可以使用相同的配置,所有的用户看到的是相同的文件树。对于大的安装而言这是非常重要的。对于NFS文件系统而言,客户需要服务器的最新列表而在Coda中只需要找到根目录/coda。

当在客户端敲入"cat /coda/tmp/foo"这样的请求时,cat将调用系统调用向核心请求服务,核心首先找到对应的文件索引节点并返回与该文件相关的文件句柄。索引节 点包含文件的一些相关信息,文件句柄用于打开文件。系统调用首先进入核心的虚拟文件系统(VFS),然后它将请求传送给核心中的Coda文件系统模块进行 处理。Coda文件系统模块包含着从VFS来的最近的一些请求,然后它将此请求交给Coda缓冲管理器venus进行处理。Venus通过察看硬盘缓冲 区、向服务器发请求等方式来定位文件的所在地。如果在硬盘缓冲区中没有找到匹配的文件,则通过远程系统调用向服务器发请求,并且将取到的文件放在 cache中,这时,这个文件就是一个普通的文件了,因此可以通过本地文件系统对该文件进行读写的操作。如果在硬盘缓冲区找到了此文件,则可以直接使用这 个文件。当对此文件进行了一定的修改并且关闭了以后,venus将把新文件传送给服务器从而来更新服务器上的文件。其它的操作如修改文件系统,创建新目 录,删除文件,去除符号链接等都可以传送给服务器。

但是由于网络有时会出现问题,因此如何保证文件的连续性是一个非常重要的问题。当venus意识到服务器不可用时,它就将客户端对文件的更新存储在修改日志中,当服务器重新可用时,便根据修改日志对服务器上的相应的文件进行更新。

Global 文件系统

Global 文件系统(Global File System, GFS)允许多个Linux机器通过网络共享存储设备。每一台机器都可以将网络共享磁盘看作是本地磁盘,而且GFS自己也以本地文件系统的形式出现。如果 某台机器对某个文件执行了些操作,则后来访问此文件的机器就会读到写以后的结果。GFS文件系统的使用示意图如图1所示。


图1 GFS文件系统使用示意图
图1 GFS文件系统使用示意图

xFS文件系统

xFS试图通过将服务器的功能如保持cache的一致性、定位数据和处理磁盘请求分布在各个客户上来提供对文件系统数据的低延迟、高带宽的访问。

为了保持cache一致性,xFS采用了如下的方法。它将客户方的所有的内存空间看为一个大的cache,这样就减少了客户方的数据缓存,利用了闲置机器的内存,这种合作型的缓存可以通过减少到达磁盘的请求量来降低读延迟。

为了将定位数据的功能分布到每个客户端,xFS让每个客户都必须对文件的一个子集对应的请求进行处理。文件数据在多个客户端加以分类从而提供更高的带宽, 这些分类数据包括一些奇偶信息,通过这些信息可以在机器失效时恢复分类的数据报。这种方法可以保证没有任何节点会产生单点失效的情况。

MOSIX文件系统

MOSIX集群使用了自己的文件系统MFS文件系统。MFS将集群中的所有文件系统和目录都看作是一个文件系统,而且它提供了对所有节点上的所有文件系统的统一访问,它还通过只提供一个cache保证了cache的一致性。

MFS包含了许多位于不同节点上的文件子树,因此它就允许对多个文件进行并行操作和cache一致性。

在MOSIX集群中进行进程迁移时,如果此进程主要占用的是CPU资源,则迁移此进程对于提供系统性能是非常有效的,但是如果此进程需要进行大量的I/O操作,则迁移进程非常不利。这是因为每个I/O操作都需要与该进程原来所处的节点进行通讯。

因此MFS增加了对DFSA(Direct File System Acess)的支持。DFSA的目的就是让那些需要进行大量I/O操作的进程迁移到远端节点上,该远端节点拥有大多数I/O操作将会涉及到的文件,因此大 多数的I/O操作都能在远端节点上完成,而且在远端节点上可以通过本地访问来访问数据。如果一个系统调用是节点无关的,此系统调用就会在远端节点上执行, 否则就在本地执行。MFS比其它网络文件系统优越的地方就是它允许使用本地文件系统,这样就减少了进程和文件服务器之间的通讯开销。

OSI参考模型及TCP/IP参考模型

OSI模型(open system interconnection reference model)是基于国际标准化组织(ISO)的建议而发展起来的,它分为如图3-1所示的七层。当卫星和无线网络出现以后,现有的协议在和这些网络互联时出现了问题,所以需要一种新的参考体系结构,能无缝地连接多个网络。这个体系结构就是TCP/IP参考模型。


图3-1 OSI模型和TCP/IP 模型

TCP 协议

因特网在传输层有两种主要的协议:一种是面向连接的协议,一种是无连接的协议。传输控制协议TCP是(transmission control protocol)专门用于在不可靠的因特网上提供可靠的、端对端的字节流通信的协议。通过在发送方和接收方分别创建一个称为套接字的通信端口就可以获得TCP服务。所有的TCP 连接均是全双工的和点到点的。

发送和接收方TCP实体以数据报的形式交换数据。一个数据报包含一个固定的20字节的头、一个可选部分以及0或多字节的数据。对数据报的大小有两个限制条 件:首先,每个数据报(包括TCP头在内)必须适合IP的载荷能力,不能超过65535字节;其次,每个网络都存在最大传输单元MTU(maximum transfer unit),要求每个数据报必须适合MTU。如果一个数据报进入了一个MTU小于该数据报长度的网络,那么处于网络边界上的路由器会把该数据报分解为多个 小的数据报。

TCP实体所采用的基本协议是滑动窗口协议。当发送方传送一个数据报时,它将启动计时器。当该数据报到达目的地后,接收方的TCP实体向回发送一个数据 报,其中包含有一个确认序号,它等于希望收到的下一个数据报的顺序号。如果发送方的定时器在确认信息到达之前超时,那么发送方会重发该数据报。

2.1 TCP数据报头

图3-2给出了TCP数据报头的格式。


图3-2 TCP 头结构图

源端口、目的端口:16位长。标识出远端和本地的端口号。

顺序号:32位长。表明了发送的数据报的顺序。

确认号:32位长。希望收到的下一个数据报的序列号。

TCP头长:4位长。表明TCP头中包含多少个32位字。

接下来的6位未用。
ACK:ACK位置1表明确认号是合法的。如果ACK为0,那么数据报不包含确认信息,确认字段被省略。

PSH:表示是带有PUSH标志的数据。接收方因此请求数据报一到便可送往应用程序而不必等到缓冲区装满时才传送。

RST:用于复位由于主机崩溃或其它原因而出现的错误的连接。还可以用于拒绝非法的数据报或拒绝连接请求。

SYN:用于建立连接。

FIN:用于释放连接。

窗口大小:16位长。窗口大小字段表示在确认了字节之后还可以发送多少个字节。

校验和:16位长。是为了确保高可靠性而设置的。它校验头部、数据和伪TCP头部之和。

可选项:0个或多个32位字。包括最大TCP载荷,窗口比例、选择重发数据报等选项。

  1. 最大TCP载荷:允许每台主机设定其能够接受的最大的TCP载荷能力。在建立连接期间,双方均声明其最大载荷能力,并选取其中较小的作为标准。如果一台主机未使用该选项,那么其载荷能力缺省设置为536字节。
  2. 窗口比例:允许发送方和接收方商定一个合适的窗口比例因子。这一因子使滑动窗口最大能够达到232字节。
  3. 选择重发数据报:这个选项允许接收方请求发送指定的一个或多个数据报。

2.2 连接管理

在TCP中建立连接采用三次握手的方法。为了建立连接,其中一方,如服务器,通过执行LISTEN和ACCEPT原语被动地等待一个到达的连接请求。

另一方,如客户方,执行CONNECT原语,同时要指明它想连接到的IP地址和端口号,设置它能够接受的TCP数据报的最大值,以及一些可选的用户数据。CONNECT原语发送一个SYN=1,ACK=0的数据报到目的端,并等待对方响应。

该数据报到达目的端后,那里的TCP实体将察看是否有进程在侦听目的端口字段指定的端口。如果没有,它将发送一个RST=1的应答,拒绝建立该连接。

如果某个进程正在对该端口进行侦听,于是便将到达的TCP数据报交给该进程,它可以接受或拒绝建立连接。如果接受,便发回一个确认数据报。一般情况下,TCP的连接建立过程如图3-3所示。


图3-3 TCP的连接建立过程

为了释放连接,每方均可发送一个FIN=1的TCP数据报,表明本方已无数据发送。当FIN数据报被确认后,那个方向的连接即告关闭。当两个方向上的连接 均关闭后,该连接就被完全释放了。一般情况下,释放一个连接需要4个TCP数据报:每个方向均有一个FIN数据报和一个ACK数据报。

2.3 传输策略

TCP中采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方还有多大的缓冲区可以用于接收数据。发送方可以通过滑动窗口的大小来 确定应该发送多少字节的数据。当滑动窗口为0时,发送方一般不能再发送数据报,但有两种情况除外,一种情况是可以发送紧急数据,例如,允许用户终止在远端 机上的运行进程。另一种情况是发送方可以发送一个1字节的数据报来通知接收方重新声明它希望接收的下一字节及发送方的滑动窗口大小。

2.4 拥塞控制

当加载到某个网络上的载荷能力超过其处理能力时,便会出现拥塞现象。对于因特网来说有两个潜在的问题--网络的容量和接收方的容量,应该分别进行处理。发送方始终保持两个窗口:接收方承认的窗口和拥塞窗口。取两个窗口的最小值作为可以发送的字节数。

当建立连接时,发送方将拥塞窗口大小初始化为该连接所用的最大数据报的长度值,并随后发送一个最大长度的数据报。如果该数据报在定时器超时之前得到了确 认,那么发送方会在原拥塞窗口的基础上再增加一个数据报的字节值,使其为两倍最大数据报的大小,然后发送两个数据报。当这些数据报中的每一个都被确认后, 拥塞窗口大小就再增加一个最大数据报的长度。当拥塞窗口是N个数据报的大小时,如果发送的所有N个数据报都被及时确认,那么将拥塞窗口大小增加N个数据报 对应的字节数目。拥塞窗口保持指数规律增大,直到数据传输超时或者达到接收方设定的窗口大小。拥塞窗口便设置为恰好不造成超时或达到接收方的窗口大小的字 节数。

2.5 定时器管理

TCP使用多个定时器,如重发定时器、持续定时器、"keep alive"定时器等。 最重要的是重发定时器。在发送一个数据报的同时,启动一个数据重发定时器。如果在定时器超时前该数据报被确认,则关闭该定时器;相反,如果在确认到达之前定时器超时,则需要重发该数据报。

持续定时器用于防止出现死锁情况。 当一个连接长时间闲置时,"keep alive"定时器会超时而使一方去检测另一方是否仍然存在。如果它未得到响应,便终止该连接。

UDP协议

因特网协议组也支持无连接的传输协议UDP(user data protocol)。 UDP使用底层的因特网协议来传送报文,提供与IP一样的不可靠的、无连接的数据报传输服务。它不使用确认信息对报文的到达进行确认,不对收到的数据报进 行排序,也不提供反馈信息来控制机器之间传输的信息流量。UDP通信的可靠性方面的工作,包括报文的丢失、重复、乱序等现象,由使用UDP的应用程序来承 担。

一个UDP数据报包括一个8字节的头和数据部分。报头的格式如下图3-4所示,它包括四个长为16字节的字段。源端口和目的端口的作用与TCP中的相同, 是用来标明源端和目的端的端口号。UDP长度字段指明包括8个字节的头和数据在内的数据报长度。UDP校验和字段是可选项,用于纪录 UDP头、UDP伪头、用户数据三者的校验和。


图3-4 UDP头结构图

IP协议

IP协议提供了不可靠的、无连接的数据报传输机制。TCP/IP是为了适应物理网络的多样性而设计的,而这种适应性主要是通过IP层来体现的。由于物理网 络的多样性,各种物理网络的数据帧格式、地址格式之间的差异很大。为了将这些底层的细节屏蔽起来,使得采用不同物理网络的网络之间进行通讯, TCP/IP分别采用了IP数据报和IP地址作为物理数据帧与物理地址的统一描述形式。 这样IP向上层提供统一的IP数据报和统一的IP地址,使得各种物理帧及物理地址的差异性对上层协议不复存在。

4.1 IP数据报头

一个IP数据报由一个头部和数据部分构成。头部包括一个20字节的固定长度部分和一个可选任意长度部分。头部格式如图3-5所示。


图3-5 IP 头结构图

版本:4位长。记录了数据报对应的协议版本号。当前的IP协议有两个版本:IPV4 和IPV6。

IHL:4位长。代表头部的总长度,以32位字节为一个单位。

服务类型:8位长。使主机可以告诉子网它想要什么样的服务。如下图所示,服务类型域又分为了5个部分。优先权字段是标志优先级的;三个标志位分别代表延迟、吞吐量、可靠性。


总长:16位。指头部和数据的总长。最大长度是65535个字节。

标识:16位。通过它使目的主机判断新来的分段属于哪个分组,所有属于同一分组的分段包含同样的标识值。

DF:代表不要分段。它命令路由器不要将数据报分段,因为目的端不能重组分段。

MF:代表还有进一步的分段,用它来标志是否所有的分组都已到达。除了最后一个分段的所有分段都设置了这一位。

分段偏移:13位。标明分段在当前数据报的什么位置。

生命期:8位。用来限制分组生命周期的计数器。它在每个节点中都递减,而且当在一个路由器中排队时可以倍数递减。

协议:8位。说明将分组发送给那个传输进程,如TCR、VDP等。

头校验和:16位。仅用来校验头部。

源地址: 32位。产生IP数据报的源主机IP地址。

目的地址:32位。IP数据报的目的主机的IP地址。

可选项:是变长的。每个可选项用一个字节标明内容。有些可选项还跟有一字节的可选项长度字段,其后是一个或多个数据字节。现在已定义了安全性、严格的源路由选择、松的源路由选择、记录路由和时间标记五个可选项。但不是所有的路由器都支持全部5个可选项。

安全性选项说明了信息的安全程度。

严格的源路由选择选项以一系列的IP地址方式,给出了从源到目的地的完整路径。数据报必须严格地从这条路径传送。当路由选择表崩溃,系统管理员发送紧急分组时,或作时间测量时,此字段很有用。

松的源路由选择选项要求分组遍及所列的路由器,但它可以在其间穿过其它的路由器。

记录路由选项让沿途的路由器都将其IP地址加到可选字段之后,这使系统管理者可以跟踪路由选择算法的错误。

时间标记选项像记录路由选项一样,除了记录32位的IP地址外,每个路由器还要记录一个32位的时间标记。同样地,这一选择可用来为路由选择算法查错。

4.2 IP数据报的分段与重组

IP数据报是通过封装为物理帧来传输的。由于因特网是通过各种不同物理网络技术互连起来的,在因特网的不同部分,物理帧的大小(最大传 输单元MTU)可能各不相同。为了最大程度的利用物理网络的能力,IP模块以所在的物理网络的MTU做为依据,来确定IP数据报的大小。当IP数据报在两 个不同MTU的网络之间传输时,就可能出现IP数据报的分段与重组操作。

在IP头中控制分段和重组的IP头域有三个:标识域、标志域、分段偏移域。标识是源主机赋予IP数据报的标识符。目的主机根据标识域来判断收到的IP数据 报分段属于哪一个数据报,以进行IP数据报重组。标志域中的DF位标识该IP数据报是否允许分段。当需要对IP数据报进行分段时,如果DF位置1,网关将 会抛弃该IP数据报,并向源主机发送出错信息。标志域中的MF位标识该IP数据报分段是否是最后一个分段。分段偏移域记录了该IP数据报分段在原IP数据 报中的偏移量。偏移量是8字节的整数倍。分段偏移域被用来确定该IP数据报分段在IP数据报重组时的顺序。

IP数据报在被传输过程中,一旦被分段,各段就作为独立的IP数据报进行传输,在到达目的主机之前有可能会被再次或多次分段。但是IP数据报分段的重组都只在目的主机进行。

4.3 IP对输入数据报的处理

IP对输入数据报的处理分为两种,一种是主机对数据报的处理,一种是网关对数据报的处理。

当IP数据报到达主机时,如果IP数据报的目的地址与主机地址匹配,IP接收该数据报并将它传给高级协议软件处理;否则抛弃该IP数据报。

网关则不同,当IP数据报到达网关IP层后,网关首先判断本机是否是数据报到达的目的主机。如果是,网关将接收到的IP数据报上传给高级协议软件处理。如果不是,网关将对接收到的IP数据报进行寻径,并随后将其转发出去。

4.4 IP对输出数据报的处理

IP对输出数据报的处理也分为两种,一种是主机对数据报的处理,一种是网关对数据报的处理。

对于网关来说,IP接收到IP数据报后,经过寻径,找到该IP数据报的传输路径。该路径实际上是全路径中的下一个网关的IP地址。然后,该网关将该IP数 据报和寻径到的下一个网关的地址交给网络接口软件。网络接口软件收到IP数据报和下一个网关地址后,首先调用ARP完成下一个网关IP地址到物理地址的映 射,然后将IP数据报封装成帧,最后由子网完成数据报的物理传输。

ICMP协议

ICMP(Internet Control Message Protocol)-因特网控制报文协议。ICMP主要用于差错信息和控制信息的构造及某些网络信息的获取。ICMP与IP 同属IP层,但ICMP报文是经IP封装后,作为IP数据报发送出去的。不把ICMP作为一个独立的协议层次,是因为ICMP不是上层协议的基础,在概念上构不成一个独立的层次。

ICMP消息包括以下类型:目的不可达、超时、参数问题、源端抑制、重定向、回声请求、回声应答、时间标记请求、时间标记应答。

目的不可达消息用来报告子网或路由器不能定位目的地,或设置了DF位的分组不能绕过"小分组"网络。

超时消息用来报告报文由于计时器为零而被丢弃。

参数问题消息表明在头部字段中发现了非法值。

源端抑制消息用来抑制发送过多分组的主机。当主机收到这个消息,就要减慢发送速度。

重定向消息在路由器发现可能出现了路由错误时发送。

回声请求和回声应答消息用来测试目的是否可达且正常运行。收到回声请求消息,目的端应该往回发一个回声应答消息。时间标记请求和时间标记应答与此类似,只是消息到达时间和应答发出时间应加入应答中,其好处是可以用来测试网络性能。

IP在Linux上的实现

如图3-6所示,Linux以分层的软件结构实现了TCP/IP协议。BSD套接字由一般性的套接字管理软件INET套接字层支持。INET套接字管理着 基于IP的TCP或UDP协议端。在传输UDP数据报时,Linux不必关心数据报是否安全到达目的端。但对TCP数据报来说,Linux需要对数据报进 行编号,数据报的源端和目的端需要协调工作,以便保证数据报不会丢失,或以错误的顺序发送。IP层包含的代码需要处理数据报的报头信息,并且必须将传入的 数据报发送到TCP或 UDP两者中正确的一层处理。在IP层之下是Linux的网络设备层,其中包括以太网设备或PPP设备等。和Linux系统中的其它设备不同,网络设备并 不总代表实际的物理设备,例如,回环设备就是一个纯软件设备。ARP协议提供地址解析功能,因此它处于IP层和网络设备层之间。


图3-6 Linux网络分层结构图

6.1 套接字缓冲区

Linux利用套接字缓冲区在协议层和网络设备之间传送数据。Sk_buff包含了一些指针和长度信息,从而可让协议层以标准的函数或 方法对应用程序的数据进行处理。如图3-7所示,每个sk_buff均包含一个数据块、四个数据指针以及两个长度字段。利用四个数据指针,各协议层可操纵 和管理套接字缓冲区的数据,这四个指针的用途如下。

Head:指向内存中数据区的起始地址。Sk_buff和相关数据块在分配之后,该指针的值是固定的。

Data:指向协议数据的当前起始地址。该指针的值随当前拥有Sk_buff的协议层的变化而变化。

Tail:指向协议数据的当前结尾地址。和data指针一样,该指针的值也随当前拥有Sk_buff的协议层的变化而变化。

End:指向内存中数据区的结尾。和head指针一样,Sk_buff被分配之后,该指针的值也固定不变。

Sk_buff的两个长度字段,len和truesize,分别描述当前协议数据报的长度和数据缓冲区的实际长度。


图3-7 sk_buff结构图

6.2 接收IP数据报

当网络设备从网络上接收到数据报时,它必须将接收到的数据转换为sk_buff数据结构,然后将该结构添加到backlog队列中排 队。当backlog队列变得很大时,接收到的sk_buff数据将会被丢弃。当新的sk_buff添加到backlog队列时,网络底层程序将被标志为 就绪状态,从而可以让调度程序调度底层程序进行处理。

调度程序最终会运行网络的底层处理程序。这时,网络底层处理程序将处理任何等待传输的数据报,但在这之前,底层处理程序首先会处理sk_buff结构的backlog队列。底层处理程序必须确定将接收到的数据报传递到哪个协议层。

在Linux进行网络层的初始化时,每个协议要在ptype_all链表或ptype_base哈希表中添加packet_type数据结构以进行注册。 Packet_type数据结构包含协议类型、指向网络设备的指针、指向协议的接收数据处理例程的指针等 。Ptype_base是一个哈希表,其哈希函数以协议标识符为参数,内核通常利用该哈希表判断应当接受传入的网络数据报的协议。通过检查 ptype_all链表和ptype_base哈希表,网络底层处理程序会复制新的sk_buff,最终,sk_buff会传递到一个或多个目标协议的处 理例程。

6.3 发送IP 数据报

网络处理代码必须建立sk_buff来包含要传输的数据,并且在协议层之间传递数据时,需要添加不同的协议头和协议尾。

首先,IP协议需要决定要使用的网络设备,网络设备的选择依赖于数据报的最佳路由。对于只利用调制解调器和PPP协议连接的计算机来说,路由的选择比较容易,但是对于连接到以太网的计算机来说,路由的选择是比较复杂的。

对每个要传输的IP数据报,IP利用路由表解析目标IP地址的路由。对每个可从路由表中找到路由的目标IP地址,路由表返回一个rtable数据结构描述 可使用的路由。这包括要使用的源地址、网络设备的device数据结构的地址以及预先建立的硬件头信息。该硬件头信息和网络设备相关,包含了源和目标的物 理地址以及其它的介质信息。

6.4 数据报的分段与重组

当传输IP数据报时,IP从IP路由表中找到发送该IP数据报的网络设备,网络设备对应的device数据结构中包含由一个mtu字 段,该字段描述最大的传输单元。如果设备的mtu小于等待发送的IP数据报的大小,就需要将该IP数据报划分为小的片断。每个片断由一个sk_buff代 表,其中的IP头标记为数据报片断,以及该片断在IP数据报中的偏移。最后的数据报被标志为最后的IP片断。如果分段过程中IP不能分配sk_buff, 则传输失败。

IP片断的接收较片断的发送更加复杂一些,因为IP片断可能以任意的顺序接收到,而在重组之前,必须接受到所有的片断。每次接收到IP数据报时,IP 要检查是否是一个分段数据报。当第一次接收到分段的消息时,IP建立一个新的ipq数据结构,并将它链接到由等待重组的IP片断形成的ipqueue链表 中。随着其他IP片断的接收,IP找到正确的ipq数据结构,同时建立新的ipfrag数据结构描述该片断。每个ipq数据结构中包含有其源和目标IP地 址、高层协议的标识符以及该IP帧的标识符,从而唯一描述了一个分段的IP接收帧。当所有的片断接收到之后,它们被组合成单一的sk_buff并传递到上 一级协议层处理。如果定时器在所有的片断到达之前到期,ipq数据结构和ipfrag被丢弃,并假定消息已经在传输中丢失,这时,高层协议需要请求源主机 重新发送丢失的信息。

在计算机硬件价格下降、计算机网络拓扑发展的情况下,分布式计算机系统给用户提供了一个丰富的资源集合。人们在研究分布式系统时,就注意到了这样一个问 题:在一个由网络连接起来的多计算机环境中,在某一时刻,一些计算机的负载比较重,而另外一些计算机的负载却比较轻。平衡各计算机之间的负载是任务分配与 调度的一个主要目标,它能够提高整个系统的性能。

为了改善系统的性能,通过在多台计算机之间合理地分配负载,使各台计算机的负载基本均衡,这种计算能力共享的形式,通常被称为负载平衡或负载共享。一般来说,"负载平衡"要达到的目标是使各台计算机之间的负载基本均衡,而"负载共享"意味着只是简单的负载的重新分配。

负载平衡包括两种,一种是静态负载平衡,一种是动态负载平衡。只是利用系统负载的平均信息,而忽视系统当前的负载状况的方法被称为静态负载平衡。根据系统当前的负载状况来调整任务划分的方法被称为动态负载平衡。

导致负载不平衡主要是由于:

  1. 某些算法的迭代大小不是固定的,但迭代的大小在编译时却可以被求得;
  2. 某些算法的迭代大小不是固定的,并且迭代的大小依赖于被处理的数据,在编译时无法求得;
  3. 即使迭代大小是固定的,也会有许多不定因素导致计算速度的差异。

考察这三个原因,对第一种情况可在编译时估计各迭代的工作量,按照处理节点的处理能力分布迭代,这就是静态负载平衡的方法。对第二、三种情况来说,必须采 用动态负载平衡的手段,在运行过程中根据各个处理节点完成任务的情况,动态地迁移任务,实现动态负载平衡。进行动态负载平衡需要考察处理节点的处理能力, 它的基本依据是根据处理节点先前的处理速度预见未来的处理速度。

负载平衡算法

一个负载平衡算法都包含以下三个组成部分:

  1. 信息策略:制定任务放置策略的制定者使用的负载和任务量,以及信息分配的方式。
  2. 传送策略:基于任务和计算机负载,判断是否要把一个任务传送到其它计算机上处理。
  3. 放置策略:对于适合传送到其它计算机处理的任务,选择任务将被传送的目的计算机。

负载平衡的上述三个部分之间是以不同的方式相互作用的。放置策略利用信息策略提供的负载信息,仅当任务被传送策略判断为适于传送之后才行动。

总之,负载平衡的目标是:提供最短的平均任务响应时间; 能适于变化的负载;是可靠的负载平衡机制。

信息策略

人们用来描述负载信息采用的参数有:

  1. 运行队列中的任务数;
  2. 系统调用的速率;
  3. CPU上下文切换率;
  4. 空闲CPU时间百分比;
  5. 空闲存储器的大小(K字节);
  6. 1分钟内的平均负载。对于这些单个的负载描述参数,第(1)个,即采用运行队列中的任务数作为描述负载的参数被证明是最有效的,即它的平均任务响应时间最 短,并且已经得到广泛应用。但是,如果为了使系统信息更全面而采集了更多的参数,则往往由于增加了额外开销,却得不到所希望的性能改善。例如,采用将六个 参数中的某两个进行"AND"或"OR"组合,得到的平均响应时间反而比单个参数的平均响应时间还要差一些。

传送策略

为了简单起见,在选用传送策略时,多选用阀值策略。例如,Eager等人的方法是:在判断是否要在本地处理一个任务时,无需交换计算机之间的状态信息,一 旦服务队列或等待服务队列的长度大于阀值时,就传送这个任务,而且传送的是刚刚接收的任务。而进程迁移能够迁移正在执行的任务,是对这种只能传送刚刚接收 的任务的一种改进。

Zhou在模拟研究七个负载平衡算法时,其传送策略都采用阀值策略。它的阀值策略基于两个阀值∶计算机的负载阀值Load和任务执行时间阀值TCPU。如果计算机的负载超过Load并且任务的执行时间超过TCPU时,就把此任务传送到其它计算机执行。

放置策略

经过总结,共有以下四种放置策略。

  1. 集中策略。每隔P秒,其中一个计算机被指定为"负载信息中心"(LIC),接受所有其它负载的变更值,并把它们汇集到一个"负载向量"中,然后把负载向量 广播给所有其它的计算机。当一台计算机认为一个任务适于传送到其它计算机上执行时,它就给LIC发送一个请求,并告知当前负载的值。LIC选一台具有最短 运行队列长度的计算机,并且通知任务所在的计算机把任务发送给它,同时,它把目的主机负载值增加1。
  2. 阀值策略。随机选择一台计算机,判断若把任务传送到那台计算机后,那台计算机的任务队列长度是否会超过阀值。如果不超过阀值,就传送此任务;否则,随机选 择另一台计算机,并以同样方式判断,继续这样做直到找到一台合适的目的计算机,或探测次数超过一个静态值限制LP,当任务真正到达计算机以后,不管状态如 何,必须处理该任务。
  3. 最短任务队列策略。随机选择LP台不同的计算机,察看每台计算机的任务队列长度,任务被传送到具有最短任务队列长度的计算机。当任务真正到达计算机,无论 状态如何,目的计算机必须处理该任务。对此策略的一个简单改进时,无论何时,遇到一台队列长度为0的计算机时,不再继续探测,因为可以确定此计算机是一台 可以接受的目的计算机。
  4. 保留策略。 当一个任务从一台计算机离开时,该计算机检查本地负载,如果负载小于阀值T1,就探测其它计算机,并在R个负载大于T1的计算机中登记该计算机的名字,并 把登记的内容保留到一个栈中。当一个任务到达一台超载的计算机时,就把这个任务传送到此台计算机栈顶的计算机上。如果一个计算机的负载低于T1,就清空栈 里保留的所有计算机名。

Zhou的论文中,比较了(2)和(3) 三种策略,结论是:以简单(计算不昂贵)的方式,利用少量状态信息,第(2)中方法往往获得比第(3)种方法更好的效果。第(3)中方法比较复杂,它必须用性能的改善来补偿额外花费,所以取得的效果会稍差一些[2]。

算法实现

目前,常见的算法有:中心任务调度策略、梯度模型策略、发送者启动策略和接收者启动策略。

  1. 中心任务调度策略

    顾名思义,中心任务调度策略就是让一个特定的处理节点担任计算任务分配器的角色,我们称之为调度节点,而把其它完成计算任务的处理节点称作计算节点。调度节点为了掌握任务分布情况,需要维护一个任务分布表。

    在任务启动时,调度节点装入任务的预分布情况表,而计算节点则开始完成分配给它的计算任务。在执行过程中,计算节点按照一定的周期向调度节点提交计算任务 完成情况,由调度节点根据这些信息判断处理节点的处理能力,发出任务迁移指令,控制任务从重负载节点向轻负载节点流动,同时还要随之更新在调度节点上的任 务分布表。

    中心任务调度的优点显而易见:调度节点掌握所有节点的处理能力和任务的分布情况,因此它可以在综合各种因素的基础上找到最佳的任务迁移方式。但是在计算节 点很多时,所有计算机点都必然与中心节点通讯,必然导致严重的冲突,这会大大降低动态负载平衡的效率,甚至抵消动态负载平衡所带来的一切好处。

    另外,还应该注意到,调度节点在判断是否进行任务迁移时,计算节点必须等待,这无疑又浪费了计算节点的处理能力。一种改进的方法是调度节点在收到计算节点 的当前任务完成情况时,立即存储之,并把根据上次的信息做出的判断返回给计算节点以减少延迟,在空闲时再根据本次收到的信息做出判断,留到下次使用。这样 就把调度节点进行任务迁移决策的时间和计算节点完成计算任务的时间重叠了起来,降低了动态负载平衡的开销。

  2. 梯度模型策略

    在中心任务调度策略中,计算节点越多,冲突就越多。为了减少冲突,适应大量处理节点的需要。梯度模型策略、发送者启动策略和接收者启动策略都不设置专用的调度节点,而且每个节点只与一部分节点进行交互,以减少由负载平衡导致的冲突。

    在梯度模型策略中,所有处理节点仅与直接相邻的节点进行交互,并引入两个阀值:M 1 和Mh。在运行过程中,我们将所在节点划分成三类:设一个节点的剩余任务量为t,如果t < M 1则称之为轻负载节点;如果M 1< t < M h则称之为中负载节点;如果t > M h则称之为重负载节点。另外,把从一个节点到与之最接近的轻负载节点的最短距离定义为这个节点的梯度。

    在启动时,每个节点都是重负载节点,梯度都是无穷大。在计算过程中,周期性地检查其剩余负载是否大于M1。当某一节点发现自身剩余的负载小于M1时就把它 的梯度设为零,随后把自身当前的梯度与相邻节点间的距离之和发送给相邻的节点。相邻的节点接收到这个新梯度,就与自身当前梯度进行比较。 如果自身梯度小于等于新梯度,则不做任何事;如果自身梯度大于新梯度,则将自身梯度设置为新梯度,并向发送给它新梯度信息的节点一样传播新梯度。这样,梯 度信息(实际上就是计算任务完成的情况)就会被传播开来,重负载节点就可以把它多余的负载发送给向临界点中梯度最小的节点。于是,计算任务就在梯度的引导 之下从重负载节点流向轻负载节点。

    可是,按照这种方式,有可能导致过多的计算任务涌向一个轻负载节点。如果轻负载节点接收了过多的新任务,就有可能重新变成中负载甚至重负载节点。一旦出现 这种情况,梯度信息就不再能够正确地引导计算任务了。为此,必须使轻负载节点察看要接受的计算任务,如果接收计算任务使本节点脱离轻节点状态,就拒绝接受 它。这虽然延迟了任务的接收,但随着时间的推移,轻负载节点实际上不久就可以接受被它拒绝接受的任务了,同时还可以保持节点的梯度的有效性。

  3. 发送者启动策略

    发送者启动策略也引入了一个阀值M来把所有的处理节点划分成轻负载节点和重负载节点,所有当前剩余负载t > M的节点都被称为重负载节点,t < M的节点被称为轻负载节点。发送者启动策略还需要为每个节点定义一个相关域,节点只与它的相关域中的节点进行交互和任务传递。一个直观的相关域的定义是把所有与之相邻的节点作为相关域。

    在启动时,所有节点开始执行计算任务。在执行一段时间之后,节点就开始检查其自身是否是重负载节点。如果是重负载节点,则它就试图在相关域中均匀地分布任务。具体地:设该重负载节点的负载为l p,相关域中有K个节点,其负载分别为l 1,……., l k,则平均负载L avg为:



    为了达到均匀分布,应求得重负载节点应该传递给每个相关域中节点的负载量m k。我们首先引入h k以避免负载被迁移到相关域中负载最重的重负载节点。如果L avg> l k,则 ,否则h k= 0。那么m k



    随后该节点就可以按照m k向各个相关节点发送任务了。

  4. 接收者启动策略

    接收者启动策略与发送者启动策略除了是由轻负载节点启动,要求其它节点把任务发送给它之外,其它基本相同。

    接收者启动策略同样引入M以区分轻、重负载节点,引入相关域以确定交互范围。

    在启动时,所有节点开始执行计算任务,经过一段时间之后,一旦某个节点发现自身成为轻负载节点,就试图在它的相关域中均匀地分布负载。具体地:设该轻负载节点的负载为l p ,相关域中有K个节点,其负载分别为l 1 ,……., l k,则平均负载L avg为:



    为了达到均匀分布,应求得相关域中节点应该传递给轻负载节点的负载量m k。我们首先引入权h k以避免负载从负载更轻的相关域中的节点被迁移到该节点。如果L avg< l k, 则 , 否则h k=0。那么m k为:



    随后该节点就可以按照m k发出接受任务的请求了。

近年来,Internet的发展步入黄金时期,网上信息交换的数量正在呈指数形式的增长。特别是,由于电子商务的蓬勃发展,人们已经预计在下一世纪,网上消费将成为日常生活的重要形式。

随着网络硬件设备的飞速进步,网络带宽的瓶颈效应日趋减弱,WEB服务器的性能问题逐渐显现出来。单一的服务器系统处理客户请求的能力有限,如何处理快速增长的客户请求,是当前研究人员关注的重要问题。从目前的研究方向看,服务器方向的研究可以归结为两个方面:

  1. 从实现机制上入手。主要研究Caching技术、预取技术等。这方面的研究主要从客户访问行为分析入手,研究可以缩小响应时间的方法,这些技术可以在现有服务器设备的基础上尽可能地提高系统的性能,但性能提高的程度有限。
  2. 从体系结构入手。将过去单一的服务器结构扩充为集群式服务器结构。这种改造可能需要增加较大的开销,但可以显著提高服务器的总体性能。
体系结构研究 软件技术研究
单机服务器 协议分析
缓存机制Caching
预取技术Pre-fetching
请求调度
集群服务器 节点分发

就某一商业Web站点而言,人们通常会认为,日访问人数越多,说明销售的潜力越大,潜在的购买者越多。但统计结果向我们显示的却是另一种结果。随着日访问 人数的增加,销售量上升到一定程度后,反而下降。图1给出的是某汽车销售网站网上销售的模拟计算结果。注意,当网站日查询业务量为正常的120%或更高 时,访问的服务时间明显增长,使得日收益反而比正常情况下降很多。

图1:某汽车销售商网上销售模拟计算结果

  正常 正常+10% 正常+20% 正常+30%
日查询业务量 92448 101693 110938 120182
服务器响应时间 2.86 3.80 5.67 11.28
损失交易比例 0 0 60% 95%
每日交易量 4622 5085 2219 300
日收入 83203 91524 39938 5408
可能的日收益 83203 91524 99844 108164
损失的日收益     59906 102756

究其原因,我们不难发现,服务器的性能是导致这种现象的最根本的原因。当服务器负载接近边界时,负载的一个小小的增长都有可能使服务器陷入象死锁那样的一 种境地。由此可以得出,如何优化Web服务器性能将是今后一段时间研究的一个热点。许多服务器制造商都在努力推出性能更加优良的服务器,但是单一服务器结 构有一个致命的缺陷,那就是由于服务器的处理能力有限,有可能会出现死锁的情况。死锁的产生是由于新请求的到达率大于系统服务率,系统没有能力在短期内处 理所有的请求,导致等待队列溢出,系统 稳定状态转为不稳定状态,最后崩溃。集群服务器具有良好的可扩展性,可以随着负载的增大动态地向集群中增加服务器,从而就避免了由于处理能力不足而导致的 系统崩溃。

粗粒度分发策略

在集群系统中,粒度指的是负载调度和迁移的单位。集群系统中的粗粒度指的是调度和迁移的单位是服务,而细粒度指的是进程。目前,关于集群式服务器的研究主 要集中在体系结构和负载平衡策略的研究上,其中负载平衡策略的研究又是体系结构研究的基础。早期的集群式服务器系统常采用Round-Robin DNS算法实现客户请求的分发。实际上是一种粗粒度的负载分配策略。

1.1 工作原理

正常情况下,域名服务器将主机名映射为一个IP地址,为了改善负载平衡状况,早期的集群服务器系统采用RR-DNS(Round-Robin DNS)调度算法将一个域名映射为一组IP地址,允许客户端链接到服务器集群中的某一台服务器上,由此提供了服务器站点的伸缩性。一些可伸缩Web服务器(例如Eddie和NCSA的Scalable Web Server)采用RR-DNS实现负载平衡,一些高吞吐率的站点(Yahoo)也继续采用这种简单应用。图2为这类服务器结构的工作原理图。


图 2 基于DNS机制的集群服务器结构
图 2 基于DNS机制的集群服务器结构

RR-DNS在解析域名时,附加一个生存期(TTL:Time-To-Live),这样一个请求生成后TTL时间内没有获得应答信息,可以向RR-DNS获取不同的IP地址。

1.2 工作流程

  1. 客户发出地址请求(URL)
    地址请求报文到达DNS
  2. DNS选择服务器IP地址和TTL
  3. 地址映象(URL->ADDRESS 1)
    地址映象(URL->ADDRESS 1)
  4. 客户向服务器1发出文档请求
  5. 服务器1响应客户的文档请求

1.3 存在缺陷

在一个TTL时期内,多个域名请求将被映射到相同的IP地址,这样大量的客户端请求可能出现在同一服务器上,导致明显的负载失衡。如果TTL很小,又会明显增加域名解析的网络负载。

另一个相关问题是由于客户端缓存域名-IP地址解析结果,客户端可以在未来的任意时刻发送请求,导致服务器的负载无法得到控制,出现服务器负载失衡。

1.4 相关算法研究

为解决请求的负载分布均衡问题,研究者对RR-DNS算法进行了多种改进,这些改进依据TTL的设定形式可分为TTL恒定算法和自适应TTL算法。

TTL恒定算法 TTL恒定算法根据用户使用系统状态信息的情况又可分为系统无状态算法、基于服务器状态算法、基于客户状态算法和基于服务器/客户状态算法。

  1. SSL:系统无状态算法system-stateless algorithm

    系统无状态算法指DNS服务器按固定时间间隔将客户请求分发到不同服务器上。例如时刻 时刻 的客户接受服务器k1的服务,时刻 时刻 的客户接受服务器k2的服务,式中的 为TTL值。客户获取服务器地址后,将地址缓存在客户端,然后根据需要,向服务器发请求。

    使用系统无状态算法,DNS只能控制部分请求的流向,由于不考虑服务器的容量和可用性,以及客户请求到达的不确定性,导致服务器超载或将请求发送到不可用服务器上,此算法性能很差,没有实用价值。

  2. SSB:基于服务器状态算法Server-state-based algorithm

    获取服务器状态的目的是为了选择可用性更高的服务器处理客户请求,防止服务器阻塞或服务失败。服务器状态算法需要使用简单的服务器侦听机制(例如心跳协议 等)对服务器状态进行定时跟踪。当客户请求到达时,将负载最轻的服务器地址映射给客户端。SUN-SCALR在实现上就是采用这种机制。

  3. CSB:基于客户状态算法Client-state-based algorithm

    来自客户端的信息可归结为客户访问的平均负载状况和客户分布情况。如果不考虑客户的优先级高低,CSB算法使用HLW(hidden load weight)参量描述新客户的到达率(TTL周期内,访问服务器的新客户数量),根据新客户到达率,进行服务器分配,这类算法的典型代表是MRRP(multitier round-robin policy)。

    另外,Cisco的Distributed Director在实现上也采用CSB策略,Distributed Director在服务器集群中充当主域名服务器,根据客户-服务器的拓扑距离和新客户到达率,选择最适合的服务器分发给客户。

  4. SCSB:基于服务器/客户状态的算法server and client state based algorithm

    在DNS算法中,同时使用服务器状态和客户状态信息时,获得的性能往往是最高的。例如Distributed Director的DNS算法以服务器可用信息和客户的距离信息为指标分配处理服务器。当节点服务器超载,服务器发送异步警报反馈信息给DNS控制器,控 制器将此服务器从可用服务器表中剔除,根据客户状态信息选择最有利的服务器处理客户请求。使用此算法需要对服务器状态进行动态分析和预测。

  5. WRR:带有权重的RR算法 Weight Round-Robin algorithm

    根据各台实际服务器的处理能力给它们分配不同的权重,使具有相同权重的服务器获得链接的概率相同,高权重的服务器获得链接的概率比低权重服务器获得链接的概率大。

自适应TTL算法[20]
为平衡多服务器节点的负载,特别是异构服务器的负载,人们提出了自适应的TTL算法。这类算法使用基于服务器/客户状态DNS策略选择节点服务器,并动态 调整TTL值。在异构服务器集群中,根据各服务器容量不同,设置的TTL值也不完全相同,由此控制因负载不对称造成的超载问题。

自适应TTL算法使用两步表决机制:首先DNS选择服务器的方法和基于客户状态算法相似;第二步,DNS根据负载分布情况、服务器处理能力和服务器的繁忙程度选择合适的TTL值,服务器越忙,设定的TTL值越小。

另外,自适应TTL算法的可扩展性很强,算法实现中的数据都可以动态获得。使用自适应TTL算法可以使服务器集群比较容易地从局域网拓展到广域网。

1.5 DNS算法比较

由于客户端和中间域名服务器缓存URL-IP地址映射,使用服务器状态信息的DNS算法不能保证负载平衡[15],每个地址缓存都有可能引发大量的客户请求阻塞集群中的某个服务器节点。因此,合理地预测客户请求的到达率对于选择服务器更加有效。

使用客户到达率信息和服务器监听的调度算法可以获得更高可用性的服务器。但是这种算法明显不适于异构型集群服务器。

为平衡分布系统的请求负载,自适应TTL算法是最可靠、有效的。但是,这种算法忽略了客户-服务器距离的重要性。

算法名称 优点 缺点
固定 TTL 算法 系统无状态算法 简单 不实用
基于服务器状态算法 提高服务器可用性 不能保证负载均衡
基于客户状态算法    
基于服务器/客户状态算法 可以获得更高可用性的服务器 不适于异构型集群服务器
自适应TTL算法 DNS算法中可靠性最好、效率最高的算法 忽略了客户-服务器距离的重要性

细粒度分发策略

为实现客户请求的集中调度和完全路由控制,采用细粒度负载分配策略的服务器结构中必须包含一个路由器节点──平衡器(可能是一个硬件路由器或集群服务器中配置专用软件的节点)接收发向Web站点的所有请求,根据某种负载平衡算法将请求转发到不同的服务器节点上。

与基于DNS的体系结构不同的是,平衡器采用单一的、虚拟IP地址IP-SVA(single virtual IP adress),这个IP地址是众所周知的一个IP地址,而节点服务器的实际地址对用户是透明的。由于此机制是在URL层进行请求的处理,Web页中包含的多个目标,可以由集群中的不同节点提供,这样提供了比RR-DNS更细粒度的控制策略。

根据路由机制的不同,细粒度负载分配策略又可分为报文重写(单向重写或双向重写)、报文转发和HTTP重定向。

2.1 PDR:报文双向重写策略

PDR采用集中调度方式完成客户请求的路由控制,服务器系统的平衡器负责客户请求的接收、分发和结果的返回工作。与RR-DNS策略不 同,平衡器在IP层进行地址重写,使用动态地址映射表,实现客户请求的重定向。采用单一的虚拟IP地址(IP-SVA),用户可见的只是平衡器,节点服务 器是透明的。在选择节点服务器时采用的调度策略主要有:Round Robin(轮转)、Weighted Round Robin(加权轮转)、Least Connection(最少连接)和Weighted Least Connection(加权最少连接)。平衡器将客户和节点服务器的映射添加到映射表中,这样就保证了同一客户的所有请求都发送到同一台节点服务器上,从 而保证了访问的持续性。采用PDR策略的典型代表是Cisco的Local Director,从路由机制上看,Local Director当前采用最少连接数策略。图1-3给出了Local Director处理客户请求的原理图。


图 3 LocalDirector原理图
图 3 LocalDirector原理图

工作流程

  1. 客户向服务器发出请求
  2. 平衡器选择客户请求的处理节点
  3. 将客户请求的目的IP地址(IP-SVA)改写为节点服务器地址(address1)
  4. 将客户请求发送给处理节点
  5. 处理节点将结果返回给平衡器
  6. 平衡器将应答报文的源IP地址(address1)改写为IP-SVA
  7. 客户接收应答报文

性能分析
与粗粒度负载平衡策略不同,PDR在IP级进行负载平衡分配,这样就省去了从应用层到IP层的通讯开销,因此有效缩短了服务器处理时间。较DNS机制,性能提高很大。但是这种策略也存在如下问题:

  1. 平衡器容量有限,导致系统可伸缩性不高。另外,平衡器可能成为整个服务器集群的瓶颈。
  2. 此机制只适于在局域网范围内实现。

2.2 PSR:报文单向重写策略

在某些体系结构中,平衡器对接收的客户请求进行二次路由,将客户报文的目的IP地址改写为实际处理节点的IP地址,例如基本的TCP路由机制[15]。

在TCP路由机制中,服务器集群由一组节点服务器和一个TCP路由器组成,TCP路由器充当IP地址平衡器。当客户请求到达TCP路由器时,由于IP- SVA是唯一公开的IP地址,平衡器将请求报文中的目标IP地址重写为节点服务器的私有IP地址。由于一个客户请求可能是由多个报文构成,TCP路由器在 地址表中记录客户(具有相同的源IP地址)与执行服务器的地址映射,保证来自同一客户的所有报文都能到达同一台节点服务器。服务器在发送应答报文给客户 时,将平衡器的IP-SVA写入源IP地址,这样客户并不知道请求是由隐藏的执行服务器完成。图4给出了服务器使用报文单向重写策略时,客户请求的执行过 程。

工作流程:

  1. 客户向服务器发出请求
  2. 平衡器进行地址解析,选择执行服务器
  3. 平衡器用执行服务器的私有地址(address1)替换客户请求报文的目的IP地址
  4. 客户请求报文二次路由,到达执行服务器
  5. 执行服务器处理客户请求,并将IP-SVA写入应答报文的源IP地址中
  6. 客户接收应答报文


图 4:报文单向重写示意图
图 4:报文单向重写示意图

性能分析
使用报文单向重写机制可以提高系统可用性程度,当平衡器节点出现故障时,路由表可以由原平衡器迁移到新的服务器上,服务器的结构也可以从局域网拓展到广域网。但是这种机制导致服务器结构透明性较差,而且执行服务器和平衡器在判断客户请求是否结束上存在困难。

2.3 PF:报文转发

由于报文重写增加了平衡器处理请求的复杂度,导致平衡器负载加重,研究者提出了报文转发策略(PF)。采用PF策略,平衡器和执行服务 器共用一个IP-SVA地址,客户请求报文到达平衡器后,平衡器根据调度选择执行服务器,利用执行服务器的物理地址(MAC)将报文转发给执行节点。转发 过程中不需要进行地址解析,所以不必改动客户请求报文。采用PF策略的典型代表是IBM的Network Dispatcher。

局域网内部的Network Dispatcher集群处理客户请求的原理与图5相似,其工作流程如下:

  1. 客户向服务器发出请求报文;
  2. 平衡器根据负载平衡策略选择执行服务器;
  3. 平衡器利用执行服务器的私有MAC地址转发客户报文;
  4. 客户报文路由;
  5. 执行服务器处理客户请求;
  6. 执行服务器将应答报文发送给客户。

为了将服务器集群从局域网拓展到广域网,Network Dispatcher采用两级平衡器机制,图5显示了广域网服务器集群的原理图。一级平衡器到二级服务器之间采用类似报文单向重写策略,平衡器将客户请求 报文的目的地址(IP-SVA)改写为二级平衡器的IP地址,选择二级平衡器的原则是根据客户-服务器间的距离,将客户请求分发到最近的服务器子群上。二 级平衡器将客户请求报文的目的地址改回IP-SVA,然后将报文转发到执行服务器上,服务器子群要求必须在同一局域网中。


图 5:广域网实现的报文转发
图 5:广域网实现的报文转发

在广域网环境下,实现客户请求报文处理的流程是:

  1. 客户向服务器发送请求报文;
  2. 一级平衡器根据客户-服务器距离选择二级平衡器;
  3. 一级平衡器将客户报文的目的地址改写为二级平衡器的IP地址;
  4. 客户请求报文由一级平衡器向二级平衡器路由;
  5. 二级平衡器根据负载平衡策略选择执行服务器;
  6. 二级平衡器将客户请求报文的目的地址改写为IP-SVA;
  7. 客户请求报文转发;
  8. 执行服务器将应答报文直接传送给客户。

随着负载数量的增长,相应的处理变得越来越复杂(每个服务器节点每秒处理的请求数量有限),目前路由器只负责接收报文,但链接的复杂性、每个请求的返回数据量都限制了路由器的可伸缩性。

2.4 HTTP重定向策略

集中式平衡器接收所有客户请求,使用HTTP重定向机制将客户请求分发到不同的执行服务器上。平衡器根据特殊的响应状态码,指明客户请 求文件在服务器上的位置,因此重定向机制是高度透明的。与其他分发机制不同的是,HTTP重定向机制不需要对通讯报文的IP地址进行修改,HTTP重定向 机制可以由以下两种技术实现。

2.4.1 基于服务器状态分发
在分布式服务器集群体系结构中,修正现有的HTTP协议,增加新方法实现对Web服务器的管理,改变平衡器与执行服务器间的信息交换。由于平衡器需要考虑 服务器的负载情况,每个执行服务器必须周期性地报告处理进程数量和客户请求到达率。平衡器选择负载最轻的执行服务器处理新的客户请求。

2.4.2 基于位置的分发
Cisco的Distributed Director提供了两种分发模式,第一种是基于DNS的SCSB策略,第二种为HTTP重定向策略。Distributed Director评估客户-服务器距离和节点可用性,将客户请求重定向到最合适的执行服务器。

细粒度分发策略的比较

基于平衡器的报文双向重写机制的问题是,平衡器必须对应答报文进行重写,而应答报文的数量明显超过请求报文的数量。

使用TCP路由器结构的报文单向重写机制,由于执行服务器处理众多的应答报文,减轻了平衡器的负载。广域网环境下的Network Dispatcher仅对请求报文进行两次重写,因而执行效率更高。

报文转发机制可以有效避免报文重写带来的开销,然而共享单IP地址导致静态调度策略失效(服务器状态不决定路由)。基于路由的平衡器需要对每个报文进行二次路由,基于广播的平衡器需要把报文广播到每个执行服务器,这样明显加重了服务器负载。

局域网环境下的Network Dispatcher结构避免了共享IP地址、TCP路由和双向重写的开销等问题,但是它只能在同一网段内实现,可伸缩性很差。HTTP重定向可以很好地应用于局域网和广域网中,但必须复制一定数量的TCP连接。

各种负载平衡策略的比较

基于DNS机构的实现机制可以明显减轻服务器的瓶颈效应,可伸缩能力得到加强,服务器环境从局域网拓展到广域网。但是,使用这种结构,服务器的数量不能超 过32台(受UDP报文长度的限制)。基于DNS结构的服务器通过地址映射决定客户请求的目的地址,然而,这种粗粒度负载平衡机制要求TTL必须大于0, 由于客户端对服务器地址进行缓存,导致服务器负载平衡不能保证,人们提出了基于状态信息算法和自适应TTL算法对DNS策略的性能进行改进。总的来说,单 纯基于DNS策略的服务器适合于小规模的同构型服务器集群,但不适于异构性服务器结构。

基于平衡器结构的服务器由于受到单仲裁入口的限制,客户请求迅速增长可能导致平衡器成为系统瓶颈;由于平衡器对客户请求报文重写或转发,增加了客户等待延 迟,降低了服务器性能;另外使用集中调度策略,若平衡器当机,则整个系统都会崩溃。从另一方面讲,平衡器实现的细粒度负载平衡策略,共享服务器IP地址又 克服客户端网络层地址缓存问题。基于服务器拓扑结构实现的报文重写和转发策略是目前局域网或高速广域网中集群服务器实现的主要策略。

改进执行服务器处理过程将原有的请求集中控制改为部分分布控制,是服务器结构研究的一种进步,与平衡器结构服务器相同,这种技术也是一种细粒度负载平衡策略,但它带来的客户等待延迟要比其他策略增加很多。

从目前集群式服务器结构研究的现状分析可以看出,今后服务器集群的发展趋势将是面向广域网的分布控制的服务器集群研究。

 

参考资料

  • Andrew S. Tanenbaum ,《计算机网络》, 清华大学出版社,1998

  • 刘振英、张毅等,多机系统的动态负载平衡,《计算机科学》, Vol. 26 , No 1:38-40, 1999

  • Eager D L,et al. Adaptive load sharing in homogeneous distributed systems. IEEE Tran. On Software Engineering, SE-12(5),1986

  • Zhou S. A trace-driven simulation stydy of dynamic load balancing. IEEE Tran . On Software Engineering. SE-14(9):1327~1341,1988

  • 魏永明、杨飞月、吴漠霖,《Linux实用教程》,电子工业出版社,1999

  • 胡子昂、王立,算法、网络拓扑及调度频率与动态负载平衡的关系,《计算机工程与科学》,Vol.22.No.1, 2000

  • Aaron Mackee,A TurboLinux Technical Case Study,www.turbolinux.com

  • www.linuxvirtualserver.com

  • aniel A.Menasce, "CS672-Computer System Performance Evaluation" http://www.cs.gmu. edu/faculty/menasce.html

  • Louis P.Slothouber, "A model of Web Server Performance", http://louvx.biap.com/webperfor mance/modelpaperhead.html

  • V.Cardellini, M.Colajanni et al, "DNS Dispatching Algorithms with State Estimators for Scalable Web Server Clusters", World Wide Web J.Baltzer Science Bussum, Netherlands Vol 2, No.2 July 1999

  • M.Colajanni et al, "Analysis of Task Assignment Policies in Scalable Web Server Systems", IEEE Trans Parallel and Distributed Systems, Vol.9 No.6, June 1998, pp585-600

  • D.M.Dias et al, "A Scalable and Highly Available Web Server", Proc 41st IEEE Computer Soc. Int'l Conf, IEEE Computer Soc. Press, Los Alamitos, Calif, Feb,1996, pp85-92

  • "Network Dispatcher : a connection router for scalable Internet Services",In Proceedings of the 7th Interional WWW conference , Brisbance Australia , April 1998 http://decweb .ethz.ch/www/1899/com1899.htm

  • D.L.Eager E,D Lazowska and J,Zahorjan , "Adaptive load sharing in homogeneous distributed systems", IEEE Transactions on Software Engineering ,12(5):662-675, May 1986

  • IBM "IBM parallel system support programs for AIX : group services programming guide and reference" 1996 SC28-1675-00

  • O.Kremien and J.Kramer,"Methodical analysis of adaptive load sharing algorithms", IEEE Transactions on Parallel and Distributed Processing 3(6), November 1992

  • Daniel Ridge,"Beowulf Harnessing the Power of Parallelism in a Pile of PCs"

1.设计目标

设计一个基于Linux的集群系统,它能够提供负载平衡的功能。系统能够不断监视集群中各台实际服务器的负载状况,并且将来自外部网的多种请求转发到内部网中的某一台实际服务器上执行。

具体来说,它必须拥有以下的功能:

(1)服务转发。能接受来自外部网中的多种基于TCP/IP的服务请求如FTP 、TELNET、 HTTP等,并且将它们转发到当前负载最轻的机器上执行。

(2)动态负载平衡。平衡器能够监视内部网中的实际服务器的负载状况并且找到负载最轻的机器。

(3)连接持续性。来自外部网的同一客户的所有请求必须转发到内部网中的同一台实际服务器上进行处理。

2.环境设置

如图1-1所示,该集群系统由router、server 1、server 2、server 3以及 server n等机器组成。其中router作为内部网和外部网的接口,能够接收外部网的用户请求,并将此用户请求发送到server1到servern中的某台机器 上(如server1),当server1处理完用户的请求以后,就将处理完的结果发送给router,然后再由router将请求回应返回给外部网的用 户。文章中也将router这台机器称为负载平衡器,因为它承担了均衡负载的作用;将实际响应用户请求的server1等机器称为实际服务器。试验环境中 外部网中的客户机器的IP地址为192.9.200.53,负载平衡器(router)有两个IP地址,一个是192.9.200.56, 一个是10.1.1.1,负载平衡器上运行的操作系统内核为Linux 2.2.x。 内部网中有n台实际服务器,它们的IP地址分别为10.1.1.2、10.1.1.3……..10.1.1.n,他们上面运行的操作系统可以是linux 操作系统,也可以是Windows系列的操作系统,如Windows 98、Windows NT等等。它们都将10.1.1.1设为网关,并且都增加了通往192.9.200.0网络的路由。负载平衡的目的就是将客户发向平衡器的请求 如:telnet、 ftp 、www等按照内部网机器当前负载的情况分发到各个实际服务器上。


图1-1 负载平衡系统环境设置图

3.构建过程

在构建过程这一小节中,首先介绍IP伪装技术的原理,然后介绍集群系统的建立过程。本集群系统的建立首先要建立IP伪装机制,然后再增加IP Portforwarding(IP端口转发)机制,然后设计一个应用程序,它能够根据集群中的机器的状态实现实时动态负载平衡。本集群系统中的负载平衡器上的Linux内核版本为2.2.x。

3.1 IP伪装技术

本集群系统主要采用了IP Masquerade(IP伪装)机制。该负载平衡系统采用了NAT(network address translation)机制。NAT机制主要用于内部私有网与外部网之间进行通讯。IP地址中的那些私有地址如10.0.0.0/255.0.0.0, 172.16.0.0/255.240.0.0 以及192.168.0.0/255.255.0.0等是无法直接与Internet上的机器通讯的,如果它们想与Internet上的机器通讯,需要采用网络地址翻译(Network Address Translation,NAT)机制。

NAT意味着将IP地址从一组映射到另外一组,如果这种映射关系是N-N的,则称之为静态网络地址翻译; 如果映射是M-N(M>N)的,则叫做动态网络地址翻译;IP伪装机制实际上就是一种M-1的动态网络地址翻译,它能够将多个内部网中的IP地址映 射到一个与Internet相连接的外部网IP地址上,这样这些无法直接与Internet上的机器通讯的具有内部网IP地址的机器就可以通过这台映射机 器与外界进行通讯了。而网络地址端口翻译是对网络地址翻译的一种扩展,它将许多网络地址以及它们的TCP/UDP端口翻译为一个IP地址和TCP/UDP 端口。本集群系统采用的就是网络地址端口翻译机制。

3.2 IP伪装机制的建立过程

(1) 编译核心使之能够支持IP伪装。

编译核心时要注意以下选项的选择。

* Prompt for development and/or incomplete code/drivers
(CONFIG_EXPERIMENTAL) [Y/n/?]
    - YES: though not required for IP MASQ, this option allows
    the kernel to create the MASQ modules and enable the option
    for port forwarding
  -- Non-MASQ options skipped --
  * Enable loadable module support (CONFIG_MODULES) [Y/n/?]
    - YES: allows you to load kernel IP MASQ modules
  -- Non-MASQ options skipped --
  * Networking support (CONFIG_NET) [Y/n/?]
    - YES: Enables the network subsystem
  -- Non-MASQ options skipped --
  * Sysctl support (CONFIG_SYSCTL) [Y/n/?]
    - YES:  Enables the ability to enable disable options such as forwarding,
      dynamic IPs, LooseUDP, etc.
  -- Non-MASQ options skipped --
  * Packet socket (CONFIG_PACKET) [Y/m/n/?]
    - YES: Though this is OPTIONAL, this recommended feature will allow you
    to use TCPDUMP to debug any problems with IP MASQ
  * Kernel/User netlink socket (CONFIG_NETLINK) [Y/n/?]
    - YES: Though this is OPTIONAL, this feature will allow the logging of
    advanced firewall issues such as routing messages, etc
  * Routing messages (CONFIG_RTNETLINK) [Y/n/?]
    - NO:  This option does not have anything to do with packet firewall logging
  -- Non-MASQ options skipped --
  * Network firewalls (CONFIG_FIREWALL) [Y/n/?]
    - YES: Enables the kernel to be comfigured by the IPCHAINS firewall tool
  * Socket Filtering (CONFIG_FILTER) [Y/n/?]
    - OPTIONAL:  Though this doesn't have anything do with IPMASQ, if you plan
      on implimenting a DHCP server on the internal network, you WILL need this
      option.
  * Unix domain sockets (CONFIG_UNIX) [Y/m/n/?]
    - YES:  This enables the UNIX TCP/IP sockets mechanisms
  * TCP/IP networking (CONFIG_INET) [Y/n/?]
    - YES: Enables the TCP/IP protocol
  -- Non-MASQ options skipped --
  * IP: advanced router (CONFIG_IP_ADVANCED_ROUTER) [Y/n/?]
    - YES:  This will allow you to configure advanced MASQ options farther down
  * IP: policy routing (CONFIG_IP_MULTIPLE_TABLES) [N/y/?]
    - NO: Not needed by MASQ though users who need advanced features
    such as TCP/IP source address-based or TOS-enabled routing will
    need to enable this option.
  * IP: equal cost multipath (CONFIG_IP_ROUTE_MULTIPATH) [N/y/?]
    - NO: Not needed for normal MASQ functionality
  * IP: use TOS value as routing key (CONFIG_IP_ROUTE_TOS) [N/y/?]
    - NO:  Not needed for normal MASQ functionality
  * IP: verbose route monitoring (CONFIG_IP_ROUTE_VERBOSE) [Y/n/?]
    - YES: This is useful if you use the routing code to drop IP
    spoofed packets (highly recommended) and you want to log them.
  * IP: large routing tables (CONFIG_IP_ROUTE_LARGE_TABLES) [N/y/?]
    - NO:  Not needed for normal MASQ functionality
  * IP: kernel level autoconfiguration (CONFIG_IP_PNP) [N/y/?] ?
    - NO:  Not needed for normal MASQ functionality
  * IP: firewalling (CONFIG_IP_FIREWALL) [Y/n/?]
    - YES: Enable the firewalling feature
  * IP: firewall packet netlink device
  (CONFIG_IP_FIREWALL_NETLINK) [Y/n/?]
    - OPTIONAL: Though this is OPTIONAL, this feature will allow
    IPCHAINS to copy some packets to UserSpace tools for additional
    checks
  * IP: transparent proxy support (CONFIG_IP_TRANSPARENT_PROXY) [N/y/?]
    - NO:  Not needed for normal MASQ functionality
  * IP: masquerading (CONFIG_IP_MASQUERADE) [Y/n/?]
    - YES: Enable IP Masquerade to re-address specific internal to
    external TCP/IP packets
  * IP: ICMP masquerading (CONFIG_IP_MASQUERADE_ICMP) [Y/n/?]
    - YES: Enable support for masquerading ICMP ping packets
    (ICMP error codes will be MASQed regardless).  This is an
    important feature for troubleshooting connections.
  * IP: masquerading special modules support
  (CONFIG_IP_MASQUERADE_MOD) [Y/n/?]
    - YES: Though OPTIONAL, this enables the OPTION to later enable
    the TCP/IP Port forwarding system to allow external computers to
    directly connect to specified internal MASQed machines.
  * IP: ipautofw masq support (EXPERIMENTAL)
  (CONFIG_IP_MASQUERADE_IPAUTOFW) [N/y/m/?]
    - NO:  IPautofw is a legacy method of port forwarding.  It is
    mainly old code and has been found to have some issues.  NOT
    recommended.
  * IP: ipportfw masq support (EXPERIMENTAL)
  (CONFIG_IP_MASQUERADE_IPPORTFW) [Y/m/n/?]
    - YES: Enables IPPORTFW which allows external computers on
    the Internet to directly communicate to specified internal
    MASQed machines.  This feature is typically used to access
    internal SMTP, TELNET, and WWW servers.  FTP port forwarding
will need an additional patch as described in the FAQ section of
the MASQ HOWTO.  Additional information on port forwarding is
available in the Forwards section of this HOWTO.
  * IP: ip fwmark masq-forwarding support (EXPERIMENTAL)
  (CONFIG_IP_MASQUERADE_MFW) [Y/m/n/?]
    - OPTIONAL:  This is a new method of doing PORTFW.  With this option,
    IPCHAINS can mark packets that should have additional work on.
    Using a UserSpace tool, much like IPMASQADM or IPPORFW, IPCHAINS
    would then automaticaly re-address the packets. Currently, this
    code is less tested than PORTFW but it looks promising.  For now,
    the recommended method is to use IPMASQADM and IPPORTFW.  If you
    have thoughts on MFW, please email me.
  * IP: optimize as router not host (CONFIG_IP_ROUTER) [Y/n/?]
    - YES:  This optimizes the kernel for the network subsystem though
    it isn't known if it makes a siginificant performance difference.
  * IP: tunneling (CONFIG_NET_IPIP) [N/y/m/?]
    - NO: This OPTIONAL section is for IPIP tunnels through IP Masq.
    If you need tunneling/VPN functionality, it is recommended to
    use either GRE or IPSEC tunnels.
  * IP: GRE tunnels over IP (CONFIG_NET_IPGRE) [N/y/m/?]
    - NO:   This OPTIONAL selection is to enable PPTP and
    GRE tunnels through the IP MASQ box
    -- Non-MASQ options skipped --
  * IP: TCP syncookie support (not enabled per default)
  (CONFIG_SYN_COOKIES) [Y/n/?]
    - YES: HIGHLY recommended for basic TCP/IP network security
    -- Non-MASQ options skipped --
  * IP: Allow large windows (not recommended if <16Mb of memory) *
  (CONFIG_SKB_LARGE) [Y/n/?]
    - YES:  This is recommended to optimize Linux's TCP window
    -- Non-MASQ options skipped --
  * Network device support (CONFIG_NETDEVICES) [Y/n/?]
    - YES: Enables the Linux Network device sublayer
    -- Non-MASQ options skipped --
  * Dummy net driver support (CONFIG_DUMMY) [M/n/y/?]
    - YES:  Though OPTIONAL, this option can help when debugging problems
  == Don't forget to compile in support for your network card !! ==
    -- Non-MASQ options skipped --
  == Don't forget to compile in support for PPP/SLIP if you use a modem or
     use a PPPoE DSL modem ==
    -- Non-MASQ options skipped --
  * /proc filesystem support (CONFIG_PROC_FS) [Y/n/?]
    - YES:  Required to enable the Linux network forwarding system

 

(2)重新编译了核心以后,应该通过以下命令重新编译并安装IP伪装模块:

make modules; make modules_install

3.3 IP端口转发机制的建立过程

现在需要增加适当的转发机制,从而将数据报文转发到合适的机器上去。首先要注意的是IPFWADM已经不再是2.1.x 和2.2.x核心中控制IP伪装规则的工具,这些核心现在使用的工具是IPCHAINS。

(1)首先根据以下的规则创建/etc/rc.d/rc.firewall文件。

/sbin/depmod -a
/sbin/modprobe ip_masq_ftp
/sbin/modprobe ip_masq_portfw.o
echo "1" > /proc/sys/net/ipv4/ip_forward
echo "1" > /proc/sys/net/ipv4/ip_always_defrag
/sbin/ipchains -M -S 7200 10 160
/sbin/ipchains -P forward DENY
/sbin/ipchains -A forward -s 10.1.1.0/24 -j MASQ
/usr/sbin/ipmasqadm portfw -f
#port forwarding strategy
#port forward the packet of interface 192.9.200.56 to 10.1.1.2 (server2)
#telnet service:port 23
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 23 -R 10.1.1.2 23 -p 1
#ftp service:port 21
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 21 -R 10.1.1.2 21 -p 1
#www service:port 80
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 80 -R 10.1.1.2 80 -p 1
#port forward the packet of interface 192.9.200.56 to 10.1.1.3 (server3)
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 23 -R 10.1.1.3 23 -p 1
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 21 -R 10.1.1.3 21 -p 1
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 80 -R 10.1.1.3 80 -p 1
#port forward the packet of interface 192.9.200.56 to 10.1.1.4 (server4)
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 23 -R 10.1.1.4 23 -p 1
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 21 -R 10.1.1.4 21 -p 1
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 80 -R 10.1.1.4 80 -p 1

 

(2)在编辑完/etc/rc.d/rc.firewall文件后,运行 chmod 700 /etc/rc.d/rc.firewall命令使该文件变为可执行的。

(3)在 /etc/rc.d/rc.local文件中增加一行来在每次重启以后激活IP伪装模块。

#rc.firewall script - Start IPMASQ and the firewall
 /etc/rc.d/rc.firewall.

 

在依次完成了3.2和3.3小节的操作以后,实际上已经建立起了一个基于Round-Robin调度算法的集群系统,如果用户想根据计算机性能的不同为之 赋相应的权重,只需修改rc.firewall中的规则即可。例如,如果要把server2(10.1.1.2)的权重改为2,只须将原来的规则:

/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 23 -R 10.1.1.2 23 -p 1
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 21 -R 10.1.1.2 21 -p 1
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 80 -R 10.1.1.2 80 -p 1
改为:
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 23 -R 10.1.1.2 23 -p 2
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 21 -R 10.1.1.2 21 -p 2
/usr/sbin/ipmasqadm portfw -a -P tcp -L 192.9.200.56 80 -R 10.1.1.2 80 -p 2

 

这样就可以了。

3.4 建立实现动态负载平衡的应用程序

该应用程序监视集群中的各个实际服务器的负载情况,并将用户的请求转发到负载最轻的实际服务器上。具体的实现请参考文章后半部分有关调度模块的实现方法

4.设计原理

本集群系统实现了IP级的负载平衡。当客户向平衡器发送一个请求报文时,在平衡器的IP层对此请求报文的目标地址进行了替换工作,将目标地址替换为内部网 中的实际服务器中的负载最轻的机器的IP地址。然后将此报文再次转发出去。当内部网中的实际服务器将请求处理完了以后,它将请求回应发向平衡器,平衡器再 次在IP层将目标地址替换为发出请求的外部网中的客户的IP地址,然后将此报文再次转发到客户。

对目标地址进行替换的工作是在操作系统的核心中实现的,而选取负载最轻的机器的IP地址是在应用层实现的。之所以这样做是因为在应用层取负载数据可以提高 系统的可扩展性,当需要向内部网中增加一台新的实际服务器时,只需要在应用程序的数组变量中增加一项就可以了;而且在应用层可以灵活地决定调度策略,可以 采用静态的调度策略如Round Robin、Weighted Round Robin等,也可以采用动态的调度策略如Least Connection 、Weighted Least Connection等。对IP报文进行目标地址改写的工作主要在核心完成,这是因为这样速度很快,省掉了从用户到核心的通讯过程。

当外部网中的客户向负载平衡器发出一个服务请求(如www、ftp、telnet等) 时,从这个请求中可以获得外部网机器的IP地址和端口号(laddr ,lport),以及平衡器的IP地址,根据这些信息查询IP端口转发双向链表看是否有匹配(laddr, lport)的表项存在,如果存在的话,就取出该表项中的(raddr, rport)的值,即内部网中机器的IP地址和端口号,并且替换IP包的目标地址和端口号为(raddr, rport),再将此IP包重新发送到内部网中的对应机器上去。如果没有对应表项,则创建新的IP端口转发表项,以及对应的IP伪装表项。再进行目标地址替换和包重发的工作。

5.各模块功能

本负载平衡系统主要分为IP伪装模块、IP端口转发模块和调度模块,其中IP伪装模块和IP端口转发模块都是在IP层实现的,在Linux源代码所在目录下都可以找到它们对应的程序。而调度模块是在应用层实现的。

模块名 标识符 说明
ip伪装模块 ip_masq 对ip报头进行改写,对ip报文进行转发。
ip端口转发模块 ip_portfw 接收外界的请求,根据调度算法决定将ip报文转发到哪一台实际服务器上。
调度模块 sched 根据负载信息收集模块确定的负载最轻的机器的地址将用户请求转发到负载最轻的机器上。

6 ip伪装模块的分析

6.1 设计思想

ip伪装模块的主要工作是:

1.接收内部网发向外部网的所有请求。

2.内部网中的连接请求通过平衡器转发到外部网。

3.将内部网发向外部网中的所有请求的源地址隐藏,使所有请求看上去都是由平衡器发送的。

4. 建立HASH表来记录已经建立的所有连接。

5. 接收外部网对请求的回应并将其转发到内部网中的发出请求的机器上。

6.2 模块流程

(1) 内部网中的机器向外部网中的机器发送连接请求的流程。


(2) 外部网中的机器向内部网中的机器发送连接请求的流程。


6.3 结构设计

程序名 标识符 功能 源程序
建立HASH队列 ip_masq_hash 根据m{addr, port}和s{addr, port}建立两个HASH队列 ip_masq.c
从HASH队列删除表项 ip_masq_unhash 将ip_masq表项从HASH队列中删除 ip_masq.c
处理从外到内的请求 __ip_masq_in_get 处理从外到内的请求,查询HASH表,找到内部机器的ip地址及端口 ip_masq.c
处理从内到外的请求 __ip_masq_out_get 处理从内到外的请求,查询HASH表,找出源地址、端口及目标地址、端口都匹配的表项。 ip_masq.c
减少某个连接的访问计数 __ip_masq_put 将ip_masq表项的访问计数减一。 ip_masq.c
取下一伪装端口 get_next_mport 取得下一个mport。 ip_masq.c
创建新的ip_masq结构 ip_masq_new 创建一个新ip_masq结构,并分配一个新的mport ip_masq.c
从内到外请求处理的最上层函数 ip_fw_masquerade 负责从内向外请求的处理全过程。 ip_masq.c
从外到内请求处理的最上层函数 ip_fw_demasquerade 负责从外向内请求的处理全过程。 ip_masq.c

6.4 主要数据结构

struct  ip_masq{
struct  ip_masq  *m_link,  *s_link;
atomic_t   refcnt;
struct   timer_list  timer;
__u16  protocol;
__u16  sport,  dport,  mport;
__u32  saddr,  daddr,  maddr;
struct  ip_masq_seq  out_seq, in_seq;
void  *app_data;
struct  ip_masq  *control;
atomic_t  n_control;
unsigned  flags;
unsigned  timeout;
unsigned  state;
struct  ip_masq_timeout_table  *timeout_table;
}

 

6.5 算法及流程

(1) ip_masq_hash

格式:static ip_masq_hash(struct ip_masq *ms)

返回值:1:成功;0:失败。

处理流程:

1. 如果ms->flags 已设IP_MASQ_F_HASHED标志位,则返回0。

2.根据ms->protocol、 ms->maddr和 ms->mport产生hash->key。

3.将ms链接到hash[hash_key] 链的头位置。

4.增加ms的访问计数。

5.根据ms->protocol 、ms->sadd和ms->sport产生hash_key。

6.将ms链接到hash[hash_key] 链的头位置。

7.增加ms的访问计数。

8.ms->flags 设IP_MASQ_F_HASHED位。

9. 返回1。

(2)ip_masq_unhash

格式:static int ip_masq_unhash(struct ip_masq *ms)

返回值: 1:成功;0:失败。

处理流程:

1. 如果ms->flags未设IP_MASQ_F_HASHED位,则返回0。

2. 不然,做以下几步。

3. 根据ms->protocol、 ms->maddr和 ms->mport产生hash->key。

4. 在hash[hash_key]链中找匹配的表项,将匹配项的访问计数减一,并从链表中删除此项。

5. 根据ms->protocol 、ms->sadd和 ms->sport产生hash_key。

6. 在hash[hash_key]链中找匹配的表项,将匹配项的访问计数减一,并从链表中删除此项。

7. ms->flags设位~IP_MASQ_F_HASHED。

8. 返回1。

(3)__ip_masq_in_get

格式:static struct ip_masq *__ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)

返回值:返回一个ip_masq结构ms。

处理流程:

1. 根据 protocol 、 d_addr、 d_port产生hash_key。

2. 在hash[hash_key]链中找匹配的表项,满足: (protocol == ms->protocol && d_addr == ms->maddr && dport == ms->mport && (s_addr == ms->daddr || ms->flags & MASQ_DADDR_PASS) && (s_port == ms->dport || ms_flags & MASQ_DPORT_PASS))。

3. ms的访问计数增1。

4. 返回ms。

(4)__ip_masq_out_get

格式:static struct ip_masq *__ip_masq_out_get(int protocol , __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)

返回值:返回一个ms。

处理流程:

1. 如果s_port不为0,做以下几步;不然,跳至第5步。

2. 根据 protocol 、 s_addr和s_port产生hash_key。

3. 在hash[hash_key]链中找匹配的表项,满足:(protocol == ms->protocol && s_addr == ms->saddr && sport == ms->sport && (d_addr == ms->daddr || ms->flags & MASQ_DADDR_PASS) && (d_port == ms->dport || ms_flags & MASQ_DPORT_PASS))。

4. ms的访问计数增1。

5. 返回ms。

6. 根据 protocol 、 s_add、 0产生hash_key。

7. 在hash[hash_key]链中找匹配的表项,满足:(protocol == ms->protocol && s_addr == ms->saddr && sport == ms->sport && (d_addr == ms->daddr || ms->flags & MASQ_DADDR_PASS) && (d_port == ms->dport || ms_flags & MASQ_DPORT_PASS))。

8. ms的访问计数增1。

9. 返回ms。

(5)__ip_masq_getbym

格式:static struct ip_masq *__ip_masq_getbym(int protocol, __u32 m_addr, __u16 m_port)

返回值:返回一个ms。

处理流程:

1. 根据 protocol 、m_add和 m_port产生hash_key。

2. 在hash[hash_key]链中找匹配的表项,满足:(protocol == ms->protocol && m_addr == ms->maddr && mport == ms->mport )。

3. ms的访问计数加1。

4. 返回ms。

(6)ip_masq_out_get

格式:struct ip_masq *ip_masq_out_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)

返回值:返回ms。

处理流程:

1. 为__ip_masq_lock加读锁。

2. 调__ip_masq_out_get(protocol, s_addr, s_port, d_addr, d_port)返回ms。

3. 解读锁__ip_masq_lock。

4. 为ms设置超时。

5. 返回ms。

(7)ip_masq_in_get

格式:struct ip_masq_in_get(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)

返回值:返回ms。

处理流程:

1.为__ip_masq_lock加读锁。

2.调__ip_masq_in_get(protocol, s_addr, s_port, d_addr, d_port)返回ms。

3. 解读锁__ip_masq_lock。

4. 为ms设置超时。

6. 返回ms。

(8)__ip_masq_put

格式:static __inline __void __ip_masq_put(struct ip_masq *ms)

返回值:无

处理流程:

1. 将ms的访问计数减一。

(9)get_next_mport

格式:static __u16 get_next_mport(void)

返回值:返回一个16位的端口号。

处理流程:

1. 为masq_mport_lock加旋转锁。

2. Mport = htons(masq_port ++)。

3. 如果masq_port是最后一个锁,则masq_port = 开始锁。

4. 解旋转锁masq_port_lock。

5. 返回mport。

(10)ip_masq_new

格式:struct ip_masq *ip_masq_new(int proto, __u32 maddr, __u16 mport, __u32 saddr, __u16 sport, __u32 daddr, __u16 dport, unsigned mflags)

返回值:成功:返回ms;失败:返回null。

处理流程:

1. 如果没有可用端口,返回NULL。

2. 若mflags 设IP_MASQ_F_USER位,则 prio = GFP_KERNEL;不然, prio=GFP_ATOMIC。

3. 为ms分配空间,若失败,返回NULL。

4. MOD_INC_USE_CONUNT。

5. 清空ms。

6. 初始化ms->timer。

7. ms->timer.data = (unsigned long)ms;

ms->timer.function = masq_expire;

ms->protocol = proto;

ms->saddr = saddr;

ms->sport = sport;

ms->daddr = daddr;

ms->dport = dport;

ms->flags = NULL;

ms->app_data = NULL;

ms->control = NULL;

设ms->n_control 为0;

设ms->refcnt 为0;

ms->maddr = maddr;

ms->flags设IP_MASQ_F_NO_REPLY位。

8. 如果((协议不是TCP 和UDP)|| mport),ms的伪装端口设为mport。调用__ip_masq_in_get取得ms。

9. 如果没有匹配的ms,则ms->flags设 IP_MASQ_F_MPORT位;增加伪装端口计数;将ms加入HASH队列;调用ip_masq_bind_app(ms);ms的访问计数加一;为ms的IP_MASQ_S_NONE状态设置超时;返回ms。

10. 如果有匹配项,则调用__ip_masq_put(mst)使访问计数减一;释放ms; MOD_DEC_USE_COUNT;返回NULL。

11. 调用mport = get_next_mport()来找一个可用的端口。

12. 赋值 ms->mport = mport。

13. 调用ip_masq_bind_app(ms)。

14. 设n_fails为0。

15.ms的访问计数增一。

16.为ms的IP_MASQ_S_NONE设置超时。

17.返回ms。

(11)ip_fw_masquerade

格式:int ip_masquerade(struct sk_buff **skb_p, __u32 maddr)

返回值:成功:返回大于0的数;失败:返回-1。

处理流程:

1. 先做一些有关校验和的检查。

2. 调用ip_masq_out_get_iph看入口是否已经存在。

3. 如果入口存在的话,将老的ms从HASH表中删除,将ms->maddr替换为maddr,并将新的ms结构加入HASH队列。

4. 如果没有定义源端口,做以下几步:将老的ms从HASH表中删除,设置ms->sport =h.portp[0],即设置ms的源端口为TCP头中的源端口,将新的ms加入HASH表。

5. 如果定义了IP_MASQ_F_DLOOSE,ms->dport = h .port[1]; ms->daddr = iph->daddr。

6. 如果入口不存在则创建一个新的ms。

7. 将IP头的源地址替换为平衡器的ip地址。

8. 将TCP头的源端口替换为ms的伪装端口。

9. 做一些有关校验和的操作。

10. ms的访问计数减一。

11. 返回0。

(12)ip_fw_demasquerade

格式: int ip_fw_demasquerade(struct sk_buff **skb_p)

返回值:成功:返回1;失败:返回-1。

处理流程:

1. 取得sk_buff中的数据取的起始地址。

2. 取得数据区的大小。

3. 取得针对协议的偏移量。

4. Maddr = iph->daddr。

5. 察看协议类型,如果是ICMP,则调用ip_fw_demasq_icmp;如果是TCP,什么也不做;如果是UDP协议,则首先确认端口号在BEGIN 和END之间,然后对校验和进行一定的操作。

6. 看现有表中是否有匹配项,返回ms。

7. 如果有匹配项,设置标识位~IP_MASQ_F_NO_REPLY;如果定义了非严格路由,则ms->dport = h.portp[0], ms->daddr = iph_saddr。

8. 如果定义了IP_MASQ_F_NO_DPORT,则标识位设~IP_MASQ_F_DPORT, ms的目的端口设为TCP头中的源端口。

9. 如果定义了IP_MASQ_F_NO_DADDR,ms的标识位设~IP_MASQ_F_NO_DADDR,ms的目标地址设为IP头的源地址。

10. 调用masq_skb_cow复制一个skb。

11. 将IP头的目标地址设为ms的源地址。

12. 将TCP头中的目标端口设为ms的源端口。

13. 调用ip_masq_app_pkt_in。

14. 对校验和进行操作。

15. 调用ip_send_check(iph)。

16. 调用masq_set_state(ms, 0 , iph, h.portp )。

17. ms的访问计数减一。

18. 返回1。

7. ip 端口转发模块的分析

7.1 设计思想

ip端口转发模块的主要工作:

1. 接受外部网的连接请求。

2. 对外只呈现平衡器,使所有请求看起来都是由平衡器处理的。

3. 建立一个端口转发链表。

4. 接收外部网发向内部网的请求。根据连接请求的源地址、源端口、目标地址和目标端口的信息察看链表中是否有对应表项,如果有,则调用ip伪装模块将请求转发 到实际服务器上;如果没有对应表项,则创建一个新的端口转发表项,并且在ip伪装HASH表中增加相应的表项。将实际服务器的处理结果回传给平衡器,再由 平衡器发给外部网中的客户。

5. 在ip端口转发模块中通过系统调用的实现函数对用户的系统调用进行处理,首先清空ip端口转发链表,然后建立对应于最轻负载机器ip地址的ip端口转发表项。

7.2 模块流程


7.3 结构设计

程序名 标识符 功能 源程序
删除表项 ip_portfw_del 在双向链表中删除一个ip_portfw结构的表项 ip_masq_portfw.c
清空双向链表 ip_portfw_flush 清空双向链表,释放空间 ip_masq_portfw.c
寻找匹配表项 ip_portfw_lookup 寻找符合要求的表项 ip_masq_portfw.c
设置权重 ip_portfw_edit 为匹配的表项设置权重 ip_masq_portfw.c
添加表项 ip_portfw_add 添加一个表项 ip_masq_portfw.c
控制双向链表 ip_portfw_ctl 对双向链表进行控制,进行添加、删除和清空操作 ip_masq_portfw.c
匹配表项 portfw_in_rule 判断是否存在匹配表项 ip_masq_portfw.c
创建新入口 portfw_in_creat 如果没有匹配表项,则创建一个新的ip_masq结构的表项。 ip_masq_portfw.c
系统调用处理函数 getip 接受来自用户层的系统调用,根据负载最轻的机器的IP值建立新的端口转发链表 ip_masq_portfw.c

7.4 主要数据结构

struct  ip_portfw{
    struct  list_head  list;
    __u32  laddr,  raddr;
    __u16  lport,  rport;
    atomic_t  pref_cnt;
    int  pref;
    }
struct  list_head{
struct  list_head  *next, *prev;
  }
 

 

7.5 算法及流程

(1) ip_portfw_del

格式: static __inline __ int ip_portfw_del(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr)

返回值:如果模块的访问计数 〉0,则返回一个大于0的值,否则返回0;

处理流程:

1. 在双向链表中找到这样的ip_portfw *n 结构,满足:

(n->lport == lport && (!laddr || n->laddr == laddr) && (!raddr || n->raddr == raddr) && (!rport || n->rport == rport )),从链表中删除此入口,释放n结构。

1. 若(&mmod_self -> mmod_nent)为真,则返回ESRCH,否则返回0。

(2) ip_portfw_flush

格式: static __inline__ void ip_portfw_flush(void)

返回值:无。

处理流程:

1. 对于TCP 和UDP链,循环做2. 3步

2. 从链表上删除一个入口,释放结构n。

3. 取下一入口。

(3) ip_portfw_lookup

格式: static __inline__ struct ip_portfw *ip_portfw_lookup(__u16 protocol, __u16 lport, __u32 laddr, __u32 *daddr_p, __u16 *dport_p)

返回值:返回一个ip_portfw结构的变量n。

处理流程:

1.在双向链表中找到这样的ip_portfw *n 结构,满足:

(lport == n->lport && laddr == n->laddr) , 若没有找到,则n = NULL。

2.赋值:*daddr_p = n->raddr;*dport_p = n->rport。

3.返回n。

(4) ip_portfw_edit

格式: static __inline__ int ip_portfw_edit(__u16 protocol, __u16 lport, __u32 laddr, __u16 rport, __u32 raddr, int pref)

返回值:返回满足匹配条件的表项的数目。

处理流程:

1. 设count为0。

2. 在双向链表中找这样的n,满足:( lport == n->lport && (!laddr || laddr == n->laddr) && (!raddr || raddr == n->raddr) && (!rport || rport == n->rport )) 。

3. 为n设置权重。

4. 设n->pref_cnt = pref。

5. 每找到一个匹配项, count都加1。

6. 解读锁portfw_lock。

7. 返回count。

(5) ip_portfw_add

格式: static __inline__ int ip_portfw_add(__u16 protocol, __u16 lport,__u32 laddr, __u16 rport,__u32 raddr, int pref)

返回值:成功:返回0;失败:返回EINVAL。

处理流程:

1. 调用ip_portfw_edit, 若有匹配项,则返回0。

2. 为npf分配一个 struct ip_portfw的空间,若分配失败,则返回"无可用空间" 。

3. MOD_INC_USE_COUNT。

4. npf清0。

5. npf->laddr = laddr;

npf->lport = lport;

npf->rport = rport;

npf->raddr = raddr;

npf->pref = pref;

设npf的访问计数为npf的权重;

6. 调用INIT_LIST_HEAD初始化npf->list。

7. 加写锁&portfw_lock。

8. 调用list_add增加一项到链头。

9. 解写锁。

10. 增加mmod_self计数。

11. 返回0。

(6) portfw_ctl

格式: static __inline__ int portfw_ctl(int optname,struct ip_masq_ctl *mctl, int optlen) 返回值:成功:返回0; 失败:返回EINVAL。

处理流程:

1. 如果cmd为IP_MASQ_CMD_NONE,返回0。

2. 如果cmd为IP_MASQ_CMD_ADD,调用 ip_portfw_add。

3. 如果cmd为IP_MASQ_CMD_DEL,调用 ip_portfw_del。

4. 如果cmd为IP_MASQ_CMD_FLUSH,调用ip_portfw_flush。

5. 返回EINVAL。

(7)portfw_in_creat

格式: static struct ip_masq *portfw_in_creat(const struct sk_buff *skb, const struct iphdr *iph, __u32 maddr)

返回值: 成功:返回ms。

处理流程:

1. 加写锁&portfw_lock。

2. 调用ip_portfw_lookup,若找到匹配项,则调ip_masq_new创建一个新入口表项ms。

3. 调用ip_masq_listen。

4. pf的访问计数减一,若访问计数为0,则设pf的访问计数为pf的权重,将pf 从双向链表中删除,并重新加到链表尾。

5. 返回ms。

(8) 函数getip()

格式:asmlinkage getip(__u32 laddr, __u16 lport, __u32 raddr, __u16 rport) 返回值:无。

处理流程:

1.调用ip_portfw_flush清空ip端口转发链表。

2.调用ip_portfw_add(laddr, lport, raddr, rport, 1)向链表中加入新表项。

8.调度模块的分析

8.1 设计思想

调度模块的主要任务是:

1. 平衡器向各台实际服务器发送收集负载信息的命令。

2. 各台实际服务器分别运行取cpu运行队列长度的程序。

3. 各台机器将各自的cpu运行队列长度信息回传给平衡器。

4. 平衡器对各台机器的cpu运行队列长度进行比较并选出cpu运行队列长度最短的机器,认为此机器就是负载最轻的机器。

5. 通过系统调用将负载最轻的机器的IP地址传入ip端口转发模块。

8.2 模块流程




8.3 结构设计

程序名 功能 源程序
client程序 收集server方的负载信息并进行处理 client.c
server程序 收集本机负载信息并传向client方 server.c
负载信息收集程序 取cpu运行队列长度 cpu.c

8.4 主要数据结构

struct info{
     char  host[15];
     char  cpu[20];
          }
         

 

8.5 算法及流程

(1) cpu.c

处理流程:

1. 调用readprottab2取得进程表p_table。

2. 调用do_stat计算 cpu运行队列长度的信息。

(2) 函数do_stat

格式:void do_stat(proc_t **p, float elapsed_time, int pass, int ctl)

处理流程:

1. 设进程状态变量sleeping =0,stopped = 0, zombie = 0, running = 0。

2. 做以下循环:3,4步。

3. 根据进程表取得一个进程,判断它的状态是sleeping、 stopped 、 zombie还是 running,并且给相应的变量sleeping、 stopped 、 zombie、 running加1。

4. 取下一个进程,返回3。

5. 打印正在运行的进程的个数。

(3)client.c

处理流程:

1. 循环做以下步骤:2-11。

2. 设置控制变量i,循环做3-10步。

3. 如果i < NUM(内部网中机器的总数),做以下步骤。

4. 创建套接口sockfd。

5. 调用connect请求建立一个连接。

6. 调用recv将取得的字节流放入缓冲区buf中。

7. 将buf转换为struct info的格式并将转换后的结果赋给load[I]。

8. 比较各机器的cpu运行队列的长度并且确定负载最轻的机器的IP值,以该值为参数通过自定义的系统调用getip进入内核。

9. 关闭套接口sockfd。

8. 睡眠30秒钟。

(4)server.c

流程:

1. 创建套接口sockfd用来侦听。

2. 调用bind进行绑定。

3. 调用listen进行侦听。

4. 循环做以下步骤:5-11。

5. 调用accept接受连接请求。

6. 调用gethostname取得主机名,调用gethostbyname取得主机IP。

7. 将主机IP赋给load->host。

8. 将/loadbalan/cpu.o的运行结果写入./cpuinfo。

9. 打开./cpuinfo文件,将读取到的值写入 load->cpu。

10. 将结构load以字节流的形式发送出去。

11. 关闭套接口。

9. 系统功能及特点

该负载平衡系统具有以下功能:

(1) 能够对基于TCP/IP协议的多种服务如telnet、ftp、 http等进行转发。在应用程序中,用户可以通过加入特定服务对应的端口号(如ftp对应的端口号是21)来增加对特定的服务的支持。

(2) 实现了动态负载平衡。负载平衡器不断收集各台实际服务器正在运行的进程的个数,通过比较找出具有最少运行进程个数的机器,并且将请求发向这台机器。这种负载平衡是随各台机器现有的负载情况的变化而变化的,因此是动态的负载平衡。

(3) 保证了持续连接。当来一个新的请求时,负载平衡器查找已建立连接的表项来看是否有匹配表项,如果发现已有匹配项,则将请求发往对应的实际服务器,这样就保证了来自同一个用户的同一个服务的多次请求能发送到同一台实际服务器上。

该负载平衡器具有以下的性能特点:

(1) 具有较短的响应时间。从负载平衡器向集群中实际服务器发出收集负载的请求到决定出负载最轻的机器所用的总时间约为30ms,该负载平衡系统能够保证毫秒级的响应时间。

(2) 具有良好的可伸缩性。用户可以在应用程序中对集群中的机器个数进行控制,程序中有一个数组来记录机器的IP地址,因此增加一台机器只需要向数组中增加一个新的元素,删除一台机器只需要从数组中删除对应的元素。

(3) 具有良好的容错性。当集群中的某台机器突然崩溃时,应用程序能够立即发现,并且不会再将请求分发给失效的机器;当机器修复了错误重新进入集群中时,应用程序能够探测到并开始进行正常的负载收集工作。

posted @ 2012-01-31 13:29  marr  阅读(923)  评论(0编辑  收藏  举报