当前云原生应用的开发模式在 FaaS 环境下存在挑战,本文提出一种开发模式构想:“单体式编程,编译时拆分,分布式执行”,旨在简化云应用开发,提升开发效率和应用性能。思路是通过编译器自动拆分单体应用代码,实现云基础设施上的分布式运行。(Solo 社区 投稿)

背景

云原生应用通常形象地解释为应用架构出生或生长在云基础设施上的应用程序。此类基于云基础设施构建的应用程序能够有效利用云提供的自动扩缩、高可靠性等特性,这对于个人开发者和中小型企业来说,不需要关心基础设施的复杂性,又能获得强大的支撑能力,显然是一件很香的事情。

现状

那么,现在是怎么开发云应用程序的?提到云原生应用,大家通常会想到容器、微服务,这两项技术也在 CNCF 对云原生的定义中被提到。一个典型的开发流程可能是:开发者开发微服务粒度的应用代码,封装成容器,最终托管到 PaaS 平台上。

但随着云的发展,函数计算(Function as a Service, FaaS)已经成为云的重要组成部分。相较于 PaaS,FaaS 与云的各项能力结合的更紧密,在扩缩容、冷启动等方面,FaaS 的性能也更加强悍,例如,AWS Lambda 的冷启动时延已经达到百毫秒级。

问题

那么,微服务、容器的开发模式是否仍适用于基于 FaaS 的云原生应用?分析来看:

  1. 函数承载的服务通常被称为 NanoService,比微服务的粒度更小,如果由开发者将一个应用程序的每个函数逐个打包、发布,即使云厂商提供了命令行工具,整个操作过程也会比较繁琐
  2. 将一个应用程序拆分成若干个函数进行开发,各个函数在代码关系上互不相干,函数间的调用必须通过 SDK 进行,这使得开发一个应用需要在不同函数间反复切换,在编程思维上极不连贯
  3. 对函数进行编排需要了解云基础设施提供的事件机制、编排工具等,有了更高的学习成本

整体来说,直接基于 FaaS 的开发模式体验较差,如何有效管理和协调这些函数成为了一个重要问题。显然,我们不希望开发一个应用程序是这种体验,那么,我们该如何开发云原生应用呢?在这里提出一个构想:单体式编程,编译时拆分,分布式执行

联想

看到这个构想,你可能会觉得这与并行编程框架 OpenMP 的思路比较相近,的确如此。OpenMP 利用编译器在代码并行区域添加多线程代码实现并行执行,而在这个构想中同样是利用编译器识别并提取可独立计算的代码区域,但具体的分布式执行则交由云基础设施负责。

大数据计算的 MapReduce、Spark 可能也有些相似,以及近来比较火热的 Ray,同为云计算领域,同样都是面向大规模分布式计算。这里,与以上各类框架显著不同的一个点是,底层运行时实现方式的不同。以上各类框架都是各自构建了一套底层运行时环境来支撑特定种类任务的分布式执行,而这里的构想则是希望基于云基础设施提供的 FaaS 作为统一的底层环境,来实现通用计算,支撑各类云原生应用。两种方式相较而言,前者针对特定负载可能有调度、性能优势,而后者能与云基础设施提供的各项能力结合的更紧密,同时也能让各种场景的负载有结合的可能。

在开发体验上,的确是相近的。

构想

为什么要“单体式编程”

因为我们在开发一个单体应用程序时体验是非常好的,我们的上下文都在一个工程项目中,变量间的依赖关系、函数间的调用关系能够在执行前由 Lint、Format 工具,IDE 插件等各类工具进行检查。

为什么能“编译时拆分”

没有任何编程约束的代码文件的确难以进行拆分,但是可以通过定义关键字、特殊类、特殊函数等方式来指导编译器对代码进行拆分。

例如下面这份代码,可以将 Function 看作使特殊类,而它在构造函数中传递的函数定义就可以被分析提取成一个独立的计算模块。当然,在实际实现时肯定需要考虑更多的情况。

class Function  {
constructor(fn: (...args: any[]) => any) { /* ... */ }
} const fn = new Function((a: number, b: number ) => { return a + b; }); async main() {
const c = await fn.invoke(1, 1);
console.log("1 + 1 = ", c);
}
main();

