多运行时微服务架构

Bilgin Ibryam最近发了篇关于微服务架构趋势的好文,没找到好的中文版,自己翻译一下。

原文:Multi-Runtime Microservices Architecture,作者Bilgin Ibryam,Red Hat首席架构师。

关键点:

  • 构建一个分布式系统并不容易。围绕“微服务”架构和“12要素应用“设计已经出现一些最佳实践。这些最佳实践提供了与交付生命周期、网路、状态管理、外部依赖绑定相关的指导原则。
  • 然而,以可扩展和可维护的方式一致地实施这些原则却充满挑战。
  • 为实施这些原则,传统的技术化方法有企业服务总线(ESB)和面向消息的中间件(MOM)。虽然这些解决方案提供了良好的功能特性,但主要的挑战在于单体架构以及业务逻辑和平台之间的紧密技术耦合。
  • 随着云、容器和容器编排工具(Kubernetes)的流行,出现了实施这些原则的新解决方案。例如Knative用于交付,服务网格用于网络,而Camel-K用于绑定和集成。
  • 通过这种方法,业务逻辑(称为“微逻辑”)构成了应用程序的核心,边车“Mecha”组件创建可提供强大的开箱即用的分布式原语。
  • 微逻辑(Micrologic )组件和Mecha组件的解耦可以改善day-2操作,例如打补丁和升级,并有助于维持业务逻辑内聚单元的长期可维护性。

译者注:day-2操作一般指的是运维工作,https://codilime.com/day-0-day-1-day-2-the-software-lifecycle-in-the-cloud-age/

创建优秀的分布式应用并非易事:此类系统通常要遵循12要素应用和微服务原则。它们必须是无状态的、可伸缩的、可配置的、独立发布的、容器化的以及可自动化的,有时还是事件驱动和无服务器的(Serverless)。一旦创建后,它们应该易于升级而且长期可维护。使用当今的技术,要在这些相互竞争的要求间找到良好平衡仍然是一项艰巨的工作。

在本文中,我将探讨分布式平台如何发展以实现这种平衡,更重要的是讲述在分布式系统的演进中还需要发生什么事情,进而简化可维护的分布式架构的创建。如果你想看我现场讨论这个话题,请参加三月伦敦举办的QCon,到时会有我的演讲。

分布式应用需求

在这个讨论中,我将把当今分布式应用程序的需求分为四个类别--生命周期、网络、状态、绑定,另外简要分析它们在最近几年中的发展状况。


分布式应用程序需求
生命周期(Lifecycle)

让我们从基础开始。当我们编写一项功能时,编程语言会提供此生态系统中的可用程序库、打包格式和运行时。例如,Java使用.jar格式以及所有Maven依赖作为生态系统,并将JVM作为运行时。如今,随着发布周期的缩短,生命周期中更重要的是能够自动化进行部署、错误恢复以及服务扩展的能力。这组能力广泛的代表了我们的应用生命周期需求。

网络(Networking)

从某种意义上讲,今天几乎每个应用程序都是分布式应用,都需要网络。但是现代分布式系统需要从更广的视角去管理网络。从服务发现和错误恢复,到启用现代软件发布技术以及各种跟踪和遥测。为了这些目的,我们将不同的消息交换模式(点对点、发布/订阅方法以及智能路由机制)也包括在此类。

状态(State)

当我们谈论状态时,通常是讲服务状态以及服务为什么最好是无状态的。但是管理我们服务的平台本身就需要状态。这对于执行可靠的服务编排和工作流、分布式单例、临时调度(cron作业)、幂等性、有状态的错误恢复、缓存等是必需的。此处列出的所有功能都依赖于底层的状态。虽然实际的状态管理不在本文讨论范围之内,但依赖状态的分布式原语及其抽象却是本文中要关注的。

绑定(Binding)

分布式系统的组件不仅必须彼此通讯,而且还必须与现今或遗留的外部系统集成。这就要求连接器能够转换各种协议,支持不同的消息交换模式,例如轮询、事件驱动、请求/答复、转换消息格式,甚至能够执行自定义的错误恢复过程和安全机制。
上述功能不特指具体使用案例,它表述的是一个通用原语的良好集合,这些原语正是创建优秀的分布式系统所需的。如今,许多平台都提供了这样的功能,但是本文中我们要探讨的是过去十年中我们使用这些功能的方式如何变化,以及在下一个十年中它又将如何变化。为了进行比较,让我们看一下过去的十年,基于Java的中间件如何满足这些需求。

