分布式系统在 Kubernetes 上的进化

本文翻译自 Bilgin Ibryam 的文章 The Evolution of Distributed Systems on Kubernetes。

作者 Bilgin Ibryam 译者 张晓辉 发表于 2021年3月29日

本文译自 The Evolution of Distributed Systems on Kubernetes

在 3 月份的 QCon 上,我做了一个关于 Kubernetes 的分布式系统进化的演讲。首先,我想先问一个问题,微服务之后是什么?我相信大家都有各自的答案,我也有我的答案。你会在最后发现我的想法是什么。为了达到这个目的,我建议大家看看分布式系统的需求是什么?以及这些需求在过去是如何发展的,从单体应用开始到 Kubernetes,再到最近的 Dapr、Istio、Knative 等项目,它们是如何改变我们做分布式系统的方式。我们将尝试对未来做一些预测。

现代分布式应用

为了给这个话题提供更多的背景信息,我认为的分布式系统是由数百个组件组成的系统。这些组件可以是有状态的、无状态的或者无服务器的。此外,这些组件可以用不同的语言创建,运行在混合环境上,并开发开源技术、开放标准和互操作性。我相信你可以使用闭源软件来构建这样的系统,也可以在 AWS 和其他地方构建。具体到这次演讲,我将关注 Kubernetes 生态系统,以及你如何在 Kubernetes 平台上构建这样一个系统。

我们从分布式系统的需求讲起。我认为是我们要创建一个应用或者服务,并写一些业务逻辑。那从运行时的平台到构建分布式系统,我们还需要什么呢?在底层,最开始是我们要一些生命周期的能力。当你用任一语言开发你的应用时,我们希望有能力把这个应用可靠地打包和部署、回滚、健康检查。并且能够把应用部署到不同的节点上,并实现资源隔离、扩展、配置管理,以及所有这些。这些都是你创建分布式应用所需要的第一点。

第二点是围绕网络。我们有了应用之后,我们希望它能够可靠地连接到其他服务,无论该服务是在集群内部还是在外部。我们希望其具有服务发现、负载均衡的能力。为了不同的发布策略或是其他的一些原因的我们希望有流量转移的能力。然后我们还希望其具有与其他系统进行弹性通信的能力,无论是通过重试、超时还是断路器。要有适当的安全保障,并且要有足够的监控、追踪、可观察性等等。

我们有了网络之后,接下来就是我们希望有能力与不同的 API 和端点交互,即资源绑定–与其他协议和不同的数据格式交互。甚至能够从一种数据格式转换成另一种数据格式。我还会在这里加入诸如过滤功能,也就是说,当我们订阅一个主题时,我们也许只对某些事件感兴趣。

你认为最后一类是什么?是状态。当我在说状态和有状态的抽象时,我并不是在谈论实际的状态管理,比如数据库或者文件系统的功能。我要说的更多是有关幕后依赖状态的开发人员抽象。可能,你需要具有工作流管理的能力。也许你想管理运行时间长的进程或者做临时调度或者某些定时任务来定期运行服务。也许你还想进行分布式缓存,具有幂等性或者支持回滚。所有这些都是开发人员级的原语,但在幕后,它们依赖于具有某种状态。你想随意使用这些抽象来创建完善的分布式系统。

我们将使用这个分布式系统原语的框架来评估它们在 Kubernetes 和其他项目上的变化情况。

单体架构——传统中间件功能

假设我们从单体架构以及如何获得这些能力开始。在那种情况下,首先是当我说单体的时候,在分布式应用的情况下我想到的是 ESB。ESB 是相当强大的,当我们检查我们的需求列表时,我们会说 ESB 对所有有状态的抽象有很好的支持。

使用 ESB,你可以进行长时间运行的流程的编排、分布式事务、回滚和幂等。此外,ESB 还提供了出色的资源绑定能力,并且有数百个连接器,支持转换、编排,甚至有联网功能。最后,ESB 甚至可以做服务发现和负载均衡。

它具有围绕网络连接的弹性的所有功能,因此它可以进行重试。可能 ESB 本质上不是很分布式,所以它不需要非常高级的网络和发布能力。ESB 欠缺的主要是生命周期管理。因为它是单一运行时,所以第一件事就是你只能使用一种语言。通常是创建实际运行时的语言,Java、.NET 或者其他的语言。然后,因为是单一运行时,我们不能轻松地进行声明式的部署或者自动调配。部署是相当大且非常重的,所以它通常涉及到人机交互。这种单体架构的另一个难点是扩展:“我们无法扩展单个组件。”

