18、分布式系统部署架构考量:故障转移与负载均衡策略

分布式系统部署架构考量:故障转移与负载均衡策略

在分布式系统部署中,有两个关键方面需要重点考量,即故障转移和负载均衡。这两个方面对于确保系统的高可用性、稳定性和性能优化至关重要。

故障转移的实现

故障转移是一个重要的架构问题,需要从服务层面进行讨论。当服务出现严重故障而停止运行时,我们关注的是如何干净利落地重启整个服务。

状态问题

服务恢复的一个关键问题是状态的维护,特别是会话状态。一般来说,状态越少,恢复就越容易。无状态服务是纯粹的过程,它可以简单地重启而无需担心状态丢失。然而,许多服务是有状态的。

状态对故障转移复杂性的影响各不相同。有些状态可能不需要恢复,例如用于读取的服务缓存可以随着时间重新构建。相反,如果会话本身不希望看起来中断,会话状态必须以一致的方式完全恢复,这就需要一个持久化机制。

系统通常会使用持久化层将会话状态的更改写入存储,如关系数据库。此外,一些 CORBA 实现提供加载机制,用于保存和加载对象。为了实现恢复,关键是保存的状态始终保持一致,可以通过常规的事务管理方法来实现,如使用 OTS。如果系统不能保证存储中的数据一致,就需要一种检测和处理不一致的方法,这会增加系统的复杂性,最好避免这种情况。

有状态的服务器可以维护正在进行的会话状态的缓存或日志,并且可以对这些日志进行复制以增加安全性。为了实现恢复,客户端必须拥有可以映射到日志中特定状态点的代理对象 ID。这些 ID 或标记可以与对象适配器(BOA/POA)一起使用,并传递给服务器以恢复正确的状态。

需要注意的是,不仅服务可能会失败,保存其状态的持久存储也可能会失败。在分布式系统中,维护数据存储的副本是很有必要的。可以通过复制或复制来处理这个问题。系统可以使用多个副本存储,每个事务或操作可以同时在所有存储上执行,将数据备份的责任交给持久化/事务层。或者,所有操作可以针对主存储执行,主存储然后使用特定的机制同步备份存储,这可以通过当前主要数据库支持的复制功能来实现。

故障发生

服务失败是因为某些内部操作出现问题。虽然内部故障的细节在这里并不重要,但这些故障如何影响到服务层面是关键。任何服务都需要一种方法来处理处理过程中发生的错误。如今的主要编程语言,如 C++ 和 Java,都有异常处理功能来捕获和发出错误信号。

异常可以根据程序结构的层次进行分类和分组,即系统的每个层次都有基于该层次可能出现的问题的异常家族。每个层次通常最清楚要捕获哪些错误以及如何从中恢复。异常通常通过在当前层次捕获异常、尝试恢复,如果失败则抛出更高层次的异常来进行层次映射。在这样的系统中,原始的异常原因可以作为新异常的一部分传递。如果可能出现多个错误并且可以有效地进行分类,那么相应的异常可以链接在一起。这种映射模式可以应用到系统层面,在那里可以决定给定错误的严重程度,以及是否需要关闭服务。

当故障信号到达服务的顶层并被捕获时,如果无法恢复,服务可以干净地关闭。服务关闭的方式可以是安静的或复杂的,哪种方式更好取决于整体架构的复杂性。如果服务之间没有依赖关系,并且通过 OAD 激活和访问,那么服务可以自行关闭,并在下次尝试访问时由 OAD 重新启动。一个更主动的系统会让服务在关闭前通知中央服务监视器。服务监视器可以不仅对故障服务采取行动,还可以对依赖于它的服务采取行动。如果系统认为需要人工干预,还可以通过电子邮件、寻呼网关等方式通知管理员。

