
技术行业正向更环保的做法转变,谷歌、亚马逊和Meta等大公司正在引领这一潮流。然而,采用复杂的分布式架构有时可能与这些可持续性目标背道而驰。尽管行业一直在积极地从单体架构过渡到微服务架构,但研究表明,与传统的单体架构相比,微服务通常消耗更多的 CPU、内存和网络资源。《对象技术杂志》和奥尔堡大学进行的比较分析显示,微服务架构比单体架构多消耗大约 20%的 CPU 和 44%的能源。
鉴于这一挑战,找出能让微服务更节能的方法至关重要。本文探讨了如何通过精心的设计和运营策略来降低微服务的能耗。
构建更环保的微服务
微服务由于其分布式特性,本质上比单体应用能耗更高,这通常导致网络流量增加和资源开销增大。不过,通过仔细定义服务边界和优化服务部署方式,组织能够大幅降低其微服务架构的能耗。这些优化措施主要分为两类:设计相关的效率提升和运营相关的效率提升。
设计相关的效率提升
要在微服务架构中优化能源效率,定义有效的服务边界是关键。这涉及两种互补策略:1)将每个领域封装在单个服务中,以最小化服务间通信;2)选择服务粒度时,不仅要考虑可扩展性、性能和组织对齐,还要兼顾能源效率。
领域封装
如果单个领域没有封装在一个服务中,它不可避免地会在服务之间创建紧密耦合,并增加相互依赖性。简单的请求可能需要跨多个服务进行协调,从而导致通信模式变得繁琐,维护分布式数据一致性的开销也更大。
完全封装领域的服务边界可以显著减少服务间调用,不仅减少了网络流量,还降低处理每个额外请求所需的处理能力。例如,如图 1 所示,假设用户需要检索汽车库存。由于库存系统分布在服务 A、B 和 C 中,总共需要八次服务调用才能收集所有所需信息。同样,检索订单或支付也因为领域分布在不同服务中而需要多次网络调用。然而,如果每个领域都隔离在自己的服务中,那么对于仅限于单个领域的简单查询,这些服务就不需要相互调用,所需的调用次数也会显著减少。在这种情况下,检索库存现在只需要两次调用,因为服务 A 不需要调用服务 B 和 C。

图 1. 正确与错误的服务边界定义对服务间调用的影响。
此外,如果单个领域没有封装在一个服务中,单个请求可能涉及在几个不同的数据库中更新紧密耦合的数据。如果一个服务未能成功完成其操作,可能需要在多个服务中回滚更改以保持数据的一致性。因此,需要更多的 CPU 和网络调用来进行多个服务的额外更新。考虑以下图表,它显示了在服务 C 中创建数据失败导致服务 A 和 B 回滚,需要跨服务进行额外的处理。

图 2:更新分布在不同服务中的同一领域的数据需要大量的网络调用。
这种协调数据修改和回滚的额外开销是各种分布式算法的常见挑战,如两阶段提交、三阶段提交、SAGA 模式等。例如,图 3 展示了 SAGA 编排模式,突出显示了事务中的每一步都需要多个网络调用和系统内的额外处理。

图 3:SAGA 编排模式中的大量网络调用。
然而,如果库存领域被整合到单个服务中,更新和回滚都可以通过单个数据库事务来管理。这允许数据库以原子方式处理提交或回滚操作,从而消除了在多个服务间协调这些操作所需的额外计算或网络调用。

图 4. 分布式数据的合适服务边界定义。
服务粒度
微服务的粒度指的是它处理的责任范围,即多少业务领域被整合到单个服务中。例如,订单、支付和库存可以分别实现为单独的服务,也可以合并为一个单一的、整合的服务。