最后却并非最不重要的一点是,围绕隔离,无论是资源隔离还是故障隔离。使用单体架构无法完成所有这些工作。从我们的需求框架来看,ESB 的单体架构不符合条件。

云原生架构——微服务和 Kubernetes

接下来,我建议我们研究一下云原生架构以及这些需求是如何变化的。如果我们从一个非常高的层面来看,这些架构是如何发生变化的,云原生可能始于微服务运动。微服务使我们可以按业务领域进行拆分单体应用。事实证明,容器和 Kubernetes 实际上是管理这些微服务的优秀平台。让我们来看一下 Kubernetes 对于微服务特别有吸引力的一些具体特性和功能。

从一开始,进行健康状况探测的能力就是 Kubernetes 受欢迎的原因。在实践中,这意味着当你将容器部署到 Pod 中时,Kubernetes 会检查进程的运行状况。通常情况下,该过程模型还不够好。你可能仍然有一个已启动并正在运行的进程,但是它并不健康。这就是为什么还可以使用就绪度和存活度检查的原因。Kubernetes 会做一个就绪度检查,以确定你的应用在启动期间何时准备接受流量。它将进行活跃度检查,以检查服务的运行状况。在 Kubernetes 之前,这并不是很流行,但今天几乎所有语言、所有框架、所有运行时都有健康检查功能,你可以在其中快速启动端点。

Kubernetes 引入的下一个特性是围绕应用程序的托管生命周期——我的意思是,你不再控制何时启动、何时关闭服务。你相信平台可以做到这一点。Kubernetes 可以启动你的应用;它可以将其关闭,然后在不同的节点上移动它。为此,你必须正确执行平台在应用启动和关闭期间告诉你的事件。

Kubernetes 流行的另一件特性是围绕着声明式部署。这意味着你不再需要启动服务;检查日志是否已经启动。你不必手动升级实例——支持声明式部署的 Kubernetes 可以为你做到这一点。根据你选择的策略,它可以停止旧实例并启动新实例。此外,如果出现问题,可以进行回滚。

另外就是声明你的资源需求。创建服务时,将其容器化。最好告诉平台该服务将需要多少 CPU 和内存。Kubernetes 利用这些信息为你的工作负载找到最佳节点。在使用 Kubernetes 之前,我们必须根据我们的标准将实例手动放置到一个节点上。现在,我们可以根据自己的偏好来指导 Kubernetes,它将为我们做出最佳的决策。

如今,在 Kubernetes 上,你可以进行多语言配置管理。无需在应用程序运行时进行配置查找就可以进行任何操作。Kubernetes 会确保配置最终在工作负载所在的同一节点上。这些配置被映射为卷或环境变量,以供你的应用程序使用。

事实证明,我刚才谈到的那些特定功能也是相关的。比如说,如果要进行自动放置,则必须告诉 Kubernetes 服务的资源需求。然后,你必须告诉它要使用的部署策略。为了让策略正确运行,你的应用程序必须执行来自环境的事件。它必须执行健康检查。一旦采用了所有这些最佳实践并使用所有这些功能,你的应用就会成为出色的云原生公民,并且可以在 Kubernetes 上实现自动化了(这是在 Kubernetes 上运行工作负载的基本模式)。最后,还有围绕着构建 Pod 中的容器、配置管理和行为,还有其他模式。

我要简要介绍的下一个主题是工作负载。从生命周期的角度来看,我们希望能够运行不同的工作负载。我们也可以在 Kubernetes 上做到这一点。运行十二要素应用程序和无状态微服务非常简单。Kubernetes 可以做到这一点。这不是你将要承担的唯一工作量。可能你还有有状态的工作负载,你可以使用有状态集在 Kubernetes 上完成此工作。

你可能还有的另一个工作负载是单例。也许你希望某个应用程序的实例是整个集群中应用程序的唯一一个实例–你希望它成为可靠的单例。如果失败,则重新启动。因此,你可以根据需求以及是否希望单例至少具有一种或最多一种语义来在有状态集和副本集之间进行选择。你可能还有的另一个工作负载是围绕作业和定时作业–有了 Kubernetes,你也可以实现这些。

如果我们将所有这些 Kubernetes 功能映射到我们的需求,则 Kubernetes 可以满足生命周期需求。我通常创建的需求列表主要是由 Kubernetes 今天提供给我们的。这些是任何平台上的预期功能,而 Kubernetes 可以为你的部署做的是配置管理、资源隔离和故障隔离。此外,除了无服务器本身之外,它还支持其他工作负载。

