什么是多运行时架构?(下)

简介: 什么是多运行时架构?(下)

微软的尝试:Dapr

Dapr 是微软主导开发并开源的一种 Mecha runtime,从宏观上看它处在整个架构的中间层:

(来源:Dapr)

自上而下分别是业务层、Dapr Runtime层、基础设施层。Dapr 通过 Http 或 gRPC API 向业务层提供分布式能力抽象,通过称为 “Component” 的接口定义,实现对具体基础设施的插件式管理。

Building Blocks

作为一个合格的 Mecha,最关键的就是如何定义分布式能力抽象层。如何把各类中间件提供的分布式能力定义清楚是一项挑战。Dapr 中定义的分布式能力抽象层,称为 Building Blocks。顾名思义,就是一系列的 “构建块”,每一个块定义了一种分布式能力。

(来源:Dapr)

其中有一些 Blocks 的能力由 Dapr 自己就能实现,有一些则需要由实际的基础设施或中间件来实现。选取几个典型举例说明:

  • Service-to-service Invocation:提供服务间调用的能力,其中也隐含了服务的注册与发现。该 Block 的能力由 Dapr 直接实现。
  • State management:提供状态管理能力,最简单的就是存取状态。该 Block 需要其他基础设施通过 Component 的形式实现,例如定义一个 Redis Component。
  • Publish and subscribe:提供消息发布和订阅的能力,这是非常典型的一种分布式能力。也需要通过基础设施来实现,如定义一个 Kafka Component。

Dapr 的限制与挑战

Dapr 期望通过定义一个能容纳所有需求的分布式能力抽象层,来彻底解放业务逻辑。从归一化的角度看,不得不说这是一种大胆而富有野心的尝试,理想条件下的确能非常优雅地解决问题。但现实总是充斥着各种跳脱出理想的情况,Dapr 在推广的过程中遇到了很多限制与挑战。

与 Service Mesh 整合

作为面向开发侧提供的能力抽象层,Dapr 在网络能力上包含了 mTLS、Observability 与 Resiliency(即超时重试熔断等),但并没有包含诸如负载均衡、动态切换、金丝雀发布等运维侧的流量管理能力。

(来源:Dapr)

因此对于不断走向成熟的业务系统,可能既要 Service Mesh 在运维侧的流量管理能力,又要 Dapr 在开发侧的分布式抽象能力,不管谁先谁后,都将面临一个问题:怎样搭配使用它们才是正确的?某些场景下可以做适配,如:

  • 对于 distributed tracing 的能力,如果采用 Service Mesh 来实现,则需要考虑将原本 Dapr 直连的中间件也加入 mesh 网络,否则会 trace 不到。但从 distributed tracing 本身功能角度讲,更应该使用 Dapr。
  • mTLS 应该只在 Dapr 或者 Service Mesh 中开启,而不应该都开启。

但 Dapr 与 Service Mesh 配合使用中难以避免的是开销的问题,包括资源开销和性能开销。

每个应用 Pod 携带两种 sidecar,再加上 Dapr 和 Service Mesh 自己的控制面应用(高可用方案主备或多副本),这些资源开销是无法忽略,甚至是非常可观的。

而由于 Service Mesh 网络代理的流量劫持,网络调用需要先经过 Dapr sidecar,再经过网络代理 sidecar,被代理两次,也会造成一定的性能开销。

下表是汇总的 Dapr 官方标注的 daprd 资源与性能消耗数据,以及 Istio v1.16(最新版未找到)官方标注的 envoy 资源与性能消耗数据:

简单计算一下就会发现,当拥有 1000 个业务实例时,dapr + istio 的 Sidecar 进程可能会消耗 800+ vCPU 和 60+ GiB 内存。

随着分布式能力抽象层的不断扩展,到底哪些属于开发侧,哪些属于运维侧,也许不会像现在这样泾渭分明了。因此已经有对 Multi-Runtime 与 Service Mesh 能力边界越来越模糊的讨论。

Sidecarless?

从上一节的表格我们发现,资源消耗以及性能的问题其实不只是 Dapr 下的场景,实际上它是 sidecar 模式自有的限制,因此在 Service Mesh 领域的讨论中,已经有提出 Sidecarless 的概念了,即通过 DaemonSet 而不是 Sidecar 的形式来部署网络代理。