图 5. 整合服务与独立服务。
当服务被整合时,服务间的通信会减少,从而降低网络流量和处理开销。然而,过度的整合可能会导致形成一个单体应用,从而削弱模块化设计的优势。最佳的方法是保持平衡:
如果业务领域之间紧密相互依赖,将它们整合到一个服务中有助于最小化通信开销,并简化分布式事务,从而提高能源效率。
如果业务领域在逻辑上独立且交互较少,将它们分离到不同的服务中可以实现独立部署,而不会产生显著的网络开销。这使得能够针对每个服务的工作负载制定更高效的资源分配策略。
以下步骤有助于在架构设计阶段评估是否需要合并或分离服务:
步骤 1:确定依赖程度
绘制出各个领域之间交互的各种场景(例如,API 调用、事件等),包括故障案例。例如,考虑以下序列图,它展示了订单、库存和支付领域之间的各种交互场景。

图 6. 序列图表示设计阶段的领域交互。
步骤 2:探索最小化相互依赖的策略
评估是否可以应用任何策略来最小化领域之间的相互依赖,从而减少网络开销和计算负载的能耗。一些例子包括:
缓存:当一个领域频繁访问另一个领域的数据时使用缓存,以减少冗余的 API 调用和数据库查询。
数据反规范化:跨领域复制数据可以帮助消除实时依赖。
批量 API 调用:将多个请求聚合到一个批量调用中有助于减少网络调用的次数。
例如,在上述示例中,为单个订单进行了多次支付收集调用。这可以通过将它们合并到一个批量 API 调用中进行优化。

图 7. 序列图表示优化后的领域交互。
步骤 3:重新评估依赖程度
在减少交互次数进行优化之后,如果领域间的依赖程度仍然很高,考虑将它们合并到一个服务中以减少网络开销。如果依赖程度较低,保持领域分离,以便更灵活地部署。在上述示例中,如果订单和库存领域高度依赖,而支付领域松散耦合,那么可以将订单和库存合并到一个服务中,而支付则可以保持为独立服务。

图 8. 将相互依赖的领域合并到一个服务中。
在考虑性能、可扩展性和开发团队等因素时,找到最优的服务粒度和相互依赖关系对于架构良好的微服务至关重要。事实证明,找到这些最优边界通常会使整个系统更节能。
与运营相关的效率
基于位置的调度
一些数据中心的碳效率明显高于其他数据中心。它们的效率取决于多种因素,包括冷却方法、硬件和电力来源。在碳效率高的数据中心部署应用程序通常更具可持续性。许多云服务提供商提供哪些区域碳效率更高的数据。图 9 展示了谷歌如何在不同区域发布其数据。

图 9. 谷歌云区域的碳数据。来源:谷歌云网站。访问日期:2025 年 6 月 14 日。
在部署应用程序时,这些数据有助于做出更明智、更可持续的区域选择决策。由于微服务本质上更细粒度,因此可以战略性地部署以提高整体能源效率:
对延迟敏感且依赖频繁用户交互的微服务应部署在更靠近终端用户的位置。。这可减少网络开销,并通过降低数据传输成本来提高能源效率。
批量处理微服务,如分析管道或报告任务,可以部署在碳效率较高的区域。这些服务通常不需要实时响应,并且可以利用低碳基础设施。

图 10. 根据微服务的类型进行基于位置的部署。
需要注意的是,虽然在碳效率高的区域部署微服务可以提高可持续性,但关于位置的架构决策总是涉及与性能、成本和数据可访问性等属性相关的权衡。例如,考虑这样一种场景:分析服务部署在一个碳效率高的区域,其相关数据源也集中放置以实现最佳的能源效率。虽然这种设置可能将分析工作负载的碳足迹降至最低,但它可能会为需要从不同区域访问相同数据的其他服务带来更高的延迟和降低性能。因此,架构师必须根据系统的优先级和使用模式来评估并平衡可持续性与其他属性。
优化资源扩展
在为微服务分配资源时,考虑以下流量特征:
突发性
自动扩展会根据需求变化动态调整资源,在需求增加时扩展资源,在需求减少时缩减资源。然而,反应式自动扩展可能无法对突发的流量高峰做出足够迅速的反应,从而可能导致临时的资源过度或不足配置。