然后,如果这就是 Kubernetes 给开发者提供的全部功能,那么我们该如何扩展 Kubernetes 呢?以及如何使它具有更多功能?因此,我想描述当今使用的两种常用方法。

进程外扩展机制

首先是 Pod 的概念,Pod 是用于在节点上部署容器的抽象。此外,Pod 给我们提供了两组保证:

  • 第一组是部署保证 – Pod 中的所有容器始终位于同一个节点上。这意味着它们可以通过 localhost 相互通信,也可以使用文件系统或通过其他 IPC 机制进行异步通信。
  • Pod 给我们的另一组保证是围绕生命周期的。Pod 中的所有容器并非都相等。

根据使用的是 init 容器还是应用程序容器,你会获得不同的保证。例如,init 容器在开始时运行;当 Pod 启动时,它按顺序一个接一个地运行。他们仅在之前的容器已成功完成时运行。它们有助于实现由容器驱动的类似工作流的逻辑。

另一方面,应用程序容器是并行运行的。它们在整个 Pod 的生命周期中运行,这也是 sidecar 模式的基础。sidecar 可以运行多个容器,这些容器可以协作并共同为用户提供价值。这也是当今我们看到的扩展 Kubernetes 附加功能的主要机制之一。

为了解释以下功能,我必须简要地告诉你 Kubernetes 内部的工作方式。它是基于调谐循环的。调谐循环的思想是将期望状态驱动到实际状态。在 Kubernetes 中,很多功能都是靠这个来实现的。例如,当你说我要两个 Pod 实例,这系统的期望状态。有一个控制循环不断地运行,并检查你的 Pod 是否有两个实例。如果不存在两个实例,它将计算差值。它将确保存在两个实例。

这方面的例子有很多。一些是副本集或有状态集。资源定义映射到控制器是什么,并且每个资源定义都有一个控制器。该控制器确保现实世界与所需控制器相匹配,你甚至可以编写自己的自定义控制器。

当在 Pod 中运行应用程序时,你将无法在运行时加载任何配置文件更改。然而,你可以编写一个自定义控制器,检测 config map 的变化,重新启动 Pod 和应用程序–从而获取配置更改。

事实证明,即使 Kubernetes 拥有丰富的资源集合,但它们并不能满足你的所有不同需求。Kubernetes 引入了自定义资源定义的概念。这意味着你可以对需求进行建模并定义适用于 Kubernetes 的 API。它与其他 Kubernetes 原生资源共存。你可以用能理解模型的任何语言编写自己的控制器。你可以设计一个用 Java 实现的 ConfigWatcher,描述我们前面所解释的内容。这就是 operator 模式,即与自定义资源定义一起使用的控制器。如今,我们看到很多 operator 加入,这就是第二种扩展 Kubernetes 附加功能的方式。

接下来,我想简单介绍一下基于 Kubernetes 构建的一些平台,这些平台大量使用 sidecar 和 operator 来给开发者提供额外的功能。

什么是服务网格?

让我们从服务网格开始,什么是服务网格?

我们有两个服务,服务 A 要调用服务 B,并且可以用任何语言。把这个当做是我们的应用工作负载。服务网格使用 sidecar 控制器,并在我们的服务旁边注入一个代理。你最终会在 Pod 中得到两个容器。代理是一个透明的代理,你的应用对这个代理完全无感知–它拦截所有传入和传出的流量。此外,代理还充当数据防火墙。

这些服务代理的集合代表了你的数据平面,并且很小且无状态。为了获得所有状态和配置,它们依赖于控制平面。控制平面是保持所有配置,收集指标,做出决定并与数据平面进行交互的有状态部分。此外,它们是不同控制平面和数据平面的正确选择。事实证明,我们还需要一个组件-一个 API 网关,以将数据获取到我们的集群中。一些服务网格具有自己的 API 网关,而某些使用第三方。如果你研究下所有这些组件,它们将提供我们所需的功能。

API 网关主要专注于抽象我们服务的实现。它隐藏细节并提供边界功能。服务网格则相反。在某种程度上,它增强了服务内的可见性和可靠性。可以说,API 网关和服务网格共同提供了所有网络需求。要在 Kubernetes 上获得网络功能,仅使用服务是不够的:“你需要一些服务网格。”

什么是 Knative?