对于网络代理的 Sidecarless 化,支持方认为它能带来高性能、低资源消耗的优点,而反对方则认为它会导致安全性与隔离性差、故障的爆炸半径过大等缺点。

那么,Mecha 是否也可能会走向 Sidecarless 呢?

与网络代理的 Sidecarless 类似,如果将 Mecha 做成 Daemonset,其优劣势也差不多。而 Daemonset 形式的 Mecha,由于只启动一次,可能会在 Serverless 的场景下大幅缩短 Serverless 函数的执行时间。对此 Dapr 项目也有相关的讨论。

就像今年 Cilium 发布支持 Service Mesh 能力的办法,通过 eBPF 在内核态实现 L3 L4 层能力,而对应的 L7 层能力则交给用户态的 Envoy 处理这种将问题一分为二的思想,也许多运行时架构的未来方案也可能是折中或是多种方式结合的。例如采用在 Node 上按 Service Account 或 Namespace 运行多实例,或是轻量级 Sidecar 做协议转换+DaemonSet 做流量管理和网络调用。

当然 DaemonSet 也有其固有的缺陷,资源被共享从而降低消耗的同时,故障也被共享了,而且故障产生的伤害面也变大了,此外还会导致 DaemonSet 被应用使用的争抢问题,以及应用之间的数据暴露风险。到底后续将会如何演进,我们拭目以待。

定义抽象能力的(API)的困境

分布式能力抽象层,是对分布式场景下需求的抽象性定义,抽象作为一种共识,其要义就在于保留共性而排除个性。但实际当中会发现,同类型中间件的差异化恰恰体现在了一些高级的、细分的专有特性上,很多业务对中间件选型的原因也在于这些专有特性上。

这就引出了一个困境:抽象能力所覆盖的需求,其丰富程度与可移植性成反比。

就如上图所示,如果抽象能力范围只覆盖到红色的部分,则组件 ABC 的专有特性都无法被引入,而如果抽象能力范围覆盖到绿色,那么就无法迁移到组件C。

Dapr 的 Building Blocks 中,State management 就存在这样的一个例子:

State management 定义了基于事务操作的能力 /v1.0/state/<storename>/transaction,支持 State management 能力的 Component 有很多,对于支持事务的中间件如 Redis 就一切正常,但有一些并不支持事务的如 DynamoDB,则这种能力就无法使用。

定义抽象能力的困境,本质上是一种对能力收敛的权衡,这种权衡可能是与具体的业务需要高度相关的。

关于如何降低专有特性对能力集合可移植性的冲击,敖小剑在他的文章《死生之地不可不察:论API标准化对Dapr的重要性》中提到了四种解决思路:

(1) 在 Mecha 层弥补能力缺失

如果缺失的能力支持用基础能力来间接实现,就可以在 Mecha 内做处理。例如对于不支持批量写入的基础设施,在 Dapr 中通过 forloop 连续调用单次写入也能间接地弥补这一能力(虽然无法做到性能一致)。 然而这样也可能导致 Dapr 越来越臃肿,怎么权衡见仁见智。

(2) 在 Component 层弥补能力缺失

Component 作为某种具体基础设施与 Dapr 的适配器,可以将 1 中的方案下沉到 Component 里面,避免 Dapr 本身的臃肿,然而这种办法的缺陷在于每种基础设施只要想弥补缺失的能力,就都要分别在自己的 Component 中实现一遍。

(3) 直接忽略某些缺失的能力

例如在 State management 中对多副本强一致性的配置属性 consistency,假如实际的存储中间件是单副本架构,那么就可以直接忽略掉该属性。

(4) 其余的情况,只能在业务侧处理

就像前文提到的事务能力,对于不支持的基础设施必须要明确报错,否则可能导致业务不正确。这种情况就只能在业务侧做限制,本质上是侵入了业务层。

这四种解决思路从权衡与折中的角度,覆盖了绝大多数能力缺失的场景,本质上这些思路属于 “坚守API 能力交集” 的办法。假如跳出“抽象共识”这一限制,我们是否可以试图构建出一套包含了所有分布式能力的“大全集”呢?显然只是理论可行,但不现实。