传统中间件限制

上一代满足上述要求的传统解决方案众人皆知:企业服务总线(ESB)及其变体(例如面向消息的中间件,更轻量级的集成框架等)。ESB是一种中间件,可以使用面向服务架构(即经典SOA)在异构环境之间实现互操作。

ESB可以为你提供良好的功能集,但ESB的主要挑战是单体架构以及业务逻辑和平台之间紧密的技术耦合,从而导致技术和组织集中化。当将服务开发并部署到这样的系统中时,它与分布式系统框架紧密结合,从而限制了服务的发展。这通常只会在软件生命周期的后期才变得明显。

以下是每类需求的一些问题和局限性,这些问题和局限性使得ESB在当今时代不再有用。

生命周期(Lifecycle)

在传统的中间件中,通常只有一个受支持的语言运行时(例如Java),它规定了软件的打包方式、可用的库、必须维护的频率等。业务服务必须使用这些库,使其与平台(平台编写语言与业务服务是一样的)紧密结合。在生产实践中,这导致服务和平台的升级必须要协调,常规服务与平台的发布不能够独立进行。

网络(Networking)

尽管传统中间件具有与内部和外部服务交互的高级功能,但它有一些主要缺点,网络功能集中于一种主要语言及其相关技术,对于Java语言,即JMS,JDBC,JTA等。更重要的是,网络问题和语义也深深地刻在业务服务中。有一些抽象能力的库来解决网络问题(例如曾经很受欢迎的Hystrix项目),但是该库的抽象“泄漏”到了服务的编程模型、交换模式、错误处理语义以及库本身中。虽然在一个位置可以方便的编写和读取整个业务逻辑(与网络问题混在一起),但是这导致两个问题紧密地耦合到同一实现中,最终形成了一个关联的演进路径。

状态(State)

为了进行可靠的服务编排、业务流程管理以及实施模式(例如Saga模式和其它长时间运行的流程),平台需要在幕后持久化状态。同样,临时动作(例如触发计时器和cron作业)建立在状态之上,并且需要在分布式环境中对数据库进行集群化和弹性。这里的主要约束在于:与状态交互的库和接口没有完全抽象出来,也没有与服务运行时分离。通常,这些库必须配置有数据库详细信息,并且它们存在于服务中,从而将语义和依赖关系泄漏到应用程序域中。

绑定(Binding)

使用集成中间件的一个主要原因是能够使用不同的协议、数据格式和消息交换模式连接到其它各种系统。但是,这些连接器必须与应用程序一起使用,这意味着必须将这些依赖与业务逻辑一起进行更新和维护;意味着必须在服务内来回转换数据类型和数据格式;意味着必须根据消息交换模式来构造代码并设计流程。这些示例展示了抽象端点如何影响传统中间件中服务实现。

云原生趋势

传统的中间件功能是强大的,它具有所有必要的技术功能,但缺乏现今数字化业务所要求的快速更改和扩展的能力。这就是微服务结构及其指导原则(为设计现代分布式应用程序)所要解决的问题。

微服务背后的思想及其技术要求推动了容器和Kubernetes的普及和广泛使用。这开始了一种新的创新方式,这种方式将影响我们未来多年处理分布式应用的方式。让我们看看Kubernetes和相关技术如何影响每类需求。

生命周期(Lifecycle)

容器和Kubernetes将打包、发布和部署应用程序的方式发展为一种与语言无关的格式。关于Kubernetes模式和Kubernetes对开发人员的影响的文章很多,在这里我简短介绍。但是请注意,对于Kubernetes,管理的最小原语是容器,它专注于在容器级别和流程模型上提供分布式原语。这意味着它在管理应用程序的生命周期方面:运行状况检查、恢复、部署和扩展方面做得很出色,但是在容器内分布式应用的其它方面却没有做得很好,例如灵活的网络、状态管理和绑定。

您可能会指出,Kubernetes具有状态型工作负载、服务发现、cron作业和其它功能。的确如此,但是所有这些原语都是在容器级别的。在容器内部,开发人员仍然必须使用特定语言的库来访问我们在本文开头列出的更细粒度的功能。这也是促使诸如Envoy,Linkerd,Consul,Knative,Dapr,Camel-K等项目产生的原因。

