在云环境中运行时,应用程序需要具有弹性。网络通信方面特别容易出现故障。添加网络弹性的一种常见模式是创建一个导入到应用程序中的库,该库提供本附录中描述的网络弹性模式。但是,导入的库很难维护以多种语言编写的服务,且当新版本的网络库发布时,会增加应用程序测试和重新部署的负担。

取代应用程序处理网络弹性逻辑的另一种方式是,可以将代理置于适当的位置,作为应用程序的保护和增强层。代理的优势在于避免应用程序需要额外的复杂代码,尽量减少开发人员的工作量。

可以在连接层(物理或 SDN),应用程序或透明代理中处理网络弹性逻辑。虽然代理不是传统网络堆栈的一部分,但它们可用于透明地管理应用程序的网络弹性。

透明代理可以在基础架构中的任何位置运行,但与应用程序的距离越近越有利。代理支持的协议还要尽可能全面,且可以代理的开放系统互连模型(OSI 模型)层。

通过实施以下模式,代理在基础架构的弹性中扮演着积极的角色:

  • 负载均衡
  • 负载切分(Load shedding)
  • 服务发现
  • 重试和 deadline
  • 断路

代理也可以用来为应用程序添加功能。包括:

  • 安全和认证
  • 路由(入口和出口)
  • 洞察和监测

负载均衡

应用程序负载均衡的方式有很多,应始终将负载均衡器放在云原生应用程序之前的原因有:

DigitalOcean 在“5 个 DigitalOcean 负载均衡器使用案例”中给出了一些很好的理由:

  • 水平缩放
  • 高可用性
  • 应用程序部署
  • 动态流量路由

协调透明代理(例如 Envoy 和 Linkerd)是负载均衡应用程序的一种方式。具有透明代理句柄负载均衡的一些好处是:

  • 对所有端点的请求视图允许更好的负载均衡决策。
  • 基于软件的负载均衡器可灵活选择正确的方式来平衡负载。

透明代理不必盲目地将流量传递给下一个路由器。正如 Bunyan 在其博客文章“超越循环:负载均衡延迟”中指出的,他们可以集中协调以对基础架构有更广泛的了解。这使得负载均衡能够从全局优化流量路由,而不是仅为本地优化快速分组切换。

随着对端点中哪些服务正在发送和接收请求有了更深的了解,代理可以更合理地向发送流量。

负载切分

“站点可靠性工程”手册解释了负载切分(Load shedding)与负载均衡不同。尽管负载均衡试图找到正确的后端来发送流量,但是如果应用程序无法接受请求,负载剔除会有意地丢弃流量。

通过删除负载来保护应用程序实例,可以确保应用程序不会重新启动或被迫进入不利条件。删除请求比等待超时并要求重新启动应用程序要快得多。

当发生中断或流量过多时,减载可以帮助保护应用程序实例。一切正常时,应用程序应该通过服务发现发现其他相关服务。

服务发现

服务发现通常由运行服务的编排系统处理。透明代理可以绑定到相同的数据并提供附加功能。

代理可以通过将多个源绑定在一起(例如,DNS 和键值数据库)并将它们呈现在统一接口中来增强标准服务发现。这允许实现者在不重写所有应用程序代码的情况下改变其后端。如果在应用程序之外处理服务发现,则可以更改服务发现工具而不必重写任何应用程序代码。

由于代理可以对基础架构中的请求提供更全面的视图,因此可以决定端点何时健康与否。这与其他功能配合使用,例如负载均衡和重试,以将流量路由到最佳端点。

当允许服务彼此发现时,代理服务器还可以考虑额外的元数据。它们可以实现逻辑,如节点延迟或“距离”,以确保为请求发现正确的服务。

重试和 deadline

通常,应用程序会使用内置逻辑来知道如何处理对外部服务失败的请求。这也可以由代理无需额外的应用程序代码来处理。

代理拦截应用程序的所有入口和出口流量并路由请求。如果传出请求失败,代理可以自动重试,而无需涉及应用程序。如果请求因任何其他原因返回,则代理可以根据其配置中的规则进行适当处理。

这很好,只要应用程序对延迟有弹性。否则,代理应根据申请截止日期返回失败通知。

截止日期允许应用程序指定允许请求的时间长度。由于代理可以“追踪”到目的地和返回的请求,因此它可以在使用代理的所有应用程序中强制执行最终期限策略。

当超过 deadline 时,失败将返回给应用程序,并且可以决定适当的操作。选项可能会降级服务,但应用程序也可能选择将错误发回给用户。

断路

该模式根据家用的断路器命名。当一切正常时,电路默认为“关闭”状态,允许流量流过断路器。当检测到故障时,电路“打开”并切断流量。

重试模式使应用程序能够重试操作,以期成功。断路器模式阻止应用程序执行可能失败的操作。

——Alex Homer,云设计模式:云应用程序指令性架构指南

断开的电路可以是单个端点或整个服务。打开后,不会发送任何流量,所有发送流量的尝试都将立即返回失败。

与家用电路不同,即使处于打开状态,代理也可以测试失败的端点。当检测到故障后再次可用时,可将损坏的端点置于“半开”状态。此状态将发送少量流量,直到端点被标记为失败或健康。

这种模式可以使得应用程序快速失败,并且只能发送到健康端点,从而使应用程序更快。通过不断检查端点,网络可以自行修复并智能地路由流量。

除了这些弹性功能外,代理还可以通过以下方式增强应用程序。

TLS 和身份验证

代理可以终止传输层安全性(TLS)或代理支持的任何其他安全性。这使得安全逻辑能够集中管理,而不是在每个应用程序中重新实现。然后可以在整个基础架构中更新安全协议或证书,而无需重新部署应用程序。

身份验证也是如此。但是,授权仍应由应用程序管理,因为它通常是更细粒度的应用程序特定功能。在应用程序监督它们之前,用户会话 cookie 可以由代理验证。这意味着只有通过认证的流量才会被应用程序看到。

这不仅可以节省应用程序的时间,还可以防止某些类型的滥用导致的停机。

路由(入口和出口)

当代理在所有应用程序之前运行时,它们控制流入和流出应用程序的流量。它们还可以管理流入和流出集群的流量。

正如反向代理可以用于在 N 层体系结构中将流量路由到后端一样,服务代理也可能暴露于集群外部,用来路由到达的请求。这里的代理知道流量的另一个数据点来自何处和目的地。

具有对所有服务间通信的深入了解的反向代理,可以比传统的反向代理更好地了解路由选择。

洞察和监控

利用所有关于基础架构内流量流的知识,代理系统可以公开关于单个端点和整个集群范围内的流量视图的指标。这些数据点传统上已经在专有网络系统或难以自动化的协议中暴露出来(例如,SNMP)。

由于代理可以立即知道何时端点无法访问,所以它们也最先了解端点何时不健康。虽然编排系统也可以检查应用程序运行状况,但应用程序可能不知道向编排工具报告不健康的状态。有了对同一服务所有端点的了解后,代理也可以成为监控服务运行状况的最佳位置。