特别的是,在拆分出一个个计算模块后,整个代码文件相应去除各个计算模块的代码,剩下的部分也应该成为一个计算模块。而这个计算模块就是整个应用程序的入口,类似单体应用中的 main 函数,而这个 main 函数就可以完成整个应用程序的逻辑编排。

这样,我们就获得了单体式编程的开发体验,并通过编译时拆分的方式获得了基于云的分布式执行的能力。这种开发模式的产物是直接长在云基础设施上的,属于云原生应用。

示例

来看一个基于这种构想的示例程序。这个程序是利用蒙特卡洛计算 Pi,整个代码逻辑很简单:创建 10 个 Worker,每个 Worker 各自执行 100 万次采样,最终汇总采样结果。

const calculatePi = new Function((iterations: number): number => {
let insideCircle = 0; for (let i = 0; i < iterations; i++) {
const x = Math.random();
const y = Math.random();
if (x * x + y * y <= 1) {
insideCircle++;
}
} const piEstimate = (insideCircle / iterations) * 4;
return piEstimate;
}); async main() {
const workerCount = 10;
const iterationsPerWorker = 1000000; let piPromises: Promise<number>[] = [];
for (let i = 0; i < workerCount; i++) {
piPromises.push(calculatePi.invoke(iterationsPerWorker));
} const piResults = await Promise.all(piPromises); const piSum = piResults.reduce((sum, current) => sum + current, 0);
const pi = piSum / numWorkers;
console.log(`Estimated value of π: ${pi}`);
} main();

这份代码执行起来的预期效果应该像上面这张图展示的:

  1. 在编译阶段,拆分出两个计算模块,一个对应 calculatePi,另一个对应整体代码去除 calculatePi 后的剩余代码(main 代码)。
  2. 然后将两个计算模块部署成两个 FaaS 资源实例。
  3. 部署完成后,调用执行 main 代码对应的 FaaS 实例,从日志中获取输出结果。

更复杂的示例可以从这里了解:

2024 年 Pluto 也将基于这个构想继续进行尝试,在具体实现时,会利用静态分析、IaC 等技术来支撑,感兴趣或有适用场景的朋友也欢迎交流。如果觉得想法不错,可以给项目点个 Star,谢谢。

GitHub 仓库: https://github.com/pluto-lang/pluto

订阅

这个专栏会同步更新在 Solo 社区、公众号、知乎、社群。

微信搜索"Solo 独立开发者社区"或者扫描二维码,即可手机订阅。

Solo开发者社区-重新思考云原生应用的开发模式的更多相关文章

  1. 解锁云原生 AI 技能 - 开发你的机器学习工作流

    按照上篇文章<解锁云原生 AI 技能 | 在 Kubernetes 上构建机器学习系统>搭建了一套 Kubeflow Pipelines 之后,我们一起小试牛刀,用一个真实的案例,学习如何 ...

  2. CNCF 旗下首个为中国开发者量身打造的云原生课程,《CNCF x Alibaba 云原生技术公开课》即将上线

    伴随着以 Kubernetes 为代表的云原生技术体系的日益成熟以及 CNCF 生态的逐渐壮大,“云原生”已然成为了未来云计算时代里一个当仁不让的关键词.但是,到底什么是“云原生”?云原生与 CNCF ...

  3. Canonical 开源 MicroK8 | 云原生生态周报 Vol. 25

    业界要闻 1.Canonical 开源 MicroK8 面向工作站和边缘/物联网的零运维 Kubernetes!MicroK8 是 Canonical 提供的一款功能强大的企业级 Kubernetes ...

  4. 云原生生态周报 Vol. 2

    摘要: Cloud Native Weekly China Vol. 2 业界要闻 Kubernetes External Secrets 近日,世界上最大的域名托管公司 Godaddy公司,正式宣布 ...

  5. 视频课程 | 云原生下的Serverless浅谈

    京东云开发者社区在3月底于北京举行了以"Cloud Native时代的应用之路与开源创新"为主题的技术沙龙,现场多位技术大咖与开发者们面对面就Cloud Native进行了深入交流 ...

  6. 牛年 dotnet云原生技术趋势

    首先祝大家:新年快乐,牛年大吉,牛年发发发! 2020年的春节,新冠疫情使得全球业务停滞不前,那时候,没有人知道会发生什么,因此会议被取消,合同被搁置,项目被推迟,一切似乎都停止了.但是我们却见证了I ...

  7. 专访 KubeVela 核心团队:如何简化云原生复杂环境下的应用交付和管理

    作者 | Infoq Tina 背景 12 月 9 日,在 2021 年 KubeCon 云原生技术峰会上,CNCF 开源项目 KubeVela 宣布推出了 1.2 版本. KubeVela 是一个简 ...

  8. 拥抱云原生 2.0 时代,Tapdata 入选阿里云首期云原生加速器!

      3月9日,阿里云首期云原生加速器官宣,Tapdata 突出重围,成功入选31 强,将与多家行业知名企业,携手阿里云共建云原生行业新生态,加速拥抱云原生新时代的无限潜能.   2021年,阿里云正式 ...

  9. Java云原生崛起微服务框架Quarkus入门实践

    @ 目录 概述 定义 GraalVM简介 为何使用 特性 官方性能 实战 入门示例 步骤 安装GraalVM 创建quarkus工程 Idea导入项目 Idea运行和调试 打包成普通的Jar 打包成依 ...

  10. 分布式云原生平台Kurator v0.2.0正式发布!一键构建分布式云原生平台

    摘要:北京时间2023年2月9日,Kurator 正式发布 v0.2.0 版本. 本文分享自华为云社区<分布式云原生平台Kurator v0.2.0正式发布!一键构建分布式云原生平台>,作 ...