部分故障也是一个重要的细节。服务执行操作是因为客户端请求它们这样做,所以如果服务中出现问题,几乎总是在客户端调用的上下文中。许多系统设计用于指示操作的完成程度,可能的结果有是、否和可能。通过向客户端提供这些信息,服务可以表明其故障程度,并让客户端决定下一步如何进行。对于某些应用程序,客户端可能能够处理部分数据,同时尝试检索其余部分。客户端必须能够处理通信和服务故障,因此必须捕获异常并做出适当的响应。客户端从故障中恢复与服务本身的恢复同样重要。

切换

服务停止后,必须重新启动或替换。这涉及几个问题,包括服务如何和在哪里重新启动,以及如何处理服务之间的依赖关系,以确保系统在故障面前保持稳定。

使用 OAD 启动服务器进程的系统通常支持各种激活模式。可以选择不同的模式来增强稳定性。例如,许多 CORBA 系统支持按客户端激活,即为不同的客户端或客户端进程启动不同的进程。这可以隔离每个服务器进程,使得如果一个进程死亡,只会影响其客户端。分布式对象也可以选择共享或不共享相同的服务器进程,这是另一种隔离控制方式。在评估激活策略时,要记住它们也会影响系统的可扩展性。

当服务停止并重新启动时,发布该服务引用的实体可能需要被通知。OAD、命名服务、交易服务等都属于这一类。OAD 通过发布自身的引用增加了一层间接性,会自动处理这个问题,但重要的是要正确维护命名、交易和其他服务导出的任何信息。

当前 CORBA 产品的一个关键弱点是对处理服务依赖关系的支持不足。这意味着如果架构中的服务之间存在非平凡的依赖关系,就需要自己的依赖处理机制。可以通过几种方式实现这一点。具有 OAD 功能的中央服务监视器可以负责控制重启。或者,服务本身可以承担一些重启责任。然而,中央服务监视器可以使系统更简洁、更具可扩展性,并且更容易推广。这样的监视器可以有权向服务发送关闭消息,并通过进程调用或 OAD 访问激活它们。

负责采取行动的一方需要知道两件事:依赖关系是什么以及基于这些依赖关系应该采取什么行动。依赖关系图可以由服务内部化或外部化,即每个服务可以维护自己的依赖信息,这些信息可以是不透明的或透明的,或者中央监视器可以持有所有依赖信息。依赖信息可以预先配置,或者在更动态的系统中,通过跟踪使用的其他服务在运行时发现。

状态问题也会影响依赖关系的维护。如果一个服务依赖于另一个无状态服务,那么它可以在任何位置使用该服务的任何实例。如果第二个服务有与第一个服务相关或所需的会话状态,那么第一个服务将依赖于它正在使用的特定实例,并且在故障后必须与该服务实例的完全恢复版本重新建立联系。

负载均衡

负载是对计算机繁忙程度的量化描述,但目前没有统一的标准度量。几乎每个当前操作系统桌面的性能监视器都以各种形式测量负载,但这些测量结果的含义并不明确。因此,需要根据具体系统选择合适的负载指标。

