2019 JSConf China《面向传统,Serverless 进化之路》

本次 JSConf China 分享的话题叫 《面向传统,Serverless 进化之路》,主要讲述的是阿里集团内部逐步迁移到 Serverless 体系的过程以及思考。

自 GMTC 以来,国内各个公司在 Serverless 投入都有所变化,腾讯和阿里云都铆足了劲在上面发力,提出了各自的解决方案,前段时间腾讯推出了他们的 Serverless 2.0,以及几天前阿里云推出的预留模式,都是对 Serverless 越来越重视的表现。

下面还是进入主题。

今天我所介绍的,主要有两部分,第一是阿里在近期做的前端研发升级,为了拓展前端的边界和职能,尝试做了一次和 Serverless 结合,第二是在这其中,我们尝试对现有的体系做了思考,希望能将传统应用快速迁移到 Serverless 体系,享受到 Serverless 红利。

现状

之前 6 月在 GMTC 讲过,阿里的 Node.js 应用非常多,1600+ 的数量让维护和治理都变的很麻烦,每一次升级都要推行很久,这不管对框架开发还是平台治理都是不利的。

2019 JSConf China《面向传统,Serverless 进化之路》

很多 Node.js 应用都是 BFF 应用,内部平台等,这些应用常年大多都处在负载低(10%以下),没有流量的状态,而且维护者大多处在离职或者不积极的状态,一方面造成了资源浪费,另一方面也给治理造成了困难。

2019 JSConf China《面向传统,Serverless 进化之路》

其次,现在在集团开发传统应用,需要申请,整个研发流程还是比较长,需要业务了解预算和资源,牵扯到很多细节。

2019 JSConf China《面向传统,Serverless 进化之路》

为此,我们开始了 前端研发升级 这个大项目。

整个前端研发模式升级的目的有两个,一是为了“前端赋能”,二是为了“前端提效”。

所谓的“前端赋能”,是因为我们希望前端能够打破现有的技术壁垒,朝着更底层,面向数据的地方去深入,探索,在这之中可以从面向 UI,视图本身变的更加了解业务,从更面全面的视角来理解现有的体系。

2019 JSConf China《面向传统,Serverless 进化之路》

而“前端提效”,则是希望让 Serverless,用更轻量化的方式进行业务研发,降低整个前端参与业务交付的门槛,同时,在开发期间,也能减少人力总成本,让前端减负,业务小步快跑成为可能。

2019 JSConf China《面向传统,Serverless 进化之路》

但是阿里的 Serverless 的路非常困难,不像外界已经有的成熟的体系,目前一些原因无法使用上公有云上开放的产品,阿里云也无法直接对内部提供服务,同时,内部的中间件在外部都没有,都需要跨团队来重新建设。

而我们 Node.js 基础团队的使命,就是给集团 Node.js 生态提供各种基础能力,包括但不限于框架,中间件包等,而在 Serverless 体系,我们要负责框架、工具链、运行时、发布系统,同时也需要和周边的网关,监控系统等对接。

2019 JSConf China《面向传统,Serverless 进化之路》

收益

从去年 10 月开始,我们开始进行调研 Serverless 以及了解相关的知识,到现在为止,我们已经取得了一定的阶段性成果,将淘宝和飞猪两道 BU 的导购链路整个迁移到了 Serverless 体系,并且承载了导购链路的千万级流量。

2019 JSConf China《面向传统,Serverless 进化之路》

同时,内部系统也进行了一定程度的 Serverless 升级尝试,不管是重写还是传统应用迁移,我们都有了一定的沉淀。

我们最初的目的是希望能降低成本,按照网上 Serverless 的降低成本率能达到 90% 以上,不过导购业务比较特殊,流量比较大,不像那些需要弹性的应用,根据我们的测算,单进程下函数的性能非常不错,但是由于大促要提前预留一些资源,整体机器成本只降低到了平时的 70%,而在非大促期间,不需要预留这些资源,就能更低,降到 40% 以下。

2019 JSConf China《面向传统,Serverless 进化之路》

现在都说 DevOPS,而 Serverless 最大的好处是减少运维,减少固定服务器资源,不需要用户关心调度等,同时也简化了开发的代码,专注了逻辑,晚上睡觉会更加的放心,不再担心机器容量不足而报警。

2019 JSConf China《面向传统,Serverless 进化之路》