我要讨论的下一个主题是 Knative,这是 Google 几年前启动的一个项目。它是 Kubernetes 之上的一层,可为您提供无服务器功能,并具有两个主要模块:

  • Knative 服务 - 围绕着请求-应答交互,以及
  • Knative Eventing - 更多的是用于事件驱动的交互。

只是让你感受一下,Knative Serving 是什么?通过 Knative Serving,你可以定义服务,但这不同于 Kubernetes 服务。这是 Knative 服务。使用 Knative 服务定义工作负载后,你就会得到具有无服务器的特征的部署。你不需要有启动并运行实例。它可以在请求到达时从零开始。你得到的是无服务器的能力;它可以迅速扩容,也可以缩容到零。

Knative Eventing 为我们提供了一个完全声明式的事件管理系统。假设我们有一些要与之集成的外部系统,以及一些外部的事件生产者。在底部,我们将应用程序放在具有 HTTP 端点的容器中。借助 Knative Eventing,我们可以启动代理,该代理可以触发 Kafka 映射的代理,也可以在内存或者某些云服务中。此外,我们可以启动连接到外部系统的导入器,并将事件导入到我们的代理中。这些导入器可以基于,例如,具有数百个连接器的 Apache Camel。

一旦我们将事件发送给代理,然后用 YAML 文件声明,我们可以让容器订阅这些事件。在我们的容器中,我们不需要任何消息客户端–比如 Kafka 客户端。我们的容器将使用云事件通过 HTTP POST 获取事件。这是一个完全平台管理的消息传递基础设施。作为开发人员,你必须在容器中编写业务代码,并且不处理任何消息传递逻辑。

从我们的需求的角度来看,Knative 可以满足其中的一些要求。从生命周期的角度来看,它为我们的工作负载提供了无服务器的功能,因此能够将其扩展到零,并从零开始激活。从网络的角度来看,如果服务网格之间存在某些重叠,则 Knative 也可以进行流量转移。从绑定的角度来看,它对使用 Knative 导入程序进行绑定提供了很好的支持。它可以使我们进行发布/订阅,或点对点交互,甚至可以进行一些排序。它可以满足几类需求。

什么是 Dapr?

另一个使用 sidecar 和 operator 的项目是 Dapr,它是微软几个月前才开始并且正在迅速流行起来。此外,1.0 版本 被认为是生产可用的。它是一个作为 sidecar 的分布式系统工具包–Dapr 中的所有内容都是作为 sidecar 提供的,并且有一套他们所谓的构件或功能集的集合。

这些功能是什么呢?第一组功能是围绕网络。Dapr 可以进行服务发现和服务之间的点对点集成。同样,它也可以进行服务网格的追踪、可靠通信、重试和恢复。第二套功能是围绕资源绑定:

  • 它有很多云 API、不同系统的连接器,以及
  • 也可以做消息发布/订阅和其他逻辑。

有趣的是,Dapr 还引入了状态管理的概念。除了 Knative 和服务网格提供的功能外,Dapr 在状态存储之上进行了抽象。此外,你通过存储机制支持与 Dapr 进行基于键值的交互。

在较高的层次上,架构是你的应用程序位于顶部,可以使用任何语言。你可以使用 Dapr 提供的客户端库,但你不必这样做。你可以使用语言功能来执行称为 sidecar 的 HTTP 和 gRPC。与 服务网格的区别在于,这里的 Dapr sidecar 不是一个透明的代理。它是一个显式代理,你必须从你的应用中调用它,并通过 HTTP 或 gRPC 与之交互。根据你需要的功能,Dapr 可以与其他如云服务的系统对话。

在 Kubernetes 上,Dapr 是作为 sidecar 部署的,并且可以在 Kubernetes 之外工作(不仅仅是 Kubernetes)。此外,它还有一个 operator – 而 sidecar 和 Operator 是主要的扩展机制。其他一些组件管理证书、处理基于 actor 的建模并注入 sidecar。你的工作负载与 sidecar 交互,并尽其所能与其他服务对话,让你与不同的云提供商进行互操作。它还为你提供了额外的分布式系统功能。

综上所述,这些项目所提供的功能,我们可以说 ESB 是分布式系统的早期化身,其中我们有集中式的控制平面和数据平面–但是扩展性不好。在云原生中,集中式控制平面仍然存在,但是数据平面是分散的–并且具有隔音功能和高度的可扩展性。