负载指标
  • 请求指标 :为了确定一个好的负载指标,首先要考虑服务所做的实际消耗资源的工作。如果工作是 I/O 密集型的,如处理大文件或频繁调用数据库,带宽和连接数可能是一个好的负载度量。如果工作是计算密集型的,如计算变换或求解微分方程,CPU 利用率可能是一个好的度量。计算指标的难点在于为处理请求的每个方法分配合理的负载值。需要从两个方面检查方法的负载:该方法通常预期产生的负载,以及它在运行时为特定请求实际产生的负载。负载均衡系统至少需要一个大致的估计才能做出智能的请求路由决策,并且通过实际运行时检查可以提高系统的准确性。有时在处理开始之前,负载可能无法准确估计。在其他情况下,可以根据请求参数估计传入请求的负载。在简单情况下,可以根据实现知识进行估计。如果对特定服务的所有请求具有相同的特征,那么一个好的负载度量就是该服务当前正在处理的请求数量。即使有多个类别的请求类型,由于它们使用的资源特征是相互独立的,也可以分别考虑。例如,计算密集型进程最好在当前 I/O 繁忙的机器上运行。如果处理请求使用的资源集不同,严格分类方法可能没有太大意义。在这种情况下,可能需要更复杂的优化例程。但要注意,负载计算和优化的开销本身不能抵消负载均衡带来的收益。一个复杂的平衡系统对于长作业系统(如科学模型处理器)可能是值得的,但对于短作业系统(如短数据查询系统)可能是不利的。
  • 机器指标 :评估负载指标时,另一个需要考虑的因素是单个机器能够处理的负载量。一台配备快速网卡的慢速机器可能能够处理与具有相同网卡的快速机器几乎相同的 I/O 负载,但无法处理一半的计算负载。准确计算特定机器能够处理的负载量可能很棘手。如果所有机器是等效的,那么这个度量可以忽略,但如果它们不同,这对于正确的负载均衡至关重要。此外,机器能够处理的负载总是相对于给定系统的性能标准而言的。需要确定一台机器在性能变得不可接受之前能够处理多少请求。准确测量机器的容量可能需要在机器上运行性能测试,测量每个方法的平均运行完成时间。同样重要的是在同一台机器上并行运行测试,以考虑进程和线程切换的成本。测试结果可以得出机器之间的比较估计。然而,在这个领域,重要的是事先决定测试必须达到的准确程度与所需工作量之间的平衡。还应记住,一组方法的平均运行高度依赖于用户的使用模式,这些模式在全新系统中可能不明显,或者随着系统添加更多功能可能会发生巨大变化。
  • 使用指标 :由于真正准确的负载指标可能变得过于复杂,通常会使用常见的简化估计。许多此类估计的一个核心因素是用户使用模式。如果用户之间的使用模式一致,那么可以根据当前用户数量和模式中的位置来估计负载,而不必根据每个方法进行计算。如果使用模式倾向于属于少数几种模式之一,客户端应用程序或用户偏好模块可以建立使用配置文件,这样当特定用户登录时,系统可以向客户端应用程序询问会话的预期负载描述。即使系统的使用模式不完全统一或无法分类,每个进程服务的用户数量也是一个简单的指标,对于许多系统来说已经足够。
  • 全局指标 :每个运行的进程都会增加机器的负载,因此单个服务的负载作为机器负载的度量是没有意义的。必须考虑在该机器上运行的所有服务的负载,以便做出关于机器之间负载平衡的有意义决策。这就是为什么全局监控系统对于协调跨机器的服务指标以支持负载均衡至关重要。
负载均衡策略
  • 静态分配 :可以简单地将一组专用资源分配给给定的服务。根据预期的使用模式和每个服务处理的请求的特征,使用不同资源的服务可以放在同一台机器上,而使用相同资源的服务可以分散在不同的机器上。这需要根据常规用户使用模式对每个服务将产生的负载进行静态评估。这种方法的主要优点是几乎不需要运行时智能,但缺点是无法对意外使用情况进行动态调整负载,也无法根据当前处理情况进行优化,因此系统的性能取决于初始估计的准确性。
  • 动态分配 :更常见和更动态的技术是将系统复制到每个资源上。对于每个请求,负载均衡器只需检查所有机器上的适当负载指标,并将请求发送到最合适的选择。这种方法试图在请求时确保尽可能好的性能,但依赖于运行时负载估计的准确性。通常采用的方法介于上述两种方法之间。某些服务,如由本地数据库支持的服务,在自己的机器上运行,而系统的其余部分在其余机器之间进行平衡。另一种选择是尝试确保一定的最低性能水平,而不是追求最佳性能。在资源非常有限的情况下,可以为系统设置最低性能水平。如果系统主应用服务器机器的性能低于阈值,可以启动另一台机器。这台机器可以是特定集合中当前负载最低的机器。这样,资源可以分配给不同的系统,每个资源都准备好处理溢出。
