自2019年开源Midway框架后,阿里巴巴一直在深入研究Node.js的前沿。除了加入TC39参与标准化建设,持续对上游Node.js项目做出贡献,除了与龙蜥社区合作优化外,在Serverless领域也颇有建树。今天给大家介绍一下我们最新的Serverless架构下面向云原生场景的新产品,代号Noslate。什么是诺斯莱特?欢迎访问项目了解更多:https://github.com/noslate-pr...JavaScript是开发者最多的编程语言。早年Node.js等技术的出现,让JavaScript可以轻松处理各种服务器任务。但在云原生/Serverless等新架构理念的引领下,弹性效率成为新的架构设计目标。为了让JavaScript任务更加灵活高效,进而满足泛终端和全栈交付领域的效率期望。在逐步深入的探索中,我们逐渐形成了Noslate项目,旨在提升JavaScript在云原生场景下的调度性能,解决诊断性黑盒问题。Noslate主要由三个子项目组成,分别反映了我们在提高Javascript任务弹性效率过程中遇到的问题和解决方案:Node.jsDistribution:初步针对函数计算冷启动场景进行优化,减少Node.js用户codeloading耗时,形成一个有针对性的Node.js发布版本。NoslateWorkers:随着探索的深入,我们针对轻量级端云同构场景,设计了W3CWeb可互操作的JavaScript轻量级容器方案。它在交付灵活性与资源和执行效率之间取得了平衡。现在主要用于集中式SSR渲染等轻量级任务场景,效果显着。NoslateDebugger:在实现业务的过程中,我们发现弹性效率提升后,异常和崩溃的定??位变得困难。得益于Linux系统Coredump机制的启发,我们设计了基于Corefile的离线诊断问题的NoslateDebugger产品,帮助用户实时追溯和定位问题。简而言之,Noslate的目标是通过提供完整的技术产品解决方案,让JavaScript成为云原生时代最灵活的交付语言。为什么开源?一方面,我们希望通过开源加强项目的产品化;另一方面,我们希望吸纳更多社区的实际场景,不断完善产品设计。欢迎大家参与该项目。同时,依托阿里云龙里社区与Anolis操作系统的合作,我们能够在底层进行探索,实现技术的演进。1.NoslateWorkersW3CWeb互操作运行时Aworker提供了一个轻量级的JavaScriptServerless运行环境,几乎是零冷启动。通过它,您可以轻松地将轻量级的Serverless能力集成到现有架构中。与传统的FaaS架构不同,这是一个在通用应用程序容器之上的轻量级任务单元。得益于良好的动态任务高密度混合和隔离特性,以及任务状态复制API带来的几乎零冷启动特性,任务可以在使用时立即启动,在停止抛出时,有无需关心集群中任务节点的整个大规模编排。与现有架构的关系:NoslateWorkers由两个主要组件组成:Aworker-轻量级、Web可互操作的JavaScriptRuntimeNoslated-ServlerssAworker调度控制实现关于Aworker提供WebAPI标准Web可互操作的JavaScript运行时,适用于不同业务逻辑的直接部署依赖于系统接口。Aworker实现了一个类似于ServiceWorkerAPI的规范,提供了一个基本的Request-Response服务API。因为提供了比Node.jsAPI更高级抽象的定义,不泄露系统底层状态,Aworker通过StartupSnapshot和Warmfork能力实现更快的水平和垂直扩展,可以毫秒级启动和运行.以更高的弹性效率处理流量。亮点特点一:Warmfork熟悉Linux系统编程的同学都知道fork(2)系统调用有几个优点:新进程可以继承父进程的当前状态,无需从main()初始化;pcb,stack,memorypages,pagetables都是纯内存拷贝,所以进程创建速度快(<1ms);CopyOnWrite,新进程可以继承父进程的静态页表,可以节省系统内存;对于Node.js来说,因为不能在主线程中持有所有的多线程状态(比如锁,信号量等),所以在Node.js中修改fork是非常困难的。它的多线程设计主要来源于libuv库和V8PlatformWorker线程:因为有些IO操作有同步调用,比如dns、文件读写等,libuv使用IO线程将同步操作转换为异步操作;Node.js的V8默认配置为多线程GC,后台编译/优化;Node.js的单进程多线程模型可以用下图来表示:Aworker被设计成采用单进程单线程模型,即将上述模型中的worker线程抽离出来,放到一个单独的过程。所以Worker可以支持fork,从而避免从main()开始的启动消耗,达到快速启动的目的。为了支持单线程,Aworker还做了如下修改:使用LinuxAIO特性来代替libuv中的同步文件系统操作(不是POSIXAIO,两者是有区别的。posixAIO类似于libuv现有的实现);使用V8的SingleThread模式是针对低端设备的能力,但它与Serverless资源模型非常一致;为了管理和隔离这些工作进程,我们需要一个轻量级的业务流程容器管理组件Turf,该组件用于通过Warmfork创建一个新的Aworker服务进程,并能提供一定的资源环境隔离能力,并兼容OCI.与传统的runc和rund容器不同,turf旨在承载Aworker等轻型JS运行时。不需要镜像运行,开销更低,可以支持更高的部署密度。AlinodeWarmfork具体对比:提供一个“复制”进程,称为“种子进程”,其他服务进程都是这个进程的克隆。例如,Aworker被用作种子进程。它需要确定自己“可以被克隆”的时间点,并以自己的状态(内存)作为被克隆进程的初始状态。Warmfork的系统顺序如下:亮点特点2:启动快照Warmfork可以解决单机服务进程快速启动的问题。对于冷机启动,需要启动快照解决方案。StartupSnapshot和CodeCache的区别在于,StartupSnapshot可以保存用户代码逻辑执行状态,而CodeCache只保存代码分析结果,仍然需要重新执行用户代码逻辑。在设计上,StartupSnapshot可以提供与用户代码逻辑的快速恢复,但它也有局限性:StartupSnapshot对内存开销敏感。如果在应用程序启动阶段使用大量内存,可能会造成负优化;用户代码启动需要明确的状态。如IP地址、日期、连接状态、服务发现结果等。对于这些有歧义的内容,用户代码需要有在进程恢复时纠正的能力;V8的StartupSnapshotSerializer是一个类似于GC的对象遍历器。这个遍历器遍历添加到Snapshot中的Root对象,遍历其对应的对象图,根据对象关系生成一系列的反序列化指令。StartupSnapshot相当于从V8的Context对象及其globalThis开始,遍历堆中的所有对象,将对象关系和引用序列化为唯一的字节码,形成一个线性的可存储状态。并且在恢复、解释和执行这些字节码的时候,恢复堆中的对象内容以及它们之间的引用关系。以上两类与调度性能相关的特性统称为状态复制API。具体使用可以参考官网文档中的《状态拷贝 API》章节,里面详细介绍了程序中的命令行参数和事件。https://noslate.midwayjs.org/...NoslatedNoslateContainerDeamon作为NoslateWorkers解决方案的核心控制程序,提供实例调度、弹性伸缩、配置管理、流量管理等能力。基于健壮性的考虑,它由两个角色组成:ControlPlane和DataPlane。Noslated实例管控主要有三种模式:基本模式-基于流量的伸缩和丢弃模式-运行后即销毁预留模式-兼容历史场景,这里不再展开。详情请参考官网【预订政策】。1.Basic模式当流量进入DataPlane时,如果没有可以处理请求的Worker实例,会通过requestQueueing事件通知ControlPlane,ControlPlane会根据当前水位来决定扩容多少。如果当前无法创建Worker实例,会返回资源上限错误。新的Worker实例启动后,会自动连接到DataPlane。DataPlane发现有新的Worker实例连接后,会主动触发初始化请求。初始化成功后,会开始消费请求队列中积累的请求。当Worker实例空闲一段时间后,ControlPlane会主动发起GC操作,并通知DataPlane关闭流量。关闭流量后,ControlPlane会通知Turf关闭Worker实例,清理资源残留。2、即时抛出模式针对特定的灵活场景,一次性轻量级用户脚本执行(比如SSR等双方任务的特别高密度混合分区执行),以隔离不同请求之间的上下文,你可以为每个请求实例创建一个并在执行后销毁。比如普通的有业务逻辑的Node.js实例一般不会启动得太快,直接响应用户流量是不可接受的。得益于Aworker运行时以及Warmfork和StartupSnapshot功能,可以更快地启动Worker实例。也可以将业务本身的部分初始化逻辑放到Warmfrok特性中,使得新实例的初始化时间最少,使得高密度混合部门二方任务成为可能。3、预约方式这里不再展开。详情请参考官网【预订政策】。2.NoslateDebuggerNoslateDebugger是一款针对V8应用的离线分析工具。可以分析Node.js等应用产生的Corefile(Core文件):检查Node.js/V8应用的结构、堆栈等,检查V8堆从Corefile中导出各种对象信息HeapSnapshot业务无意义获取Corefile(通过Arthur工具)已经支持Node.js/AWorkerLTS正式发布为了更好的解决问题而不是造轮子,Noslate将在未来几个月发布Debugger也将与优秀开源的EasyMonitor构建集成国内社区在Node.js稳定性领域的软件,以及在Node.js/V8问题诊断领域形成合力,同样值得期待。优势一:基于Corefile的“快照”更适合ServerlessServerless应用通常使用大量生命周期短、规格小的任务实例,但此类任务实例不易获得调试和诊断能力,这使得Serverless应用程序处于一个相对长期的Theblackbox困境。比如Inspector需要稳定、长时间的网络连接,HeapSnapshot在运行时需要更多的计算和内存资源,这些都与Serverless架构背道而驰。无论是V8对象还是堆快照,都是“信息”在内存中的存储,Inspector功能可以在“运行时”提取这些信息。NoslateDebugger利用Corefile将这部分调试诊断能力转移到离线,使得原本实时性要求高的在线诊断调试仅通过简单的文件上传即可集成使用。在用户本地或云服务上,提供接近用户本地开发的调试诊断体验:Corefile(具体为GNUCorefile格式)主要记录Node.js进程的内存和寄存器转储(CoreDump:进程从内存到磁盘)。因此,它也是进程的完整“信息”,作为Linux系统应用Crash(有损)的调试载体,也可以用于GCore(无损)生成进程快照,供离线分析。优势二:业务影响更小相比原来线上“堆快照”对业务几分钟的影响,对业务的影响只是秒级(通过GCore),甚至几十毫秒(通过Arthur工具)。Corefile快照不会有任何运行时“添油加醋”,因此也适用于定位没有被GCed的对象,比如诊断已经结束的业务流程。Arthur是NoslateDebugger中使用的一个工具,用于以低影响获取核心文件。它使用fork来减少进程暂停时间,并使用LZ4压缩来减少转储大小。带业务流量的线上环境抓包,业务影响为31.106毫秒,Corefile大小为338MB(进程原本使用1.44GB物理内存)。3.Node.js发布版本我们还针对弹性场景对Node.js实例进行了优化,提高了用户代码的加载速度,从而减少了冷启动时间。主要包括Require关系加速和BytecodeCache,优化效果提升可达100%到200%。此版本还包括阿里云基础软件团队在ARM架构上的性能优化功能。冷启动优化PGO(ProfileGuidedOptimization)是一种基于运行时ProfilingData进行编译和优化的技术。这里借用这个概念。主要是在执行一次后通过收集启动阶段的热点数据生成缓存文件,然后通过内存映射直接加载高效的缓存文件,从而获得100%到200%的用户代码冷启动优化效果提升。针对特定平台架构优化Node.js支持包括x64、arm64等多种架构,但针对ARM芯片的快速发展,上游版本往往只提供基础适配,缺乏针对新指令集的优化,导致无法获取ARM芯片的潜在性能改进。目前主流云厂商大多提供ARM架构和高性价比的运行环境。NoslateNode.js发行版针对ARM等平台的优化允许应用程序在这些架构上实现更高的性能和效率。目前,NoslateNode.js版本已经针对阿里云安培和阿里云倚天进行了定制和优化。未来的计划包括支持DragonLizard社区中的其他架构。主要包括:zlib的特性优化,以及其他一些使用SIMD的性能提升,都在PR的merge和calibration中。了解更多以上是对Noslate项目的简单介绍。如果你想了解更多,可以通过以下方法:GitHub:https://github.com/noslate-pr...网站:https://noslate.midwayjs.org/DragonLizardCommunitySIG(SpecialInterest集团、钉钉集团):https://openanolis.cn/sig/web...邮件列表:noslate-support@list.alibaba-inc.com致谢感谢阿里巴巴集团内的业务同时,我会感谢所有为本项目贡献代码,共同探索技术方向的伙伴(包括但不限于legendecas、mariodu、zhaolei0505、XadillaX、umuoy1、oraluben、hyj1991等)。