我们始终需要 Kubernetes 来做良好的生命周期管理,除此之外,你可能还需要一个或多个附加组件。你可能需要 Istio 来进行高级联网。你可能会使用 Knative 来进行无服务器工作负载,或者使用 Dapr 来做集成。这些框架可与 Istio 和 Envoy 很好的配合使用。从 Dapr 和 Knative 的角度来看,你可能必须选择一个。它们共同以云原生的方式提供了我们过去在 ESB 上拥有的东西。

未来云原生趋势–生命周期趋势

在接下来的部分,我列出了一些我认为在这些领域正在发生令人振奋的发展的项目。

我想从生命周期开始。通过 Kubernetes,我们可以为应用程序提供一个有用的生命周期,这可能不足以进行更复杂的生命周期管理。比如,如果你有一个更复杂的有状态应用,则可能会有这样的场景,其中 Kubernetes 中的部署原语不足以为应用提供支持。

在这些场景下,你可以使用 operator 模式。你可以使用一个 operator 来进行部署和升级,还可以将 S3 作为服务备份的存储介质。此外,你可能还会发现 Kubernetes 的实际健康检查机制不够好。假设存活检查和就绪检查不够好。在这种情况下,你可以使用 operator 对你的应用进行更智能的存活和就绪检查,然后在此基础上进行恢复。

第三个领域就是自动伸缩和调整。你可以让 operator 更好的了解你的应用,并在平台上进行自动调整。目前,编写 operator 的框架主要有两个,一个是 Kubernetes 特别兴趣小组的 Kubebuilder,另一个是红帽创建的 operator 框架的一部分–operator SDK。它有以下几个方面的内容:

Operator SDK 让你可以编写 operator – operator 生命周期管理器来管理 operator 的生命周期,以及可以发布你的 operator 到 OperatorHub。如今在 OperatorHub,你会看到 100 多个 operator 用于管理数据库、消息队列和监控工具。从生命周期空间来看,operator 可能是 Kubernetes 生态系统中发展最活跃的领域。

网络趋势 - Envoy

我选的另一个项目是 Envoy。服务网格接口规范的引入将使你更轻松地切换不同的服务网格实现。在部署上 Istio 对架构进行了一些整合。你不再需要为控制平面部署 7 个 Pod;现在,你只需要部署一次就可以了。更有趣的是在 Envoy 项目的数据平面上所正在发生的:越来越多的第 7 层协议被添加到 Envoy 中。

服务网格增加了对更多协议的支持,比如 MongoDB、ZooKeeper、MySQL、Redis,而最新的协议是 Kafka。我看到 Kafka 社区现在正在进一步改进他们的协议,使其对服务网格更加友好。我们可以预料将会有更紧密的集成、更多的功能。最有可能的是,会有一些桥接的能力。你可以从服务中在你的应用本地做一个 HTTP 调用,而代理将在后台使用 Kafka。你可以在应用外部,在 sidecar 中针对 Kafka 协议进行转换和加密。

另一个令人兴奋的发展是引入了 HTTP 缓存。现在 Envoy 可以进行 HTTP 缓存。你不必在你的应用中使用缓存客户端。所有这些都是在 sidecar 中透明地完成的。有了 tap 过滤器,你可以 tap 流量并获得流量的副本。最近,WebAssembly 的引入,意味着如果你要为 Envoy 编写一些自定义的过滤器,你不必用 C++ 编写,也不必编译整个 Envoy 运行时。你可以用 WebAssembly 写你的过滤器,然后在运行时进行部署。这些大多数还在进行中。它们不存在,说明数据平面和服务网格无意停止,仅支持 HTTP 和 gRPC。他们有兴趣支持更多的应用层协议,为你提供更多的功能,以实现更多的用例。最主要的是,随着 WebAssembly 的引入,你现在可以在 sidecar 中编写自定义逻辑。只要你没有在其中添加一些业务逻辑就可以了。

绑定趋势 - Apache Camel

Apache Camel 是一个用于集成的项目,它具有很多使用企业集成模式连接到不同系统的连接器。 比如 Camel version 3 就深度集成到了 Kubernetes 中,并且使用了我们到目前为止所讲的那些原语,比如 operator。

你可以在 Camel 中用 Java、JavaScript 或 YAML 等语言编写你的集成逻辑。最新的版本引入了一个 Camel operator,它在 Kubernetes 中运行并理解你的集成。当你写好 Camel 应用,将其部署到自定义资源中,operator 就知道如何构建容器或查找依赖项。根据平台的能力,不管是只用 Kubernetes,还是带有 Knative 的 Kubernetes,它都可以决定要使用的服务以及如何实现集成。在运行时之外有相当多的智能 – 包括 operator – 所有这些都非常快地发生。为什么我会说这是一个绑定的趋势?主要是因为 Apache Camel 提供的连接器的功能。这里有趣的一点是它如何与 Kubernetes 深度集成。