负载均衡方式
  • 按会话平衡 :基本上是在初始请求到来时,通过命名服务或服务工厂找到负载最轻的服务器。这种方法通常在全局层面进行,尽可能在服务实现之外完成。
  • 按工作平衡 :对于服务的每个请求,决定在哪里可以以最佳性能处理工作。这种方法几乎完全在特定服务的实现内部完成,尽管通常会使用监控、命名和客户端代码提供支持。
按命名服务进行负载均衡

如果选择的负载指标围绕客户端会话,那么在客户端连接到新服务器时,或者更理想的是,当客户端首次使用命名服务定位服务器时,进行负载均衡是有效的。即使供应商提供的命名服务实现不支持任何负载均衡功能,也可以实现命名上下文接口来执行负载均衡,并将此类上下文绑定到命名层次结构的适当位置。

命名上下文实现不是简单地将名称绑定到单个对象引用,而是绑定到一个引用列表。在解析名称时,上下文会选择最适合负载均衡的引用并返回。为了找到最佳平衡,上下文可以向监控服务询问当前负载指标并相应地进行选择。如果特定服务的使用模式和会话长度在各个会话中相当一致,那么简单的循环选择方法效果很好。虽然这可能并不总是产生最佳性能,但每个服务实例的平均负载应该相当均匀。如果会话长度差异很大,从服务实例列表中随机选择可能会产生略好的平均性能。

有时,保持最低性能水平比提供服务本身更重要。如果所有服务实例的负载都达到最大值,命名服务可以拒绝客户端访问服务,这迫使客户端取消或推迟其请求,使当前作业能够在合理的时间内运行。

通过扩展命名上下文接口,命名服务可以获得更多信息,从而做出更好的决策。由于 CORBA 连接基本上是匿名的,关于特定用户或客户端应用程序类型的任何信息必须由客户端通过安全上下文或接口中的显式调用发送。接口可以接受使用提示,如预期使用的功能或子应用程序。如果系统提供持久用户偏好服务,可以使用简单的学习算法(使用以前会话的平均统计数据)来学习用户的使用模式,客户端可以将此信息发送给命名服务。知道此扩展功能的客户端可以找到上下文并将其缩小到扩展接口,然后在请求解析对象引用时发送额外信息。这不会阻止其他客户端以标准形式使用命名上下文,只是服务不会那么优化。扩展的上下文接口还可以允许访问服务实例列表。

按 OAD 进行负载均衡

命名服务方法需要在请求到来之前运行多个服务实例并将它们绑定到命名上下文中。虽然这种方法可行,但如果服务未被使用,空闲进程会占用资源并降低其他服务的性能。因此,理想的解决方案是在需要时启动进程。

OAD 的功能是将服务映射到进程并管理这些进程。它负责为传入的客户端请求启动新进程或服务副本。标准的激活策略包括为每个客户端连接或每个客户端请求启动进程。常见的扩展包括每个用户一个进程,即使用户可以通过其他服务间接从不同的客户端进程请求连接。

由于大多数 OAD 在单个机器上工作,仅使用它们进行负载均衡可能没有太大价值,除非关键资源是文件描述符或线程。如果能找到支持 RPC 或 SNMP 的 OAD,可能会解决问题;否则,解决方案是联合本地 OAD。一种方法是在不同机器上定义一组 OAD,当请求启动进程时,它们的成员总是相互协调。另一种方法是设计一个整合服务,协调不同机器上的 OAD 以自动创建进程。在这两种情况下,联合需要知道服务可以在哪些机器上启动,以及哪些机器上已经有正在运行的进程。