网络(Networking)

Kubernetes提供了围绕服务发现的基本网络功能,事实证明,这是一个很好的基础,但对于现代应用程序来说还不够。随着微服务数量的增加和部署速度的加快,对更高级的发布策略、管理安全性、运行指标、跟踪、故障恢复、错误模拟等方面的需求变得越来越强烈,并产生了一类新的软件,称为服务网格( service mesh)。

这里更令人兴奋的是,趋势是将与网络相关的关注点从包含业务逻辑的服务移到单独的运行时(无论是边车还是节点级代理),再移到单独的运行时。如今,服务网格可以执行高级路由、帮助测试、处理安全性的某些方面,甚至支持特定应用程序的协议(例如,Envoy支持Kafka,MongoDB,Redis,MySQL等)。尽管作为解决方案的服务网格可能尚未得到广泛采用,但它触及了分布式系统中的真正痛点,我相信它会成型而且找到最合适的存在形态。

除了典型的服务网格外,还有其他项目,例如Skupper,这些项目证实了将网络功能放入外部运行时代理的趋势。Skupper通过第7层虚拟网络解决了多集群通信难题,并提供了高级路由和连接功能。但是,它没有将Skupper嵌入到业务服务运行时中,而是每个Kubernetes名称空间运行一个实例,该实例充当共享的边车(sidercar)。

综上所述,容器和Kubernetes在应用程序的生命周期管理方面迈出了重要的一步。服务网格和相关技术触碰到了分布式系统真正的痛点,更多职责将从应用程序迁移到代理中,而服务网格为其奠定了基础。接下来我们看下一类需求。

状态(State)

我们在前面列出了依赖状态的主要集成原语。管理状态非常困难,应将其委托给专门的存储软件和托管服务。这不是本文关注话题,但是通过语言无关的抽象及使用状态来帮助集成用例却是我们要讨论的。今天,有许多努力试图在语言无关的抽象后面提供有状态的原语。有状态的工作流管理是云服务中的必备的功能,例如AWS Step Functions,Azure Durable Functions等。在基于容器的部署中,CloudState和Dapr都依赖于sidecar模型提供对分布式应用中的状态抽象更好的解耦。

我也期待可以将上面列出的所有有状态功能抽象到一个单独的运行时中。这意味着工作流管理、单例、幂等、事务管理、cron作业触发器和有状态错误处理都可靠的运行在边车(或主机级代理)中,而不是存在于服务中。业务逻辑不需要在应用程序中包含此类依赖和语义,它可以从绑定环境中声明性地请求此类行为。例如,Sidecar可以作为一个cron作业触发器、幂等消费者和工作流管理器,而自定义业务逻辑可以作为回调被执行或插入工作流的某些阶段、错误处理、临时调用或唯一幂等要求等。

另一个有状态用例是缓存。无论是通过服务网格层执行请求缓存,还是使用Infinispan,Redis,Hazelcast等之类的数据缓存,都有一些将缓存功能转移到应用程序运行时之外的示例。

绑定(Binding)

尽管我们讨论的主题是解耦所有分布式需求与应用程序运行时,但这种趋势也依然伴随着绑定。连接器、协议转换、消息转换、错误处理和安全认证都可以移出服务运行时。我们还没有达到那个程度,但是在诸如Knative和Dapr之类的项目已朝这个方向进行了尝试。将所有这些职责移出应用程序运行时将使得应用代码更精简、更注重业务逻辑。应用代码将在独立于分布式系统需求的运行时(指的是与业务逻辑无关的分布式功能),而分布式系统需求可以作为预安装功能使用。

Apache Camel-K项目采用了另一种有趣的方法。该项目不是使用代理运行时来支持主应用程序,而是依靠智能的Kubernetes Operator来构建应用程序运行时,运行时同时具有Kubernetes和Knative等附加平台功能。在这里,唯一的代理是负责包括应用程序所需的分布式系统原语的operator。不同之处在于,某些分布式原语已添加到应用程序运行时中,另外一些已在平台中提供(也可能包括一个边车Sidecar)。

未来架构趋势

目光放远,我们可以得出结论,通过将功能转移到平台级别,分布式应用程序的商品化达到了新的高度。除了生命周期之外,现在我们还能看到网络、状态抽象、声明性事件和端点绑定也已现成可用,EIP也在此列表。有趣的是,商品化使用进程外模型(sidecar)进行功能扩展,而不是使用运行时库或纯平台功能(例如新的Kubernetes功能)。

我们正通过将所有传统的中间件功能(也称为ESB)转移到其它运行时中来(这很快就会实现),不久,我们在服务中要做的就只是编写业务逻辑。

传统中间件平台和云原生平台

与传统的ESB时代相比,这种架构将业务逻辑与平台更好地分离了,不过还没有完全分离。许多分布式原语,例如经典的企业集成模式(EIP):分离器、聚合器、过滤器、基于内容的路由器;流处理模式:映射、过滤、折叠、联接、合并、滑动窗口;仍然必须包含在业务逻辑运行时中,而其它很多原语则依赖于多种不同的、重叠的平台附加组件。

如果我们将不同领域的各类创新性云原生项目进行汇总,那么可以得到如下图所示:

多运行时微服务

这里的图仅用于展示目的,它特意选择了一些代表性项目并将其映射到一组分布式原语上。实际上,你不会同时用到所有这些项目,因为其中一些项目是重叠的且不兼容的工作负载模型。如何解释这个图?

  • Kubernetes和容器在多语言应用程序的生命周期管理中取得了巨大飞跃,并为未来的创新奠定了基础。
  • 服务网格技术通过高级网络功能在对Kubernetes进行了改进,并开始涉足到应用程序。
  • 虽然Knative通过快速扩展主要专注于serverless工作负载,但它也满足了服务编排和事件驱动的绑定需求。
  • Dapr以Kubernetes、Knative和Service Mesh的思想为基础,并深入应用程序运行时以解决有状态的工作负载、绑定和集成需求,充当现代的分布式中间件。

该图可帮助你直观地看到,很可能在将来,我们最终将使用多个运行时来实现分布式系统。多个运行时,不是因为有多个微服务,而是因为每个微服务都将由多个运行时组成,最有可能是两个运行时--自定义业务逻辑运行时和分布式原语运行时。

引入多运行时微服务

多运行时微服务体系结构正开始形成,以下是对其的简要说明。

你是否还记得电影《阿凡达》中科学家们制作的增强机动平台(“机甲mech suits”),他们去旷野探索潘多拉。这种多运行时架构类似于这些机甲Mecha-suits,它们为类人驾驶员赋予超能力。在电影中,你穿上西装就能获得力量以及破坏性武器。在这种软件结构中,你让你的业务逻辑构成应用程序的核心(称为微逻辑 micrologic),而sider mecha组件提供强大的现成分布式原语。Micrologic与mecha功能相结合,形成了一个多运行时微服务,该服务使用进程外功能来满足其分布式系统需求。最棒的是,阿凡达2即将面世,以帮助推进这种架构。我们最终可以在所有软件会议上用令人赞叹的机甲图片代替老式的边车摩托车;-)。接下来,让我们看看该软件架构的详细信息。

译者添加:MK-6 Amplified Mobility Platform

这是一个类似于客户端--服务器架构的两组件模型,其中每个组件都是独立的运行时。它与纯粹的客户端--服务器架构的不同之处在于,这两个组件都位于同一主机上,彼此之间有可靠的网络连接。这两个组件的重要性相当,它们可以在任一方向上发起操作并充当客户端或服务器。其中的一个组件称为Micrologic,在剥离所有分布式系统问题后,它只拥有非常少的业务逻辑。另一个随附的组件是Mecha,它提供了我们在本文中一直讨论的所有分布式系统功能(生命周期除外,它是一个平台功能)。

多运行时(进程外)微服务架构

Micrologic和Mecha可能是一对一的部署(称为sidecar模型),也可以是几个Micrologic运行时共享一个Mecha。第一种模型最适用于Kubernetes等环境,而第二种模型则适用于边缘部署。

Micrologic运行时特征