然而,在企业实际的场景下,这个“全集”的规模可能并不一定像我们想象的那么庞大,因此就有可能提供额外的一种思路,即对分布是抽象层进行扩展,将有限规模的“个性”全部包含进去,形成 “并集” 从而规避上述问题。

蚂蚁 Layotto 的设计中体现了这种方案,详见下文。

蚂蚁金服的方案:layotto

蚂蚁金服作为 Dapr 的早起使用者,在落地的过程中结合遇到的问题及业务思考,在 2021 年年中推出了自研的 Mecha 方案:layotto。

Layotto 的架构

(来源:Layotto)

非常有趣的一点是,layotto 是以 MOSN 为基座的。MOSN 是蚂蚁金服自研的网络代理,可用于 Service Mesh 数据面。因此 layotto 类似于是 MOSN 的一个特殊的插件,向业务侧提供分布式能力抽象层,并且仍然以 Component 的形式封装各种中间件的访问与操作,而在这之下的所有网络层交互全部代理给 MOSN。

由于 layotto 在运行态上是与 MOSN 绑定在一个 Sidecar 内的,因此就减少了一部分前文提到的两个 Sidecar 之间通信的开销。当然 layotto 可以这样做也有一部分原因在于 MOSN 本身已经在蚂蚁内部大规模落地,同时蚂蚁也有足够的研发强度来支撑 layotto 的开发。

“私有协议”与“可信协议”

Layotto 的开发者,在讨论多运行时架构以及 layotto 落地实践的文章中,尝试对可移植性的概念进行了扩展,将支撑分布式能力的协议划分为“可信协议”与“私有协议”。

其中,可信协议指代的是一类影响力很大的协议如 Redis 协议、S3 协议、SQL 标准等。这一类协议由于用户众多,且被各类云厂商所支持,因此可以认为它们本身就具有可移植性。

私有协议则指代一些企业内部自研的、闭源或影响力小的开源软件提供的协议。显然这一类协议才更需要考虑抽象与可移植性。

因此实际上的所谓分布式能力抽象层可能会是如下图所示的样子:

(来源:如何看待 Dapr、Layotto 这种多运行时架构?)

各类可信协议不再二次抽象,而是直接支持,对其余的私有协议再进行抽象。这种直接支持开源协议的思路,部分缓解了定义抽象能力的困境问题。

灵活的扩展模型

前文提到的 API 扩展形成 “并集”,Layotto 通过提供 In-Tree 形式的私有 API 注册点,实现了不修改 Layotto 代码就能扩展 API 能力:

(来源:Layotto 官方文档)

从代码角度看,Layotto 是通过暴露 API 注册钩子,暴露启动入口,来允许用户自行扩展代码,之后再调用启动函数启动进程。这样扩展 API 代码与 Layotto package 级隔离,但编译后可形成同一个二进制文件。

另外,通过 MOSN 的 WASM 插件能力,Layotto 也支持通过 WASM 镜像来扩展 API Filter。

未来展望

虽然多运行时架构这种理念从提出到现在只有两年,但已经很少有人会否认它所带来的价值,不论是 Dapr 还是 layotto 的快速发展,都明确了头部企业对这一领域的投资逻辑。

当然目前从理论到实践可能都不够成熟,大家在落地实践的过程中也都会或多或少遇到前文提到的一些局限。但这些局限所处的层次大都是工程化、技术选择等具体的问题,相信随着各方技术的不断整合,实践的不断完善,问题都能解决。

对多运行时架构实践的未来,结合当下的限制、挑战以及趋势,我们也许能勾勒出某种未来可能的架构形态:

在这一架构形态下:

  • 分布式能力抽象层提供标准能力抽象,以及灵活扩展的私有协议的能力
  • 既成标准协议(对前文 "可信协议" 的另一种提法)作为 "既成的" 抽象能力,在Mecha 层只做协议转换或直接透传
  • Mecha 与网络代理层进程级耦合,各类特性不再明确区分开发侧与运维侧
  • 进程在 Node 上按租户/namespace 以及高可用要求划分多实例
  • 接入现代化的可观测性体系,提升对故障的洞察分析能力,降低由于架构分层带来的问题诊断困难

总之,不管是架构形态怎么变、能力怎么抽象,让业务逻辑不断内聚,越来越面向接口、面向能力编程的趋势不会改变,服务化体系的未来值得期待。