将命名服务作为负载均衡协调器与基于 OAD 的机制结合使用可以产生良好的协同效应。许多当前的供应商 OAD 允许从 IOR 自动创建服务。IOR 实际上指向 ORB 的 OAD,并会在首次连接时根据激活策略从 OAD 转发到正确的进程。如果给定的 OAD 支持这一点,那么将这些 IOR 存储在命名服务中提供了一个不错且适度动态的解决方案。如果需要更动态的解决方案,命名服务可以负责增加服务实例的列表。当当前运行实例的负载超过阈值时,命名服务可以联系联合的 OAD 并请求启动新进程。OAD 联合将找到一台可以运行服务且尚未运行该服务的新机器。如果 OAD 能够启动一个新的有用进程,命名服务可以将其添加到列表中。在设置这样的系统时,重要的是提供一种机制,以便从命名服务列表中删除服务实例,从而释放进程。

命名服务/OAD 总结

涉及命名服务、交易服务和 OAD 的解决方案非常适合解决基本到中等复杂度的负载均衡需求。它们的一大优势是对服务本身是非侵入性的,并且对客户端完全透明。唯一可能的侵入是在追求更高精度时的指标收集,但通常用于负载均衡的相同指标对于监控运行时系统也很重要,并且无论如何都会收集这些指标。这意味着负载均衡系统可以建立在监控系统之上。

按工作进行负载均衡

在某些情况下,由于工作的资源密集型性质,按用户连接进行负载均衡是完全不合适的。虽然上述方法作为系统级技术效果很好,但在按服务评估负载均衡需求时,可能无法达到预期效果。例如,如果有几个关键的资源密集型方法,而其余请求产生的负载相对较小,那么在每个请求的基础上平衡这些昂贵方法的负载比按用户平衡更重要。这种方法非常精细,其目的是精确分配工作,因此需要非常准确的负载视图。规则可以很简单,例如不使用已经在处理请求的机器。但负载指标必须是当前和正确的。

这种负载均衡涉及将每个请求发送到不同的服务实例。因此,处理这些请求的服务最好是无状态的,这样可以避免在机器之间复制会话状态。虽然所有讨论的技术都受益于无状态,但有些技术比其他技术更具弹性。

简化服务

一种选择是定义一个只处理一种类型请求的完全无状态服务。每次客户端想要发出该类型的请求时,它从负载均衡的命名服务获取一个新引用,发出请求,然后忘记该对象引用。如果客户端需要再次发出请求,它从命名服务获取一个新引用。这种方法的一个缺点是依赖于客户端负责任地使用该机制。一个更大的潜在缺点是服务接口的不自然拆分,这可能会使系统退回到旧的 RPC 风格编程。不过,这种技术可以重用系统中现有的负载均衡机制。

客户端负责

另一种选择是让客户端决定整个生命周期内所需的性能类型。这可以有或没有用户干预,不过让客户端应用程序向用户询问性能和优先级要求可能很有用。客户端在能够提高性能且有能力这样做时切换服务实例。如果服务是有状态的,但客户端可以承受丢失当前会话状态,那么客户端应用程序可以放弃会话并返回命名服务。这使得系统可以在可能的情况下调整平衡,同时让客户端安全地保留其会话信息。另一种选择是让客户端向用户询问最低性能要求,然后监控请求的性能。如果性能下降,用户可以选择中止当前作业并将其重新发送到另一个服务实例。这种技术的实现通常涉及客户端获取服务实例列表(可能从扩展的命名上下文)并直接检查负载。这再次允许客户端定义其优先级和性能标准并进行适当选择。通常,整个机制隐藏在智能服务代理对象中。许多 ORB 供应商提供这样的 API 钩子,通过它对象引用会自动缩小为用户定义的对象类型而不是默认生成的代理。所有请求都必须通过代理,因此代理可以为每个方法调用决定将调用发送到哪个服务实例。如果服务是有状态的,代理可以决定维护一个主会话,但将不需要状态的调用委托出去。或者,它可以维护多个会话,仅复制那些更改会话状态的调用,以便可以自由分配所有其他调用。另一种选择是让客户端代理在本地缓存状态,并将其复制到想要与之通信的服务。这种方法的最大缺点是需要维护客户端代码。此外,由于客户端通常比服务多得多,如果所有客户端都向监控服务发出多个指标请求,这将产生比与监控服务位于同一台机器上的负载均衡命名服务更多的流量。这也是一个非常狭窄的解决方案,可能会干扰服务的可维护性和变更管理,并且可能与瘦客户端的发展趋势相悖。不过,它的好处包括可能与用户进行有趣和有用的交互,保持服务接口的一致性,并且不影响服务,特别是在状态复制方面。赋予客户端代理切换服务实例和复制状态的权力也将强大的故障转移机制与负载均衡相结合。