状态趋势 - Cloudstate

另一个我想讨论的项目是 Cloudstate 和与状态相关的趋势。Cloudstate 是 Lightbend 的一个项目,主要致力于无服务器和功能驱动的开发。最新发布的版本,正在使用 sidecar 和 operator 与 Kubernetes 进行深度集成。

这个创意是,当你编写你的功能时,你在功能中要做的就是使用 gRPC 来获取状态并与之进行交互。整个状态管理在与其他 sidecar 群集的 sidear 中进行。它使你能够进行事件溯源、CQRS、键值查询、消息传递。

从应用程序角度来看,你并不了解所有这些复杂性。你所做的只是调用一个本地的 sidecar,而 sidecar 会处理这些复杂的事情。它可以在后台使用两个不同的数据源。而且它拥有开发人员所需的所有有状态抽象。

到目前为止,我们已经看到了云原生生态系统中的最新技术以及一些仍在进行中的开发。我们如何理解这一切?

多运行时微服务已经到来

如果你看微服务在 Kubernetes 上的样子,则将需要使用某些平台功能。此外,你将需要首先使用 Kubernetes 的功能进行生命周期管理。然后,很有可能透明地,你的服务会使用某些服务网格(例如 Envoy)来获得增强的网络功能,无论是流量路由、弹性、增强的安全性,甚至出于监控的目的。除此之外,根据你的场景和使用的工作负载可能需要 Dapr 或者 Knative。所有这些都代表了进程外附加的功能。剩下的就是编写业务逻辑,不是放在最上面而是作为一个单独的运行时来编写。未来的微服务很有可能将是由多个容器组成的这种多运行时。有些是透明的,有些则是非常明确的。

智能的 sidecar 和愚蠢的管道

如果更深入地看,那可能是什么样的,你可以使用一些高级语言编写业务逻辑。是什么并不重要,不必仅是 Java,因为你可以使用任何其他语言并在内部开发自定义逻辑。

你的业务逻辑与外部世界的所有交互都是通过 sidecar 发生的,并与平台集成进行生命周期管理。它为外部系统执行网络抽象,为你提供高级的绑定功能和状态抽象。sidecar 是你不需要开发的东西。你可以从货架上拿到它。你用一点 YAML 或 JSON 配置它,然后就可以使用它。这意味着你可以轻松地更新 sidecar,因为它不再被嵌入到你的运行时。这使得打补丁、更新变得更加更容易。它为我们的业务逻辑启用了多语言运行时。

微服务之后是什么?

这让我想到了最初的问题,微服务之后是什么?

如果我们看下架构的发展历程,应用架构在很高的层面上是从单体应用开始的。然而微服务给我们提供了如何把一个单体应用拆分成独立的业务域的指导原则。之后又出现了无服务器和功能即服务(FaaS),我们说过可以按操作将其进一步拆分,从而实现极高的可扩展性-因为我们可以分别扩展每个操作。

我想说的是 FaaS 并不是最好的模式 – 因为功能并不是实现合理的复杂服务的最佳模式,在这种情况下,当多个操作必须与同一个数据集进行交互时,你希望它们驻留在一起。可能是多运行时(我把它称为 Mecha 架构),在该架构中你将业务逻辑放在一个容器中,而所有与基础设施相关的关注点作为一个单独的容器存在。它们共同代表多运行时微服务。也许这是一个更合适的模型,因为它有更好的属性。

你可以获得微服务的所有好处。仍然将所有域和所有限界上下文放在一处。你将所有的基础设施和分布式应用需求放在一个单独的容器中,并在运行时将它们组合在一起。大概,现在最接近这种模型的是 Dapr。他们正在遵循这种模型。如果你仅对网络方面感兴趣,那么可能使用 Envoy 也会接近这种模型。

关于作者

Bilgin Ibryam 是红帽公司的产品经理和前架构师、提交人,并且是 Apache 软件基金会的成员。他是开源布道者,经常写博客、发表演讲,是 Kubernetes Patterns 和 Camel Design Patterns 书籍的作者。Bilgin 目前的工作主要集中在分布式系统、事件驱动架构以及可重复的云原生应用开发模式和实践上。请关注他 @bibryam 了解未来类似主题的更新。