另一边,对于我们应用治理的人来说,之前会考虑各种版本碎片化的问题,node 的多版本,框架的多版本,以及启动脚本、依赖等等问题,而使用 Serverless 之后,我们将这些都固化了,用户也不关心这些,一切都变的简单了,我们也只需要治理运行时一个版本即可。

2019 JSConf China《面向传统,Serverless 进化之路》

在业务前端方面,带来的是挑战和机遇,一方面,前端的工作量增大了,能干的事情也变多了,成了一职多能的多面手,也更了解业务了,另一方面,传统的后端可以从和前端沟通中解放出来,更专注于提供服务。前端从传统的面向接口编程变成了面向服务编程,由于集团内都是 RPC 服务,在 RPC 发布时会有固定的定义和文档,在调用时有工具辅助生产代码,大大简化了调用链路。

2019 JSConf China《面向传统,Serverless 进化之路》

在流程方面,原来需要在各个环境准备和调研,从一开始申请应用,申请预算,申请环境开始,需要了解各个方面的知识,和不同部门的人打交道,流程审批也很长,而现在只需要在我们的统一研发平台上直接申请函数组,替代了原本的复杂流程,也提升了整个开发体验。

2019 JSConf China《面向传统,Serverless 进化之路》

同时在编码中也不再考虑路由,MVC 的事情,这些在网关层配置就好,编写代码时会更关注逻辑,和之前的构建发布不同的是,现在增加了云端集成测试的步骤,由于函数和前端代码一样,是分版本的,也不担心修改到线上的正常服务,在测试完毕后,只需要将旧函数的 tag 指向新函数即可,这就完成了整个切流的过程,而一旦碰到问题,把 tag 切回去就行。

2019 JSConf China《面向传统,Serverless 进化之路》

这整个就是我们前端研发模式升级的思考和收益,带给我们的不仅仅是变化,更多的是流程、思维的革新。

思考

在研发模式升级过程中,我们针对现有的导购业务进行了重构,可以说是使用了 Serverless 的方式进行了重写,而有一些老的应用,如果整体进行改造,这个成本会非常之大。

这个时候开发者就会有很常见的一个疑问,“我原来的应用,怎么迁移到 Serverless 体系”。

而我们的回答是两种:

  • 1、使用 FaaS + Baas 的方式进行重构,代码更精简,就是需要改造成本
  • 2、把整个传统应用作为一个函数,虽然不够优雅,但是能解决迁移的问题
2019 JSConf China《面向传统,Serverless 进化之路》

把整个应用迁移到函数会有一些限制,会对代码结构和模型做一些微调,以符合整个 Serverless 的结构,毕竟新的体系和传统的代码模型是有所区别的。

阿里集团采用的是 FaaS + BaaS 的实现方式,而 FaaS 的整体概念和传统的应用不太一样。

2019 JSConf China《面向传统,Serverless 进化之路》

在概念上,Serverless 比 FaaS 的外延要广,FaaS 属于 Serverless 的其中一种实现方式,主要解决的是用户自定义的代码逻辑如何做到 Serverless,也可以叫做 Serverless Compute,同时它也是事件驱动架构的一种。

而 CNCF Serverless 白皮书中也说到,Serverless Compute 是一种粒度更细的部署模型,通过一个或者多个 function,用于响应用户的需求。可以说,粒度小,灵活性高是它的最大特性。

在代码层面,为了让用户更好的理解,我们把传统代码的结构进行了分解,传统的 MVC 类型的代码,会分为几层。

  • 1、HTTP 服务,原框架(koa/midway/egg...),Node.js 运行时,启动脚本等,将会变为函数运行时,固化下来
  • 2、原有的 HTTP Router,Web 中间件等,将会由 HTTP 网关承接
  • 3、原有的 Controller,业务逻辑(调用远程服务),继续保留,变为函数代码
  • 4、原有的数据库,消息队列,RPC 调用等,都作为 BaaS 服务,用户只关心对应的服务,使用同一的 BaaS Client 进行调用
2019 JSConf China《面向传统,Serverless 进化之路》

这样分解过后,我们对新旧两个体系的代码结构有了进一步认识,可以开始尝试修改部分代码,变成真正的 Serverless。

迁移

传统的应用,会暴露出一些对外的服务供外部调用,比如 HTTP,定时任务,RPC 服务等等,这些服务一般我们会单独抽离目录,并且和其他暴露的服务共享逻辑层代码,我们也经常称这些服务为“入口”。