服务门面

一种折中的方法是使用服务门面。这种方法使用一个维护其他服务实例列表的服务版本。客户端获取对该服务的引用,该服务的实现将请求委托给其他服务实例进行实际工作。除了支持用户干预的代码外,所有可以放在智能代理中的代码都可以放在门面中,甚至可以包括状态复制。因此,门面作为服务的远程代理而不是本地代理。

服务与工作者

将门面策略进一步提炼,会产生一个主服务和多个工作者从服务的想法。主服务维护状态,任何需要平衡的请求都会与相关的会话状态一起重新打包并发送到其中一个工作者。在这种情况下,工作者的接口不需要与主服务相同,因此主服务可以是有状态的,而工作者为每个请求接收所需的所有信息。客户端只看到主服务,工作者接口完全隐藏。如果请求的重新打包可以放在一个对象中(所有 CORBA 对象都在请求对象中表示),那么可以反转负载均衡的智能。如果主服务需要决定哪个工作者可以接下来处理请求,它需要能够比较机器和负载。相反,服务可以将请求放入队列。每个工作者在决定可以处理另一个请求时,从队列中获取一个请求并进行处理。显然,这种技术需要一个异步机制来从工作者获取结果并将其返回给客户端。这需要为每个作业添加一个标签,以便可以追溯到特定的客户端请求。即使工作者 - 服务接口必须是异步的,客户端 - 服务接口可以保持同步。处理客户端请求的线程可以简单地挂起,阻塞客户端,直到从工作者收到回复。

综上所述,在分布式系统部署中,故障转移和负载均衡是确保系统稳定运行和高效性能的关键因素。通过合理设计状态管理、故障处理、负载指标和均衡策略,可以提高系统的可用性、可扩展性和性能。在实际应用中,需要根据系统的具体需求和特点,选择合适的方法和技术来实现故障转移和负载均衡。

以下是一个简单的 mermaid 流程图,展示了按工作进行负载均衡的基本流程:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([客户端请求]):::startend --> B{请求类型}:::decision
    B -->|资源密集型| C(选择合适的服务实例):::process
    C --> D(发送请求到服务实例):::process
    D --> E(服务实例处理请求):::process
    E --> F(返回结果给客户端):::process
    B -->|非资源密集型| G(按常规方式处理):::process
    G --> F

下面是一个表格,总结了不同负载均衡方式的优缺点:
| 负载均衡方式 | 优点 | 缺点 |
| — | — | — |
| 按命名服务 | 非侵入性,对客户端透明,可利用现有监控指标 | 需要多个服务实例预先运行,依赖运行时负载估计 |
| 按 OAD | 可动态启动进程,与命名服务协同良好 | 实现较复杂,需要处理 OAD 联合和服务实例管理 |
| 按工作(简化服务) | 可重用负载均衡机制 | 服务接口拆分不自然,依赖客户端使用 |
| 按工作(客户端负责) | 可根据客户端需求调整,结合故障转移 | 需要维护客户端代码,产生较多流量 |
| 按工作(服务门面) | 提供远程代理,可包含状态复制 | 增加额外的服务层 |
| 按工作(服务与工作者) | 主服务有状态,工作者无状态,隐藏工作者接口 | 需要异步机制处理结果返回 |

分布式系统部署架构考量:故障转移与负载均衡策略(续)