Reference

  • Multi-Runtime Microservices Architecture
  • Dapr
  • 死生之地不可不察:论API标准化对Dapr的重要性
  • Layotto
  • 如何看待 Dapr、Layotto 这种多运行时架构?
最后,推荐一款应用开发神器

扯个嗓子!关于目前低代码在技术领域很活跃!

低代码是什么?一组数字技术工具平台,能基于图形化拖拽、参数化配置等更为高效的方式,实现快速构建、数据编排、连接生态、中台服务等。通过少量代码或不用代码实现数字化转型中的场景应用创新。它能缓解甚至解决庞大的市场需求与传统的开发生产力引发的供需关系矛盾问题,是数字化转型过程中降本增效趋势下的产物。

这边介绍一款好用的低代码平台——JNPF快速开发平台。近年在市场表现和产品竞争力方面表现较为突出,的是最新主流前后分离框架(SpringBoot+Mybatis-plus+Ant-Design+Vue3。代码生成器依赖性低,灵活的扩展能力,可灵活实现二次开发。

以JNPF为代表的企业级低代码平台为了支撑更高技术要求的应用开发,从数据库建模、Web API构建到页面设计,与传统软件开发几乎没有差异,只是通过低代码可视化模式,减少了构建“增删改查”功能的重复劳动,还没有了解过低代码的伙伴可以尝试了解一下。

应用:https://www.jnpfsoft.com/?csdn

有了它,开发人员在开发过程中就可以轻松上手,充分利用传统开发模式下积累的经验。所以低代码平台对于程序员来说,有着很大帮助。

相关文章
|
7月前
|
运维 Linux Apache
LAMP架构调优(二)——修改Apache运行用户
LAMP架构调优(二)——修改Apache运行用户
250 1
|
7月前
|
资源调度 分布式计算 Java
Flink(三)【运行时架构】
Flink(三)【运行时架构】
|
安全 持续交付 开发者
Docker 架构解析:多角度解析 Docker 引擎与容器运行时
Docker 架构解析:多角度解析 Docker 引擎与容器运行时
109 0
|
持续交付 虚拟化 Docker
Docker 架构解析:理解 Docker 引擎和容器运行时
Docker 架构解析:理解 Docker 引擎和容器运行时
1349 1
|
2月前
|
前端开发 Java 应用服务中间件
21张图解析Tomcat运行原理与架构全貌
【10月更文挑战第2天】本文通过21张图详细解析了Tomcat的运行原理与架构。Tomcat作为Java Web开发中最流行的Web服务器之一,其架构设计精妙。文章首先介绍了Tomcat的基本组件:Connector(连接器)负责网络通信,Container(容器)处理业务逻辑。连接器内部包括EndPoint、Processor和Adapter等组件,分别处理通信、协议解析和请求封装。容器采用多级结构(Engine、Host、Context、Wrapper),并通过Mapper组件进行请求路由。文章还探讨了Tomcat的生命周期管理、启动与停止机制,并通过源码分析展示了请求处理流程。
|
2月前
|
消息中间件 监控 Java
大数据-109 Flink 体系结构 运行架构 ResourceManager JobManager 组件关系与原理剖析
大数据-109 Flink 体系结构 运行架构 ResourceManager JobManager 组件关系与原理剖析
81 1
|
5月前
|
NoSQL Redis 开发工具
Redis性能优化问题之检查 Redis 实例是否启用了透明大页机制,如何解决
Redis性能优化问题之检查 Redis 实例是否启用了透明大页机制,如何解决
|
5月前
|
消息中间件 API 数据库
在微服务架构中,每个服务通常都是一个独立运行、独立部署、独立扩展的组件,它们之间通过轻量级的通信机制(如HTTP/RESTful API、gRPC等)进行通信。
在微服务架构中,每个服务通常都是一个独立运行、独立部署、独立扩展的组件,它们之间通过轻量级的通信机制(如HTTP/RESTful API、gRPC等)进行通信。
|
Kubernetes Cloud Native 中间件
什么是多运行时架构?(上)
什么是多运行时架构?(上)
311 0
|
Kubernetes 监控 Docker
深入解析 Kubernetes 架构:掌握主节点、工作节点和容器运行时
深入解析 Kubernetes 架构:掌握主节点、工作节点和容器运行时
456 0