图 11. 在流量激增期间自动扩展导致的过度配置。
为了以节能的方式处理此类流量激增,可以考虑实施排队机制。可以在关键入口服务处放置一个队列,该队列将限制传入请求,并因此减慢所有下游微服务的请求处理速度。这种方法牺牲了即时性能以提高能效,因为它避免了快速且可能过度的扩展。最终,所有请求都会在一些延迟后被处理,从而使系统能够吸收流量高峰,而无需进行不必要的资源分配。

图 12. 在流量激增期间资源分配保持不变。
非关键性
微服务的粒度优势在于可以根据各个服务的重要性来分配资源。虽然关键服务需要保证资源以维持性能,但非关键任务可以分配较少的资源以优先考虑能效。例如,在非高峰时段批量处理请求的机制可以帮助确保所有请求都被处理,而速率限制可以在高峰时段通过拒绝过多请求来控制服务负载。

图 13. 即使负载较高,非关键服务的资源分配仍保持不变。
延迟敏感性
对于性能优先的服务,资源通常需要持续可用,并且可能需要过度配置以尽量减少响应时间。这种做法本身会导致能源效率降低。
工作负载整合
为了优化资源分配,推荐的做法是保持服务器之间的平均 CPU 利用率在 50%到 80%之间。利用率超过 80%可能会由于资源争用和线程饥饿而导致性能下降,而低于 50%的水平通常表明资源未充分利用。资源未充分利用是个问题,因为机器运行所需的“始终在线”能耗是一种基础设施税,仅仅是为了让机器保持运行。如果服务器相对于其能耗所做的工作很少,其能效比就会变得很差。可以将其想象成在交通灯前空转而消耗燃料——消耗了能源,但没有取得任何进展。
在微服务架构中,服务通常是细粒度且轻量级的,这意味着它们可能无法充分利用节点的容量。因此,在同一节点上共置多个服务可以提高效率并降低总体能耗。例如(如图 13 所示),如果服务 A、B 和 C 分别消耗 20%、10%和 25%的 CPU,并且分布在多个节点上,那么相当一部分计算能力将处于闲置状态。将这些工作负载整合到单个节点上,可以减少集群中活跃节点的总数,从而通过消除已退役服务器的空闲功耗来节省能源。注意:这个例子已做简化以供说明。在实践中,微服务通常部署在多个节点上,以确保更高的可用性和容错性。
容器通过提供轻量级的封装来实现这种整合,允许多个服务能够在同一节点上运行而不会出现依赖冲突。像 Kubernetes 这样的容器编排平台可以通过允许开发人员定义期望的输出并根据该输出来处理调度以自动化这个过程。

图 14. 工作负载整合实现资源消耗的优化。
此外,如果某个服务仅在有限时间内需要,完全关闭它通常是最节能的方法,这种做法被称为“轻触开关运维”(LightswitchOps)。然而,当服务必须全天候可用时,可以采用后台调度来进一步优化资源使用。例如,考虑主要处理日间流量的服务 A、B 和 C,以及需要 50% CPU 但不受时间限制的批量处理服务 D。通过在服务 A、B 和 C 的同一节点上安排服务 D 在非高峰时段运行,可以提高整体资源利用率。这种方法有助于将平均 CPU 利用率保持在 50%到 80%的理想范围内,而不会使系统资源过载。

图 15. 允许优化资源消耗的后台调度。
结论
尽管微服务本质上更耗能,但通过深思熟虑的设计选择,减少不必要的相互依赖,并以优化能耗的方式部署它们,是有可能提高它们的效率的。由于微服务具有可扩展性和更快的开发速度等优势,它继续主导着软件架构,因此开发人员必须将能效作为首要考虑因素。通过这种方式,可以利用微服务的优势,同时提高软件系统的可持续性。
原文链接:
评论