2019 JSConf China《面向传统,Serverless 进化之路》

在 Serverless(FaaS) 化的过程中,我们会根据当前部署平台的能力(比如阿里云 FC,腾讯 SCF 都会提供 HTTP 服务,定时任务,消息队列等等),将这些入口代码变为基于事件驱动的函数,

2019 JSConf China《面向传统,Serverless 进化之路》

我们通过构建机制,在发布时生成不同的包,在共享一份逻辑代码的同时,部署到不同的环境,这个方案最大的优势是复用了原有的逻辑部分,可以和传统应用同步开发,而劣势也有,就是包依赖混在一起,由于函数对包大小有限制,可能会造成依赖过大等问题。

HTTP 相对于其他的来说会复杂很多,会有很多限制,这个我们在讲下游方案的时候再说。

2019 JSConf China《面向传统,Serverless 进化之路》

针对上面的情况,对下游的数据调用我们也有相应的方案。我们将这些方案取了几个名字,比如代理模式和网关模式。

代理模式

首先来看看代理模式。一个传统的 Web 应用会分为 Router/Controller,以及逻辑层,在代理模式中,我们会保留传统的应用,只将原本的逻辑层部分迁移到了云函数中,暴露出 HTTP 服务。

2019 JSConf China《面向传统,Serverless 进化之路》

这样的好处是代码变的精简,改动适中,也易于服务复用,缺点就是依旧会占用一个应用资源作为代理层。

而代理应用一般是通过 HTTP 客户端代理来实现的只是用户体感上需要做一些额外的支持,让开发者在体验上感觉到是调用了远端服务。

2019 JSConf China《面向传统,Serverless 进化之路》

网关模式

第二种方式是网关模式,这个模式下,所有的代码都会迁移到新的体系,在 Web 层简单的时候比较适用。

该模式下,所有传统的 Web Router 会迁移到 HTTP Gateway 上,原本的路由,会话、鉴权等能力都将被网关所控制,而函数本身不需要关心这些,只需要关心数据即可。

业界现有的 FaaS 模型大多是这种结构,集团内也采用了这类结构去实践。

2019 JSConf China《面向传统,Serverless 进化之路》

在这种模式下,原有的能力会碰到一些问题,举一些例子:

  • 1、原有的 Web 中间件(koa middlware),会不知道如何处理,中间件大多是做请求流的拦截和消费,这个时候大多会拆成两部分,一部分被网关所处理,另一部分,只能交给函数本身,如果有共享的需求,也可以依赖模块来完成
  • 2、原有的会话维持,一部分平台会进行透传 cookie,这个时候你依旧可以维持一个 sessionId,同时使用第三方来存储数据,但是如果网关不做这块,那么就很麻烦了
  • 3、请求对象和原有的不同,由于函数获取的是 event,context 参数,或者原始的 request 对象,和现有的 koa 等框架不是很一致,上面的方法不一定有,会导致原有的代码做出修改和挑战

伪装者模式

那么有没有不修改代码的方案呢?我们尝试在函数外部进行代码包裹和数据模拟,让应用整个跑在函数之上,以一种 “微应用” 的方式继续存在。

2019 JSConf China《面向传统,Serverless 进化之路》

我们把原有的 Web Server(midway/egg),启动起来,在运行时中通过一个固定的端口转发,把 FaaS 的请求参数包裹成 HTTP Request 对象,而在出口处,也将 HTTP Response 包裹为函数能读懂的形式,通过这样续命的方式来延续传统应用。而由于阿里云上的容器只读不能写,目前还无法直接用这种模式。

2019 JSConf China《面向传统,Serverless 进化之路》

这种方式需要调整的是,框架需要使用单进程模型(机器配置,轻量化的要求),应用需要无状态(函数机制决定),以及没有长连接等高消耗的操作。

2019 JSConf China《面向传统,Serverless 进化之路》

总结

关于 Serverless 的问题还有很多,30 分钟我们无法关注到过于细节的地方,我们从阿里当前的状况讲起,分享了从去年到今年的研发模式升级实践,也介绍了在这其中我们的一些思考,传统应用迁移到 FaaS 体系下的方式。

感谢大家来 JSConf 听(阅读)我的分享,我们的整套方案希望经过双十一的洗礼,大流量的考验,在之后贡献给社区,开放给大家。


原文地址

https://zhuanlan.zhihu.com/p/87940654


分享到:


相關文章: