今天的开发人员被期望开发具有弹性和可伸缩性的分布式系统。在面临安全问题时易于修补的系统,以及易于进行低风险增量升级的系统。受益于软件重用和开源模式创新的系统。对于不同的语言,使用带有嵌入式库的各种应用程序框架来实现所有这些都是不可能的。
最近我写了一篇关于“多运行时微服务体系结构”的博客,在那里我探索了分布式系统的需求,如生命周期管理、高级联网、资源绑定、状态抽象,以及这些抽象在过去几年中是如何变化的。我还谈到了“Kubernetes上的分布式系统的演变”,其中介绍了Kubernetes运算符和SideCar模型如何作为交付相同的分布式系统原语的主要创新机制。
在这两种情况下,主要的结论都是预测Kubernetes上的软件应用程序架构的发展将朝着运营商管理的SideCar模式发展。侧车和运营商可能会成为主流的软件分发和消费模式,在某些情况下甚至会像我们习惯的那样取代软件库和框架。
SideCar模型允许用不同语言编写的应用程序组合,以提供联合价值,速度更快,并且没有运行时耦合。让我们看几个侧车和运算符的具体示例,然后我们将探索这种新的软件组合范例会对我们产生怎样的影响。
在Kubernetes中,SideCar是通过在单个Pod中组织多个容器轻松实现的核心设计模式之一。Pod结构确保容器始终放置在同一节点上,并且可以通过网络、文件系统或其他IPC方法进行交互来进行协作。操作员允许侧车与平台的其余部分进行自动化、管理和集成。侧车代表与语言无关的可扩展数据平面,为自定义应用程序提供分布式原语。操作员代表他们的集中管理和控制平面。
诸如Istio、Consul等服务网络正在使用诸如特使之类的透明服务代理来为分布式系统提供增强的联网功能。特使可以提高安全性,实现高级流量管理,提高弹性,增加深度监控和跟踪功能。不仅如此,它还理解越来越多的七层协议,如Redis、MongoDB、MySQL以及最近的Kafka。它还添加了响应缓存功能,甚至WebAssembly支持,这将支持所有类型的自定义插件。特使是一个示例,说明透明服务代理如何将高级联网功能添加到分布式系统,而不将它们包含到分布式应用程序组件的运行时中。
除了典型的服务网之外,还有一些项目(如Skper)通过外部代理提供应用程序联网功能。Skper通过第7层虚拟网络解决了多群集Kubernetes的通信挑战,并提供先进的路由和连接能力。但是,它并没有将Skper嵌入到业务服务运行时中,而是在每个Kubernetes命名空间中运行一个实例,该名称空间充当一个共享的SideCar。
Cloudstate是SideCar模型的另一个示例,但这一次用于为无服务器开发模型提供有状态抽象。它通过GRPC为EventSourcing、CQRS、Pub/Sub、键/值存储和其他用例提供有状态原语。再说一次,它是侧车和运算符运行的示例,但这一次是无服务器编程模型。
DAPR是微软启动的一个相对年轻的项目,它也在使用SideCar模型来提供以开发人员为中心的分布式系统原语。DAPR为状态管理、服务调用和故障处理、资源绑定、发布/订阅、分布式跟踪等提供抽象。尽管DAPR和Service Mesh提供的功能有一些重叠,但两者在本质上是非常不同的。Istio的特使是从服务中注入并透明运行的,是一种操作工具。另一方面,DAPR必须通过HTTP或GRPC从应用程序运行时显式调用,并且它是面向开发人员的显式侧车。它是分布式原语的库,作为SideCar分发和使用,对于使用分布式功能的开发人员来说,这种模型可能会变得非常有吸引力。
Apache Camel是一个成熟的集成库,它在Kubernetes上重新发现了自己。其子项目骆驼K大量采用运营者模式,改善开发者体验,与Kubernetes平台深度融合。虽然Camel K不依赖侧车,但通过其CLI和操作符,它能够在不到一秒的时间内重用相同的应用程序容器,并在远程Kubernetes集群中执行任何本地代码修改。这是通过运营商模式以开发人员为目标的软件消费的另一个示例。
这些只是通过侧车和运营商探索各种方法的先驱项目中的一部分。为了减少基于容器的分布式体系结构(如数据平面开发工具包(DPDK))引入的网络开销,正在做更多的工作,DPDK是一个用户空间应用程序,它绕过Linux内核网络堆栈的各层,直接访问网络硬件。Kubernetes项目中有一项工作是创建具有更细粒度生命周期保证的SideCar容器。有一些基于GraalVM实现的新Java项目,如Quarkus,它们减少了资源消耗和应用程序启动时间,这使得工作负载对侧车更具吸引力。所有这些创新都将使侧车模型更具吸引力,并使更多此类项目的创建成为可能。
如果项目围绕更具体的用例出现,比如在侧车中对长期运行的流程(如业务流程模型和符号(Business process Model and Notation,BPMN)引擎进行有状态编排),我不会感到惊讶。侧车中的作业调度程序。无状态集成引擎,即SideCars中的企业集成模式实现。侧车中的数据抽象和数据联合引擎。侧车中的OAuth2/OpenID代理。可扩展的数据库连接池,用于侧车中的无服务器工作负载。应用网络作为侧车等等。但是为什么软件供应商和开发人员要切换到这个模型呢?让我们看看它提供的一些好处。
如果您现在是一家软件供应商,您可能已经考虑将您的软件作为API或基于SaaS的解决方案提供给潜在用户。如果可能的话,这是最快的软件消费模式,也是一种不需要动脑筋的模式。根据软件的性质,您可能还会将软件作为库或运行时框架分发。也许现在是时候考虑一下,它是否也可以作为一个集装箱提供给运营商。这种分发软件的机制和由此产生的体系结构具有库机制无法提供的一些非常独特的好处。
通过提供可通过开放协议和标准使用的库,您可以将它们开放给所有编程语言。使用JSON等文本格式作为侧车运行并通过HTTP使用的库不需要任何特定的客户端运行时库。即使将GRPC和Protobuf用于低延迟和高性能交互,生成此类客户端仍然比在应用程序运行时包含第三方自定义库并实现某些接口更容易。
显式的SideCar体系结构(与透明的SideCar体系结构相对)是一种作为以开发人员为中心的API后面的独立运行时使用软件功能的方式。它是一个正交特性,可以添加到任何应用程序中,无论是单块应用程序、微服务应用程序、基于函数的应用程序、基于参与者的应用程序,还是介于两者之间的任何应用程序。在动态程度较低的环境中,它可以紧挨着一块巨石;在动态的基于云的环境中,它可以紧挨着每一项微服务。在Kubernetes上创建侧车是微不足道的,在许多其他软件编排平台上也是可以做到的。
业务逻辑总是在内部定制和开发的。分布式系统原语是众所周知的商用功能,可以作为平台功能或运行时库使用。您可能正在使用来自第三方开源项目或公司的用于状态抽象、消息传递客户端、网络弹性和监控库等的软件。这些第三方实体拥有
当特性作为库使用时,它会包含在您的应用程序运行时中,您有责任了解它是如何工作的,以及如何配置、监视、调优和升级。这是因为语言运行时(如JVM)和运行时框架(如Spring Boot或应用服务器)规定了如何包含、配置、监视和升级第三方库。当软件功能作为单独的运行时(如侧车或独立容器)使用时,它会以Kubernetes运算符的形式提供自己的控制平面。
这有很多好处,因为控制平面了解其管理的软件(操作数),并附带所有必要的管理情报,否则这些情报将作为文档和最佳实践分发。更重要的是,运营商还与Kubernetes深度集成,提供开箱即用的平台集成和操作数管理智能的独特融合。运算符是由创建操作数的相同开发人员创建的,他们了解容器化功能的内部结构,并知道如何操作得最好。操作员是容器中的可执行SRE,随着更多的操作员和市场的出现,操作员的数量和他们的能力正在稳步增加。
假设您是Java框架的软件提供商。您可以将其作为存档或Maven工件分发。也许您走得更远,您分发了一个容器映像。无论是哪种情况,在今天的云原生世界中,这都不够好。用户仍然需要知道如何在零宕机的情况下修补和升级正在运行的应用程序。他们必须知道要备份什么并恢复其状态。他们必须知道如何配置他们的监控和警报阈值。他们必须知道如何检测复杂故障并从中恢复。他们必须知道如何根据当前负载配置文件调优应用程序。
在所有这些和类似的场景中,Kubernetes操作员形式的智能控制平面是答案。操作员将应用程序的平台和域知识封装在声明性配置的组件中,以管理工作负载。
侧车和运营商可能会成为主流的软件分发和消费模式,在某些情况下甚至会像我们习惯的那样取代软件库和框架。
假设您正在提供一个软件库,该软件库作为依赖项包含在消费者应用程序中。可能就是上面描述的后端框架的客户端库。例如,如果它是用Java编写的,您可能已经认证它可以在JEE服务器上运行,前提是Spring Boot启动器、构建器、工厂和其他实现都隐藏在一个干净的Java接口后面。您甚至可能已经将其移植到了.Net。
有了Kubernetes操作员和侧车,所有这些对消费者来说都是隐藏的。工厂类由操作符替换,唯一的配置接口是自定义资源的YAML文件。然后,运营商负责配置软件和平台,以便用户可以将其作为显式侧车或透明代理使用。在所有情况下,您的应用程序都可以通过远程API使用,并与平台功能甚至其他相关操作符完全集成。让我们看看这是如何发生的。
考虑侧车的一种方式类似于OOP中的组合重于继承原则,但在多语言上下文中。这是一种不同的组织应用程序职责的方式,方法是组合来自不同流程的功能,而不是将它们作为依赖项包含到单个应用程序运行时中。当您将软件作为库使用时,您可以实例化一个类,通过传递一些值对象来调用它的方法。当您将其作为进程外功能使用时,您可以访问本地进程。在此模型中,方法被API替换,进程内方法调用被HTTP或GRPC调用替换,值对象被类似CloudEvents的东西替换。这是从应用服务器到作为分布式运行时的Kubernetes的改变。从特定于语言的界面到远程API的更改。从内存中调用到HTTP,从值对象到CloudEvents,等等。
这需要软件提供商分发容器和控制器来操作它们。创建能够在本地构建和调试多个运行时服务的IDE。用于将代码更改快速部署到Kubernetes和配置控制平面的CLI。编译器可以决定在自定义应用程序运行时编译什么、从侧车使用什么功能以及从编排平台使用什么功能。
从长远来看,这将导致标准化API的合并,这些API用于侧车中通用原语的消费。我们将使用多语言API,而不是特定于语言的标准和API。例如,我们将不再使用Java Database Connectivity(JDBC)API、Cache API for Java(JCache)、Java Persistence API(JPA),而是通过HTTP使用类似CloudEvents的多语言API。以Sidecar为中心的API,用于消息传递、缓存、可靠联网、cron作业和计时器调度、资源绑定(到其他API、协议的连接器)、幂等、SAGA等。所有这些功能都将以操作员的形式随管理层一起交付,甚至与自助服务UI一起提供。运营商是这里的关键推动者,因为他们将使这个更加分布式的架构在Kubernetes上更易于管理和自我操作。操作员的管理接口由CustomResourceDefinition定义,并表示另一个仍然特定于应用程序的面向公众的API。
在交付速度和可操作性的推动下,这是向分发和消费软件的不同方式的思维方式的重大转变。它是从单运行时到多运行时应用程序体系结构的转变。这与摩尔定律结束时硬件行业从单核平台到多核平台的转变类似。通过构建拼图的所有元素,这是一个正在慢慢发生的转变:我们已经统一采用和标准化了容器,我们有了通过Kubernetes进行编排的事实上的标准,可能很快就会改进侧车,快速的运营商采用,CloudEvents作为广泛同意的标准,像Quarkus这样的轻量级运行时,等等。随着基础的到位,应用程序、生产力工具、实践、标准化API和生态系统也将到来。