不同负载均衡方式的详细对比与应用场景分析

为了更清晰地了解各种负载均衡方式的特点和适用场景,我们进一步对它们进行详细对比。

负载均衡方式 适用场景 具体操作步骤
按命名服务 适用于负载指标围绕客户端会话,且需要对客户端透明的场景。例如,在一个多用户的在线购物系统中,不同用户的会话负载可能不同,通过命名服务进行负载均衡可以将用户分配到负载较轻的服务器上。 1. 实现命名上下文接口,将名称绑定到一个引用列表。
2. 当客户端首次使用命名服务定位服务器时,命名上下文向监控服务询问当前负载指标。
3. 根据负载指标选择最适合的服务实例引用并返回给客户端。
4. 如果服务实例负载达到最大值,命名服务拒绝客户端访问。
按 OAD 适用于需要动态启动进程,且希望与命名服务协同工作的场景。比如,在一个云计算环境中,根据用户的请求动态创建服务进程。 1. 定义 OAD 联合,使其知道服务可以启动的机器和已运行进程的机器。
2. 当客户端请求到来时,OAD 根据激活策略启动新进程或使用已有进程。
3. 将 IOR 存储在命名服务中,实现服务的自动创建和转发。
4. 当负载超过阈值时,命名服务联系 OAD 启动新进程,并将其添加到服务实例列表。
按工作(简化服务) 适用于服务处理的请求类型单一,且希望重用系统现有负载均衡机制的场景。例如,一个专门处理文件上传的服务。 1. 定义只处理一种类型请求的完全无状态服务。
2. 客户端每次请求时从负载均衡的命名服务获取新引用。
3. 客户端发出请求并忘记该引用,下次请求再获取新引用。
按工作(客户端负责) 适用于客户端能够根据自身需求调整性能,且希望结合故障转移机制的场景。例如,在一个复杂的数据分析系统中,客户端可以根据分析任务的紧急程度和资源需求选择合适的服务实例。 1. 客户端获取服务实例列表,可从扩展的命名上下文获取。
2. 客户端直接检查负载,根据自身优先级和性能标准选择服务实例。
3. 客户端在性能下降时可切换服务实例,或请求用户干预。
4. 客户端代理可在本地缓存状态并复制到服务。
按工作(服务门面) 适用于需要在服务层进行请求委托和状态管理的场景。例如,在一个企业级的业务系统中,服务门面可以统一管理多个子服务。 1. 创建一个维护其他服务实例列表的服务门面。
2. 客户端获取对服务门面的引用。
3. 服务门面将请求委托给其他服务实例进行实际工作。
4. 服务门面可进行状态复制等操作。
按工作(服务与工作者) 适用于主服务需要维护状态,而工作者负责具体处理请求的场景。例如,在一个分布式计算系统中,主服务负责任务分配和状态管理,工作者负责计算任务。 1. 主服务维护状态,将需要平衡的请求与会话状态重新打包。
2. 主服务将请求放入队列。
3. 工作者从队列中获取请求并处理。
4. 通过异步机制将结果返回给客户端,客户端 - 服务接口保持同步。
故障转移与负载均衡的协同工作

在实际的分布式系统中,故障转移和负载均衡并不是孤立的过程,而是需要协同工作以确保系统的高可用性和性能优化。以下是它们协同工作的流程图:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px;
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px;
    classDef decision fill:#FFF6CC,stroke:#FFBC52,stroke-width:2px;

    A([系统运行]):::startend --> B{是否检测到故障}:::decision
    B -->|是| C(启动故障转移流程):::process
    C --> D(选择新的服务实例):::process
    D --> E(将请求重新路由到新实例):::process
    E --> F(负载均衡器调整负载分配):::process
    F --> G(继续系统运行):::process
    B -->|否| H(正常负载均衡):::process
    H --> G