让我们简要地探讨Micrologic运行时的一些特征:

  • Micrologic组件本身不是微服务。它包含微服务中的业务逻辑,但是该逻辑只能与Mecha组件结合使用。另一方面,微服务是自包含的,并没有将部分功能或者处理流程扩展到其他运行时中。Micrologic与其Mecha一起形成了微服务。
  • 这也不是function或serverless架构。serverless最著名的是其具备快速扩展和缩容到零的能力。在serverless架构中,一个function实现单个操作,它是可伸缩性的基本单位。在这方面,function不同于实现多种操作的Micrologic(但这种实现不是端到端的)。最重要的是,操作的实现分布在Mecha和Micrologic运行时上。
  • 这是客户端--服务器架构的一种特殊形式,优化了对分布式原语的使用,而且无需编码。如果我们假设Mecha扮演服务器角色,那么每个实例都必须经过专门配置后与客户端一起工作。它不是一个同时支持多个客户端的通用服务器实例(就像典型的C/S架构中那样)。
  • Micrologic中的用户代码不会直接与其它系统交互,也不会实现任何分布式系统原语。它通过事实上的标准(例如HTTP / gRPC,CloudEvents规范)与Mecha进行交互,Mecha则通过丰富的功能与其它系统进行通信,并且支持可配置的步骤和机制。
  • 尽管Micrologic仅负责实现从分布式系统问题中剥离出来的业务逻辑,但它仍必须至少实现一些API。它必须允许Mecha和平台通过预定义的API和协议与其进行交互(例如,通过遵循Kubernetes部署的云原生设计原则)。

Mecha运行时特征

以下是一些Mecha运行时特征:

  • Mecha是一个通用的、高度可配置的、可重用的组件,提供分布式原语作为现成的能力。
  • Mecha的每个实例都必须配置为与一个Micrologic组件(边车模型)一起使用,或者配置为与几个组件共享。
  • Mecha不对Micrologic运行时做任何假设。它通过开放协议和格式(例如HTTP / gRPC,JSON,Protobuf,CloudEvents)与多语言微服务甚至单体系统一起运行。
  • Mecha通过简单的文本格式(例如YAML,JSON)进行声明性配置,指明要启用的功能以及如何将其绑定到Micrologic端点。对于特定API交互,可以为Mechan附加规范,例如OpenAPI、AsyncAPI,ANSI-SQL等。对于由多个处理步骤组成的有状态工作流,可以使用诸如Amazon State Language的规范。对于无状态集成,可以使用与Camel-K YAML DSL类似的方法来使用企业集成模式(EIP)。这里的关键点是,所有这些Mecha都可基于文本的、声明性的、多种语言的定义,而且无需编码。请注意,这些都是对未来的预测,当前,没有用于状态编排或EIP的Mecha,但是我希望现有的Mecha(Envoy,Dapr,Cloudstate等)很快就会开始添加此类功能。Mecha是应用程序级别的分布式原语抽象层。
  • 可能并不会依赖多个不同目的的代理(例如网络代理、缓存代理、绑定代理),而是由一个Mecha提供所有这些功能。一些功能(例如存储,消息持久性,缓存等)将被其它云或本地服务嵌入并支持。

