Laf 云开发平台及其实现原理
Laf 产品介绍
自我介绍
大家好,我是来自 Laf 团队的王子俊,很高兴今天能在这里给大家分享我们 Laf 云开发平台及其实现原理。本来想说一点什么天气之类的话作为开头,但主持人都说完啦,我就不多说了,还是直接开始今天的分享吧。
产品介绍
在准备 PPT 的时候,我想过很多种的方式来介绍我们是一个什么样的产品,但后来我发现在我们文档和官网上面这两句话完全就可以说明我们是一个什么样的产品 :
第一就是说我们是一个像写博客一样,写代码可以随时随地上线。
其次就是专注业务本身,让开发者能快速地释放创意。
为什么说像写博客一样呢 ? 因为写博客的时候,你可能会打开一个博客平台,你的电脑打开一个浏览器,然后你码完字,点一下发布,你的博客就可以被别人看到了。
那我们开发的时候是不是也可以说,我只要有一台电脑能打开浏览器,然后我进去就可以直接写代码,写完代码之后,我点一下发布,我的一个接口,我的一个应用可能就写完了。
第二就是说专注业务本身。在座有很多都是开发者,我们身为一个开发者,很多时候会有想做一个小工具,或者说想做一个应用的这么一个想法。
但等我们把环境部署好,准备好之后,这个环境是指我们电脑中的环境,比如说数据库等等这些资源,也有可能是我们身边的环境,比如说没带自己的电脑出门。
但如果说我们产品存在的话,你可能只需要摸到一台能打开浏览器的电脑,就可以进行你的编码工作了。
然后下一个环节,我是打算给大家演示一下我们产品。
产品演示
本来我是准备了一个视频的,但我觉得视频做的有一点早了,很多功能在我们官网上没有展示出来,所以我还是跟主办方沟通了一下,准备现场演示一下,我会在后面用电脑给大家演示一下,大家稍等我一下。
这里是产品演示,大家可以访问 laf.run 或者 laf.dev 来体验。
产品特点总结
好,演示环节就到此结束了。我用三点给大家总结一下,就是我们项目的特点 :
-
开箱即用的应用资源,包括提供计算资源、数据库资源、日志网络存储等应用所需要的一切资源,不需要准备任何环境,包括电脑环境和物理环境。
-
目标是尽可能缩短开发流程,降低开发门槛。如果一个应用部署一个环境需要一天,我们可能一天已经做一个 demo 出来,已经上线发给用户或群友测试了。
-
开源开放的态度,Laf 所有的源代码是开源的,我们用的组件也都是开源的,不包含任何厂商绑定,可以跑在任何云上,没有后顾之忧。
技术实现介绍
技术选型
然后介绍一下我们整体的技术选型。在编程语言方面,我们选择了 Node,最大的原因还是降低开发门槛,因为一个项目中你会用到前端,用到前端你可能会用到 JS,你前端写 JS 后端也写 JS,开发就不会割裂,可以覆盖更多用户。
然后存储方面我们选择了 MinIO,MinIO 最主要它是一个开源,除了开源之外,它提供了非常不错的横向扩展能力,我们可以通过增加节点来增加它的存储能力和处理能力。
数据库方面我们选择的是 MongoDB,MongoDB 有一个最大的优点,对于我们来说,它是非关系型的数据库。那么如果使用关系型的数据库,开发者可能门槛会提高一点,他需要去设计表,在做应用之前,他去设计一下表结构。如果用 MongoDB 的话,你可能不需要设计表,先去写业务逻辑,等你觉得你需要存储数据了,你再去使用 MongoDB 数据库。
网关我们选择的是 APISIX,它可以无缝地修改动态路由,还有它有丰富的插件。最重要的是它开源开放的能力。我们每一个云函数,每一个应用,每一个 bucket 都会分配一个给它一个二级域名。就会通过它动态路由的修改来不同的映射,就可以在我们创建云函数和创建 bucket 的时候,无缝给大家起一个二级域名,让大家应用还没有域名的时候,可以直接上线,直接进行访问。
实现流程图
然后下面是一个具体的实现流程图。我们从左边看是一个开发者的视角,我们可以通过外部 IDE,或者说我们提供的 CLI 本地开发,然后创建一个应用,连接到 Laf 的 server,然后它会把我们应用的信息,存储到数据库中,然后准备对应的资源,通过 Kubernetes 创建一个应用实例,然后里面放一个 Node 的 runtime,然后分配一个数据库,分配一个存储,整个应用从创建到启动,成功的流程就完成了。
然后从右下方开始看,这就是我们用户调用我们一个云函数,或者调用一个接口的过程。我们的流量先打到我们的网关,然后网关根据 APPID 找到,确定的某一个 runtime,然后在 runtime 中,我们云函数的名字又是唯一的,就可以确定执行哪一段函数代码,然后直接响应返回到外网。
Serverless 实现方案比较
说到 Serverless 它有一个传统的解决方案,就是说一个请求会对应一个进程,也就是说我们每次请求,它就给你创建一个 runtime,创建一个 pod,然后进行这么一个调度。
它的优点是比较明显的,说无缝弹性伸缩,因为它每次都会重新创建一个,所以就不存在弹性伸缩的概念了。因为它每一个都是一个新的 pod。技术选型的也比较性感,是一个非常优美的模型。
但它缺点也同样的明显,就会存在很多开发者介意的冷启动问题,还有长链接无法完美支持,导致开发习惯割裂。
这开发习惯割裂是指什么 ? 因为我们传统开发用一个云数据库的话,它也是一直跑在那里的,不会说我们每次请求过来,它会重启一个,就像现在很多的 AI 项目,它会接入 ChatGPT 的 OpenAI 接口。如果说用我们长连接内存的方案的话,我们只需要保存一个会话 ID 就可以支持上下文的调用了。如果没有全局缓存的话,你就需要把所有的聊天记录保存到数据库中,然后每次再输入进去,这样才能进行一个上下文的关联。
然后我们的技术选型,就是一个长连接内存的方案。它天然就不存在冷启动问题,我们容器是一直跑在那里的,就跟你一个云服务器一样,你每次请求打过来之后,它就能及时的响应。当然我们天然就支持长链接了,同样的内存,我们可以负载更多的请求,因为我们没有资源准备,资源创建,资源销毁的这么一个过程,我们的资源是一直跑在那里的。
关于弹性伸缩,我们用 Kubernetes 的 HPA 来实现,你输入自己的预期值,它会根据你负载过高,它会增加不同数量的 pod。如果说你的流量很低了,它可能会帮你缩减减少不同的 pod。当然这么做实现起来稍微要复杂一点。
但是我们把复杂留给了自己,简单留给用户,就是我们这套技术选型,它是以用户为驱动,而不是以技术为驱动的。用户需要长链接,我们就去支持了长链接。用户不喜欢冷启动,我们就把冷启动给干掉。这样我们可以做到你的调用次数越多,你的流量越多,你的成本就越低。
云函数调度流程
然后这里就大概一个流程图,展现了一下调度的方案。左侧是传统的方式,一个函数请求进来,它就会新建一个运行时来处理函数,处理请求。
而如果用我们的方案,所有的函数打到 Laf server,然后有一个任务队列,用一个运行时来处理这些所有的请求。如果说达到我们设置的负载了,它可能会新建一个 pod 去分散一下流量的处理。
然后两种方式的资源利用率,我这里也是用图简单概括了一下。传统方式它会在没有请求的时候,资源利用它确实是零,没有任何消耗。但是如果随着请求越来越多,它有资源创建和销毁的过程,就会导致请求随着资源利用率,就会线性的增加。
那 Laf 可以做到在负载比较高的时候,仍然能够保持非常低的资源占用。还是那句话,我们不需要经历创建和销毁的过程,我们是一直运行的,跟一个服务器没有任何区别,我们只需要准备一下代码段所需要的上下文就可以了。
云函数开发体验
然后后面是一些关于我们怎么实现这个方案的一些细节,就是一个云函数从动态发布到执行,到底经历过哪些过程,才能做到让我们的云函数比其他要快很多。
一个用户编写完云函数之后点击发布,因为我们是 TS 支持类型提示的,我们要把它编译成 JS,然后先存到数据库中,同时也把编译好的函数发布到应用对应的 runtime 中,然后我们还会用 Node VM 模块,把它处理成 VM 的 script 的对象,缓存到内存中的一个 map 中。这样的话我们每次调用云函数的时候,就直接从内存中去取那个 VM 的 script 对象直接执行就好了。
我们没有编译的过程,所以每次响应就快了一点。通过 HTTP 调用的过程,也就是从内存中取出我们编译好的对象,准备好上下文,比如说传入的参数等等,以参数的方式传进去,然后直接执行代码,然后执行结果 HTTP 返回就好了。这就是我们云函数从编写到入库,发布执行调用的一个过程。
那么我们团队认为一个能够像写博客一样,写代码最重要的体验就是说,我们要有一个完备的 web IDE,因为如果说这个 IDE 用起来非常的不方便,大家都不想用,我们就失去了像写博客一样写代码的体验了。我们认为一个完备的在线编辑器,需要有以下能力的支持 :
- 完整的代码类型提示,如果代码量稍微大一点,没有类型提示的,写起来是非常痛苦的。我们就会在云函数客户端那里去分析一下,我们所需要的依赖的列表,然后去请求 runtime 去递归的遍历依赖的 node_modules,找到它依赖的类型文件,再把它扔回来,给前端的编译器,编辑器我们用的是 VS Code 的,它对 TS 支持就比较友好。
- 可在线运行调试,因为我们随便拿过来一台电脑,就可以写代码。
- 可以安装用户需要的 npm 依赖。
- 有变更记录,可以回滚指定版本。
- 最下面就是我们刚刚演示的 AI 自动生成云函数这个功能是基于我们公司另外一个产品实现的,叫 FastGPT,它可以把你自己公司的数据库输入给 GPT 进行微调,然后它就能掌握你所提供的知识库的知识,根据你的知识库帮你回答问题。
后面我也会分享一下 FastGPT 具体的实现原理。
云函数是最基本的一个代码单元,那么有一些逻辑需要复用,或者说你写一些库的时候,就需要一些互相调用。在这里我们是 hack 了一下 node require,如果说我们去引用一个云函数的时候,我们确定它是一个云函数,就会把它处理成一个 node module,直接返回,就像我们引入一个 node 包一样,就非常的自然。
多租户隔离
关于 MinIO,我们如何实现多租户的隔离策略。其实我们每一个 MinIO 的存储的 bucket,我们会强制的在它的 bucket name 之前,给它加一个它的 APPID。
然后我们把 APPID 作为一个 MinIO 的 user name,我们会创建每个应用创建一个 user,然后我们只要给 s3 设置一个访问策略,就可以让它只访问自己 user name 开头的 bucket 就可以了。然后配上一些权限,就可以实现多租户的隔离,因为 MinIO 是一个集群,所以每个人只能访问到自己的 bucket,才是对文件的保护。
然后数据库也会同样遇到多租户隔离的问题,但还好 MongoDB 它自身有一个用户管理机制,所以我们也只需要给每个应用创建一个 user,然后利用它自身的管理机制,实现权限隔离就好了。
但在这里有一个比较重要的问题,如果我们用了多租户,就会需要去限制一下,或者说设计一个请求的频率对每个租户,因为如果有这种恶意请求都打到整个机器上的话,可能会影响到平台上其他的用户。
我们就会对连接到 MongoDB 所有的流量进行一个拆包,然后看看它的请求频率是否超过了我们限制,如果超出了,我们就把它丢弃掉,然后没有丢弃的我们就打入进来,然后从此来统计一下,也可以实现数据库的计量计费。
网关和路由
网关我们选用的 APISIX,刚刚简单介绍一下它可以无缝地修改动态路由,还有它有丰富的插件。最重要的是它开源开放的能力。我们每一个云函数,每一个应用,每一个 bucket 都会分配一个给它提供一个二级域名。那就会通过它动态路由的修改来不同的映射,就可以在我们创建云函数和创建一个 bucket 的时候,无缝给大家起一个二级域名。
AI 编写代码实现
然后这里就是刚刚 AI 写代码能力的一个实现分享了。从上往下看就是数据处理这个部分,我们会通过模板市场和我们的技术内容,就是文档,然后把数据向量化之后,存入到向量的数据库。
然后用户提问的时候,问题可能就分为三类,一个是写业务代码,一个是关于我们基本文档使用的问题,还有其他问题。
如果是其他问题就直接回复我们,就是说不相关的问题,我们不回答就好了。如果是代码问题,它就会到代码数据库去搜索相似内容,作为大模型的知识,然后扔给大模型,比如说我告诉你,我们产品的代码是这么实现的,关于登录的三个函数是这样的,然后你重新给我写一个用户需要的登录函数,返回给用户就可以了。具体就是通过拆分问题,预训练来实现的功能。
产品展望
然后就是关于扩展性了,因为我们给大家提供的,比如说 MongoDB,比如说云存储等等一些能力,都是我们固定好的。
如果说有的用户,我就需要 Redis,我就需要消息队列等等,一些其他的云服务,甚至说是我们自己的业务系统,我们 Laf 是放在 Sealos 上运行,Sealos 是另外一个产品。一句话总结就是一个云操作系统,在云操作系统上面,可以跑任何的其他服务,包括 Redis 等等这些。如果他们都跑在同一底层上面,就可以通过内网调用,也就是说我们的扩展性非常强,你需要其他什么样的场景支持,我们只需要去跑一个就可以了。
讲完基础的实现,我们这个产品,有一些下一步需要做的东西,也就是说我们未来规划。刚刚我们讲了,我们现在支持的编程语言是 Node,是因为我们想把 Node 做得更好,更多的覆盖更多的用户。下一步我们可以考虑其他语言的扩展,比如说 Python、Go 甚至是 Java 等等,因为我们实现原理刚刚讲过了,都很简单,只要塞一个运行时就可以了。
然后就是更强的 AI 能力,现在我们的 AI 它只能写代码价值有限,所以我们下一步可能会让它具备自己调试,自己上线的功能。
我在下面大概画了一个简图,就是 AI 编码之后,它会自己生成一个测试用例,自己去测试结果,然后反馈,然后去验收,验收如果不通过的话,它会扔回来自己 bug 修复,再去测试,再去验收,就这么一个反复的逻辑来走通,自己写完代码自己上线。现在代码我们还可能还需要去改一改,等我们这个功能完成之后,可能就不需要去改了。
然后就是更丰富的函数模板市场。函数模板现在我们是已经上线了,在函数市场中有很多我们重复的业务逻辑,比如说登录支付等等这些共用的,我们就不用每个人都写一遍了。因为大家用我们的产品写的都差不多,我们只需要点一下,就可以加载到自己的应用中。
函数模板跟 AI 能力,它其实是可以相互关联的,因为 AI 它会写代码,它就可以创造更多的函数模板市场。有更多的函数模板,就可以让 AI 训练的资料越来越多,它给出的答案就会越来越准确。
但是我们现在虽然解决了环境的问题,和重复造轮子的问题,但这还不够快。
最快的开发就是不用开发。下一步我们有一个应用市场上线,很多应用它都是重叠的,比如说像我们楼下健身房的约课系统等等,一些系统,它都是重复的,一个人开发就好,不用大家都开发。我们会上线一个应用市场,应用市场你只需要点一下,就可以把这个应用部署起来。如果这个应用适合你的场景,你只需要点一下就行了。这才是我们最终极的目标,就是最快的开发是不用开发。
案例介绍
然后给大家分享一下我们目前 Laf 上的一些比较有趣的案例。上面前三个是我们社区同学贡献的一些插件,像 VS Code 这些插件,有些人还是不喜欢我们的 IDE,他可以用这个插件就可以在自己本地进行 VS Code 或者说其他的编辑器进行开发。然后是两个关于后台管理的快速开发平台。
第一个要稍微强调一下,这个是两个大三的学生,用一个晚上的时间用我们的产品来写出来的一个项目,叫 Chat Mind,就是一个 AI 生成思维导图的工具,你可以告诉他,比如说帮我生成一个旅游攻略等等,他会给你画好思维导图,或者总结一个支持点,这个项目目前已经被 XMind 收购了。大概上线一个多月被收购的吧,两个大三的学生一晚上写出来的。如果不是我们产品存在,他可能要写更久的时间,甚至说他们就把这个事情给忘记了,放弃了。
然后下面是我们一些关于教育系统和电商系统的一些案例。中间这个稍微提一句比较有意思,它是一个猫谱,中大的一个学生写的,就是把他们校园里的流浪猫,可以收集进来,通过这个猫脸识别,可以扫出来这只猫它的信息是什么,它的名字是什么。我们现在也在做了这个支持活动,就是对所有的高校,如果他们部署这个猫谱项目的话,我们是给他提供一年的免费,就是用我们的这个东西是不收他们钱的。然后我们 Laf 一部分的收入,也会拿出来去救助那些流浪猫,这是我们觉得一个比较有意思的项目。
生态介绍
然后因为我们是一个开源的项目,现在生态就是给大家展示一下这里 STAR 5.3K,我们 1.0 版本上线至今,还不到三个月,我们在线用户数已经是 14000 了,应用总数量也接近 10000,活跃应用在 2300 左右,包括我们海外版本。
我给大家的分享就到此结束了 , 其实我们的产品实现起来本身就没有这么困难,只是说我们没有通过技术去驱动,我们通过用户需求去驱动,用户需要什么,我们就以最快的方式,最简单的办法给用户实现,这是我们产品目标。谢谢大家。