随机推荐

  1. Netflow/IPFIX 流量收集与分析

    目录 文章目录 目录 Netflow(网络数据流检测协议) IPFIX(网络流量监测) IPFIX 组网架构 IPFIX 应用场景 Usage-based Accounting(基于使用流量的计费) ...

  2. 将外部jar打入本地maven仓库

    1.将jar包放入某不含中文的路径下 ,例如:E:\file\zip4j-1.3.2.jar 2.在命令行输入操作命令 mvn install:install-file -DgroupId=zip4j ...

  3. C#WPF的多屏显示问题

    如果想让窗口在第二个屏幕中显示 public MainWindow() { InitializeComponent(); Screen[] _screens = Screen.AllScreens; ...

  4. docker lnmp配置

    1.lnmp网络与目录规划 172.16.10.0/24 nginx:172.16.10.10 mysql:172.16.10.20 php:172.16.10.30 网站访问主目录:/wwwroot ...

  5. 机器学习策略篇:详解如何改善你的模型的表现(Improving your model performance)

    如何改善模型的表现 学过正交化,如何设立开发集和测试集,用人类水平错误率来估计贝叶斯错误率以及如何估计可避免偏差和方差.现在把它们全部组合起来写成一套指导方针,如何提高学习算法性能的指导方针. 所以想 ...

  6. 代码审计——基础(JAVAEE)

    JAVAEE 目录 JAVAEE 常见框架 Struct2(控制层) Hibernate(持久层(与数据库交互)(不用再写简单的sql语句,但是需要一些列复杂的配置文件))(全ORM模型) Sprin ...

  7. SQL练习之打卡记录数据统计类问题

    最近老婆的公司,关闭了OA系统中,各类打卡时间数据统计的功能,为了不麻烦老婆手算,就做了一个简单的打卡系统,方便自动统计老婆想要知道的各类数据. 做的过程中就遇到了几个还挺有意思的SQL,这里写成一篇 ...

  8. SQL server查看触发器是否被禁用

    1 select a.name as 触发器名,b.name as 表名, 2 case a.is_disabled when 0 then '启用' when 1 then '禁用' else '未 ...

  9. C#.NET Framework RSA 公钥加密-私钥解密

    C#.NET Framework RSA 公钥加密-私钥解密 加密解析: //假设私钥长度为1024, 1024/8-11=117. //如果明文的长度小于117,直接全加密,然后转base64.(d ...

  10. C# .NET6 .NET CORE EXCEL 导入和导出

    使用NPOI导入.xlsx遇到"EOF in header"报错,网上找好很多方法,没解决,最后换成EPPlus.Core导入. 导出默认是.xls. NPOI 操作类: usin ...