一些与生命周期管理有关的分布式系统问题由管理平台(例如Kubernetes或其他云服务)提供解决会更合理,而不是由使用通用开放规范(例如[Open App https://github.com/oam-dev/spec))的Mecha运行时负责。

这种架构的主要好处是什么?

好处是业务逻辑和分布式系统问题(越来越多)之间的松耦合。软件系统的这两部分具有完全不同的动态特征。业务逻辑始终是内部编写的、唯一自定义代码。它经常更改,取决于你的组织优先级和执行能力。另一方面,分布式原语则负责解决本文中列出的问题,这众所周知。这些由软件供应商开发,并作为库、容器或服务使用。这些代码的修改取决于供应商的优先级、发布周期、安全补丁、开放源代码管理规则等。这两个组之间几乎不可见,也无法相互控制。

业务逻辑和分布式系统关注在不同架构中的耦合

微服务通过限界上下文实现不同业务领域之间的解耦,每个微服务都可以独立发展。但是微服务架构无法解决业务逻辑与中间件关注耦合带来的难题。对于某些依赖于集成用例的微服务,这可能不算一个大问题。但是,如果你的领域涉及复杂的集成(每个人都将越来越多),那么遵循微服务原则也难以让你摆脱与中间件耦合。即使中间件只是你微服务中的依赖库,当你开始迁移和更改这些库时,这种耦合也将会变得明显。另外随着你需要越来越多的分布原语,你与集成平台的耦合也会越多。通过预定义的API(而不是库),将中间件作为独立运行时/进程来使用,有助于降低耦合,并实现每个组件的独立演化。

这是供应商发行和维护复杂中间件更好的一种方法。只要与中间件的交互是通过开放API和标准的进程间通信进行,软件供应商就可以按照自己的节奏自由发布补丁和升级。消费者也可以自由使用他们喜欢的开发语言、库、运行时、部署方法和过程。

这种架构的主要缺点是什么?

进程间通信。分布式系统的业务逻辑和中间件机制(你可以看到名称的来源)跑在不同的运行时中,需要HTTP或gRPC调用而不是进程内方法调用。但是请注意,这不应该是到其它计算机或数据中心的网络调用。Micrologic运行时和Mecha应当位于同一主机上,延迟时间短,同时出现网络问题的可能性最小。

复杂性。下一个问题是,开发复杂度以及维护此类系统所获收益是否值得。我认为答案将越来越倾向于是。分布式系统的需求和发布周期的步伐正在增加。而这种架构为此做了很多优化。我前段时间写道,未来的开发人员必须具备混合开发技能。这种架构进一步证实了这一趋势。应用程序的一部分将使用高级编程语言编写,部分功能将由现成组件提供(必须进行声明性配置)。这两个部分的互连不是在编译时或在启动时通过进程内依赖注入,而是在部署时通过进程间通信实现。该模型可实现更高的软件重用率和更快的变更速度。

微服务不是Function会发生什么

微服务架构有一个明确的目标。它为变化而优化。通过将应用划分为业务域中,这种架构解耦了服务,实现了独立的团队管理和独立的步调发布,为软件演进和维护提供了最优的服务边界。

如果我们看一下serverless架构的编程模型,会发现它主要基于function。function为可伸缩性进行了优化。通过function,我们将每个操作分解为一个独立的组件,于是它可以快速、独立的按需扩展。在此模型中,部署粒度是一个function。之所以选择该function,是因为它是代码构成器,它的输入速率与缩放行为直接相关。这是一种针对极致可伸缩性(而不是为了应对复杂系统的长期可维护)进行了优化的架构。

AWS Lambda的流行及其完全托管的运营特性催生了Serverless,Serverless的其它方面又如何呢?在这方面,“ AWS Serverless”优化了供应速度,但同时带来了控制缺失以及供应商锁定的问题。但实际上完全托管的不是应用程序架构,而是一种软件使用模型。它在功能上是正交的,类似于使用基于SaaS的平台,这种平台在理想情况下适用于任何类型的架构,无论是整体式、微服务、Mecha还是function。在许多方面,AWS Lambda与完全托管的Mecha架构是相似的,但也有一个很大的区别:Mecha并不要求必须是一个function模型,只要是围绕业务域,使用更具内聚的代码构造即可,而且与所有中间件无关。

架构优化

另一方面,Mecha架构通过将中间件独立优化了微服务。尽管微服务彼此独立,但它们在很大程度上依赖于嵌入式分布式原语。Mecha架构将这两个关注面分为单独的运行时,从而允许独立团队进行独立发布。这种解耦可以改善day-2操作(例如修补和升级),并改善业务逻辑内聚单元的长期可维护性。在这方面,Mecha架构在引起最大摩擦的边界处分离了软件,这是微服务架构的自然发展。与function模型相比,这种优化在软件重用和演化方面提供了更多好处,而function模型则通过代码的过度分布式化,以实现极高的可伸缩性。

总结

分布式应用程序有许多要求。创建高效的分布式系统需要多种技术和良好的集成方式。尽管传统的单体中间件也提供了分布式系统所需的所有必要技术功能,但它却缺乏业务需要的快速更改、适配和扩展的能力。这也是微服务架构背后思想导致容器和Kubernetes迅速流行的原因,正所谓分久必合、合久必分,随着云原生领域的最新发展,我们又将所有传统中间件功能转移到了平台和现成的辅助运行时中。

应用功能的这种商品化主要是使用进程外模型进行功能扩展,而不是运行时类库或纯平台功能。这意味着将来很有可能我们将使用多个运行时来实现分布式系统。多个运行时,不是因为有多个微服务,而是因为每个微服务由多个运行时组成:一个用于自定义微业务逻辑的运行时,另一个现成的可配置运行时用于分布式原语。

你可能感兴趣的:(多运行时微服务架构)