从流程图可以看出,当系统检测到故障时,首先启动故障转移流程,选择新的服务实例并将请求重新路由。然后,负载均衡器根据新的服务实例情况调整负载分配,以确保系统的整体性能。在正常情况下,系统则进行常规的负载均衡操作。

实际应用案例分析

为了更好地理解故障转移和负载均衡在实际中的应用,我们以一个在线视频播放平台为例进行分析。

系统架构概述

该平台由多个视频服务器、负载均衡器、命名服务和 OAD 组成。视频服务器负责存储和播放视频,负载均衡器根据服务器的负载情况将用户请求分配到合适的服务器上,命名服务用于定位服务器,OAD 负责管理服务器进程。

故障转移的应用

当某个视频服务器出现故障时,系统会检测到故障信号。根据故障转移机制,OAD 会尝试重新启动该服务器。如果无法启动,系统会选择一个新的视频服务器,并通过命名服务更新服务器引用。同时,负载均衡器会将原本分配到故障服务器的用户请求重新分配到其他可用的服务器上,确保用户能够继续正常观看视频。

负载均衡的应用

在正常运行时,负载均衡器会根据服务器的负载指标,如 CPU 利用率、带宽使用情况等,将用户请求分配到负载较轻的服务器上。例如,如果某个服务器的 CPU 利用率较高,而另一个服务器的带宽使用较低,负载均衡器可能会将一个对带宽要求较高的视频播放请求分配到后者。

按命名服务进行负载均衡时,用户在首次访问平台时,命名服务会根据服务器的负载情况选择一个合适的视频服务器,并将其引用返回给用户。如果服务器的负载发生变化,命名服务会动态调整服务器引用,以确保用户始终能够获得较好的观看体验。

按 OAD 进行负载均衡时,当用户请求增加时,OAD 会根据激活策略动态启动新的视频服务器进程。例如,如果采用按用户激活策略,当有新用户登录时,OAD 会为该用户启动一个新的服务器进程。

按工作进行负载均衡时,对于一些资源密集型的操作,如高清视频转码,系统会选择合适的服务器进行处理。例如,将转码任务分配到具有较高计算能力的服务器上,以提高处理效率。

协同工作的效果

通过故障转移和负载均衡的协同工作,该在线视频播放平台能够在服务器故障时快速恢复服务,同时在正常运行时保持良好的性能。用户在观看视频时不会因为服务器故障或负载过高而出现卡顿或无法播放的情况,提高了用户体验和平台的可用性。

总结与建议

在分布式系统部署中,故障转移和负载均衡是确保系统稳定运行和高效性能的关键因素。通过合理设计状态管理、故障处理、负载指标和均衡策略,可以提高系统的可用性、可扩展性和性能。

以下是一些建议:
1. 选择合适的负载指标 :根据系统的特点和需求,选择合适的负载指标,如请求指标、机器指标、使用指标和全局指标。在实际应用中,可以结合多种指标进行综合评估。
2. 设计灵活的故障转移机制 :考虑服务的状态和依赖关系,设计灵活的故障转移机制。例如,对于有状态的服务,要确保会话状态的正确恢复;对于服务之间的依赖关系,要能够及时处理。
3. 结合多种负载均衡方式 :根据不同的应用场景,结合使用按命名服务、按 OAD 和按工作等多种负载均衡方式。例如,在全局层面可以使用按命名服务进行负载均衡,在服务内部可以采用按工作进行负载均衡。
4. 注重系统的可维护性和可扩展性 :在设计系统时,要注重系统的可维护性和可扩展性。例如,避免过于复杂的负载均衡策略,确保系统易于理解和维护;同时,要考虑系统的扩展性,以便在未来能够方便地添加新的服务和服务器。
5. 进行性能测试和优化 :在系统部署前,进行充分的性能测试,评估系统的性能和负载均衡效果。根据测试结果进行优化,调整负载均衡策略和参数,以提高系统的性能和稳定性。

通过以上措施,可以构建一个高效、稳定的分布式系统,满足用户的需求并应对各种挑战。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值