阿里巴巴 Noslate 正式开源 - 面向云原生的 JavaScript 容器方案

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 继 2019 年开源 Midway 框架之后,阿里一直在 Node.js 的前沿进行深度研究,除了加入 TC39 参与标准化建设,向上游 Node.js 项目持续贡献,与龙蜥社区合作优化之外,也在 Serverless 领域有了不小的成果。

今天,向大家介绍我们最新的面向云原生场景,面向 Serverless 架构下的新产品, 代号  Noslate。

Noslate 是什么?

欢迎访问项目了解更多内容:https://github.com/noslate-project/noslate

image.png

JavaScript 是开发者数量最庞大的编程语言,早些年 Node.js 等技术的出现,让 JavaScript 可以轻松地处理各类服务端任务。

但随着云原生/Serverless 等新架构概念的引导,弹性效率成为了全新的架构设计目标。为了能够让 JavaScript 任务拥有更高的弹性效率,进而满足在泛终端、全栈交付等领域的效率期待。我们逐步深入探索的过程中逐渐形成了 Noslate Project,旨在提升云原生场景下 JavaScript 的被调度性能,解决诊断性黑盒问题。

Noslate 它主要由三个子项目组成,分别体现了我们在提升 Javascript 任务弹性效率过程中碰到的问题以及解决方式:

  1. Node.js Distribution:初期针对函数计算冷启动场景优化,降低 Node.js 用户代码加载耗时,形成了针对性的 Node.js 发行版本。
  2. Noslate Workers:随着探索的深入,我们设计了面向轻量端云同构场景的 W3C Web-interoperable JavaScript 轻量化容器方案。在交付灵活度上和资源、执行效率上形成平衡,现在主要应用于中心化的 SSR 渲染等轻量任务场景,效果显著。
  3. Noslate Debugger:在落地业务过程中,我们发现在弹性效率提升后,对于异常和崩溃变得难以定位,得益于 Linux 系统 Coredump 机制的启发,我们设计了基于 Corefile 对问题进行离线诊断的 Noslate Debugger 产品,帮助用户实现问题的回溯和实时定位。

简而言之,Noslate 目标是通过提供完整的技术产品方案, 将 JavaScript 打造成云原生时代最灵活的交付语言。

为什么开源?

一方面我们希望通过开源加强项目产品化程度;另一方面希望在社区中吸收更多的实践场景进而继续完善产品设计,也欢迎大家参与到项目中来。

同时,依托阿里云龙蜥社区和 Anolis 操作系统的合作关系,我们得以在底层探索,实现技术的演进。

一、Noslate Workers

image.png

与传统的 FaaS 架构不同是,这是一个在普通应用容器之上的轻量任务单位。得益于良好的动态任务高密度混部和隔离特性、以及基于任务状态拷贝 API 带来的近乎 0 冷启动特性,可以实现任务的即用即启与即停即抛,进而无需关心在整个大集群中任务节点的编排问题。

与既有架构的关系:

image.png

Noslate Workers 由两个主要组件组成:

  1. Aworker - 轻量、Web-interoperable JavaScript Runtime
  2. Noslated - Servlerss 化的 Aworker 调度管控实现

关于 Aworker

提供 Web API 标准的 Web-interoperable JavaScript 运行时,适合不直接依赖系统接口的业务逻辑部署。Aworker 实现了近似 Service Worker API 的规范,提供了基本的 Request-Response 服务 API。

因为提供了相比于 Node.js 的 API 更加高层次、抽象的定义,不会泄漏系统底层状态,Aworker 通过 Startup Snapshot 和 Warmfork 能力, 实现了更快的水平及垂直扩容,能够在毫秒级启动并处理流量,具备更高的弹性效率。

亮点特性一:Warmfork

熟悉 Linux 系统编程的同学都知道 fork(2) 系统调用有几个优势:

  1. 新进程可以继承母进程的当前状态,而无需从 main() 开始初始化;
  2. pcb、栈、内存页,页表都是纯内存复制,所以进程创建快 (<1ms);
  3. CopyOnWrite,新进程可以继承母进程的静态页表,可节省系统内存;

对于 Node.js 来说,因为其无法在主线程持有所有多线程的状态 (如锁,信号量等),所以 Node.js 进行 fork 的修改难度很大。其多线程设计主要 来源于 libuv 库和 V8 Platform Worker 线程:

  1. 因部分 IO 操作存在同步调用,如 dns,文件读写等,所以 libuv 使用 IO 线程将同步操作转换成异步操作;
  2. Node.js 的 V8 默认配置为多线程 GC、Background Compilation/Optimization 的方式;

Node.js 的单进程多线程模型可以由下图表示:

image.png

Aworker 的设计是采用单进程单线程的模型,也就是将上述模型中的 worker thread 单独抽出放到一独立进程中。Worker 因此可支持 fork,从而避免从 main() 开始的启动消耗,达到快速启动的目的。

image.png

为了支持单线程,Aworker 还做了如下修改:

  1. 使用了 Linux AIO 特性替掉了 libuv 中同步的文件系统操作(不是 POSIX AIO,两者有区别。Posix AIO 类似于 libuv 现有的实现);
  2. 使用 V8 的 SingleThread 模式,这是一个给低端设备(Low-end devices)实现的能力,不过非常符合 Serverless 资源模型;

而为了管理、隔离这些工作进程,我们需要一个轻量的业务进程容器管理组件 Turf ,该组件用于能通过 Warmfork 方式创建新的 Aworker 服务进程,并能提供一定的资源、环境的隔离能力,同时兼容 OCI。区别于传统 runc, rund 的容器,turf 旨在承载如 Aworker 这类轻 JS Runtime,它无需镜像运行,开销更低,可以支持更高的部署密度。

Alinode Warmfork 具体的对比:

image.png

提供 "被复制" 的进程,称为 "种子进程",其他服务进程都是该进程的克隆。譬如 Aworker 作为种子进程,它需要确定自己一个 "可被克隆" 的时间点,将自己的所在状态(内存)作为克隆进程的初始状态。

Warmfork 的系统时序如下:

image.png

亮点特性二:Startup Snapshot

Warmfork 能解决了单机上服务进程的快速启动,对于冷机启动需要采用 Startup Snapshot 方案。Startup Snapshot 和 CodeCache 的区别在于 Startup Snapshot 能够保存用户代码逻辑执行状态,而 CodeCache 只保存代码解析结果、仍然需要重新执行 用户代码逻辑。

设计上,Startup Snapshot 可提供携带用户代码逻辑的快速恢复,但是也有局限性:

  1. Startup Snapshot 对内存开销敏感,如果应用启动阶段用了大量内存,可能造成负优化;
  2. 用户代码启动需要没有歧义的状态,比如 IP 地址、日期、连接状态、服务发现结果等,针对这些歧义内容用户代码需要在进程恢复时有修正能力;

V8 的 Startup Snapshot Serializer 就是一个类似于 GC 的对象遍历器。这个遍历器通过遍历加入到 Snapshot 中的 Root 对象,遍历它所对应的对象图并按照对象关系生成一系列的反序列化指令。

Startup Snapshot 相当于从 V8 Context 对象与它的 globalThis 开始,遍历堆中所有的对象并将对象关系与引用序列化成 特有的字节码,形成一个线性的可存储状态。并在恢复时,解释执行这些字节码,恢复堆中的对象内容与他们之间的引用关系。

image.png

上述的两类和被调度性能相关的特性被统一归类为状态拷贝 API,具体使用可以参考官网文档中的《状态拷贝 API》章节[1],详细介绍了命令行参数和程序内的 Events。https://noslate.midwayjs.org/docs/noslate_workers/aworker/serialize-api/

Noslated

Noslate Container Deamon,作为 Noslate Workers 解决方案的核心管控程序,提供了实例调度、弹性扩缩容、配置管理、流量管理等能力。

基于健壮性考虑,它由两个角色组成:控制面(Control Plane)、数据面(Data Plane)

image.png

Noslated 对于实例的管控主要有三个模式:

  1. 基础模式 - 基于流量的扩缩容
  2. 即抛模式 - 运行完即销毁
  3. 预留模式 - 面向历史场景兼容,在此不额外展开,详情可以查阅官网【预留策略】。

1、基础模式

当流量进入 Data Plane 后,如果没有能够处理请求的 Worker 实例,会通过 requestQueueing 事件通知 Control Plane,它会根据当前水位决定扩容数量,如果当前已无法创建 Worker 实例,会返回资源上限报错。新的 Worker 实例启动后,会自动连接到 Data Plane,Data Plane 发现新的 Worker 实例连接后会主动触发初始化请求,初始化成功后开始消费请求队列里堆积的请求。

当 Worker 实例闲置一段时间后,Control Plane 会主动发起 GC 操作,告知 Data Plane 关闭流量,流量关闭后,Control Plane 会通知 Turf 关闭 Worker 实例,清理资源残留。

image.png

2、即抛模式

针对特定的灵活场景,一次性的轻量用户脚本执行(比如特别高密度的混部执行二方任务如 SSR),为了隔离不同请求间的上下文,可以针对每个请求创建一个实例,并在执行后销毁。

image.png

比如普通的 Node.js 实例带上业务逻辑启动一般都不会太快,如果直接用了响应用户流量会难以接受。得益于 Aworker 运行时并配合 Warmfork [2]以及 Startup Snapshot [3]能力,更快完成 Worker 实例启动。亦可把一部分业务自己的初始化逻辑放置到 Warmfrok 特性中,进而让新实例都是最少的初始化时间,这才让高密度混部二方任务成为可能。

3、预留模式

在此不额外展开,详情可以查阅官网【预留策略】[4]

二、Noslate Debugger

image.png

Noslate Debugger 是针对 V8 应用的离线分析工具,它可以分析 Node.js 等应用程序产生的 Corefile (Core 文件):

  1. 检查 Node.js/V8 应用程序的结构体、堆栈等内容
  2. 检查 V8 堆内的各种对象信息
  3. 从 Corefile 中导出 Heap Snapshot
  4. 业务无感获取 Corefile (通过 Arthur 工具)
  5. 已支持 Node.js / AWorker LTS 官方发行版

为了更好的解决问题而不是造轮子,在未来的几个月 Noslate Debugger 也会和国内社区 Node.js 稳定性领域优秀的开源软件 Easy Monitor 共建整合,在 Node.js/V8 的问题诊断领域形成合力,也是值得期待的事情。

优点一:基于 Corefile 的 "快照" 更适应 Serverless

Serverless 应用通常会使用大量生命周期短、规格小的任务实例,但在此类任务实例上获得调试诊断能力并不容易,这使得 Serverless 应用长期处于较为黑盒的窘境。比如,Inspector 需要稳定和长时的网络连接、运行时 Heap Snapshot 需要较多的计算和内存资源,都是和 Serverless 架构背道而驰的。

不管是 V8 的对象还是堆快照,它都是 "信息" 在内存中的存储,而 Inspector 功能就是可以在 "运行时" 能提取这些信息。Noslate Debugger 通过 Corefile 将这部分调试诊断能力转移到了离线时进行,让原有实时性要求高的在线诊断调试转化为只需简单文件上传即可集成使用。

在用户本地或云端服务上提供接近用户本地开发时的调试诊断体感:

image.png

Corefile (特指 GNU Corefile 格式) 主要记录的是 Node.js 进程的内存和寄存器转储(CoreDump: 内存到磁盘的过程)。所以它也是进程完整“信息”,被用于 Linux 系统应用 Crash(有损) 的调试载体,也可用于 GCore(无损) 产生进程快照用于离线分析。

优点二:更小的业务影响

对比原有线上 "堆快照" 对业务的影响长达数分钟,到只影响业务 RT 秒级(通过 GCore),甚至只有几十毫秒 (通过 Arthur 工具)。Corefile 快照也不会有任何运行时的"添油加醋",所以它也适合那些还未被GC的对象定位,譬如诊断已经结束了的业务处理等。

Arthur 是 Noslate Debugger 中用于低影响获取 core文件的工具,利用 fork 减少进程暂停时间,LZ4 压缩减少转储体积。带业务流量的线上环境抓取,业务影响 31.106 毫秒,Corefile 大小为 338 MB (进程原使用 1.44GB 物理内存)。

三、Node.js 发行版

image.png

我们还对 Node.js 的实例进行了定向弹性场景的优化,提高了用户代码的加载速度,从而降低了冷启动时间。主要包括 Require 关系加速、Bytecode Cache,优化效果提升可高达 100% ~ 200%。该发行版,同时包含来自阿里云基础软件团队在 ARM 架构的性能优化特性。

冷启动优化

PGO(Profile Guided Optimization),是一种根据运行时 Profiling Data 来进行编译优化的技术,这里我们借鉴了这一概念。主要是通过执行一遍之后收集启动阶段的热点数据生成缓存文件,后续通过内存映射直接加载高效的缓存文件,即可获得提升在 100% ~ 200% 的用户代码冷启动优化效果。

image.png

面向特定平台架构优化

Node.js 支持包括 x64、arm64 等在内的多种架构。但针对 ARM 芯片的快速发展,上游版本往往仅提供基础适配,缺少针对新指令集的优化,导致在 ARM 芯片上无法获得潜在的性能提升。当下主流云厂商大都提供了 ARM 架构、高性价比的运行环境。Noslate Node.js 发行版针对 ARM 等平台的优化可以让应用在这些架构上获得更高的性能和效率。目前 Noslate Node.js 发行版已经在进行针对阿里云 Ampere、阿里云倚天的定制优化,未来计划包括支持龙蜥社区中的其他架构。主要包括:zlib 特性优化、其他一些利用 SIMD 的性能提升都在 PR 合并和准别中。

详细了解

上面是对 Noslate Project 的简单介绍,如果想要详细了解可通过下述方式:

致谢

感谢阿里巴巴集团内业务方的支持,同时还要特别感谢所有给本项目贡献过代码、一起探索过技术方向伙伴们(包括不限于 legendecas、mariodu、zhaolei0505、XadillaX、umuoy1、oraluben、hyj1991 等)。

相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
相关文章
|
3天前
|
Kubernetes Cloud Native Docker
云原生时代的容器化实践:Docker和Kubernetes入门
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术成为企业提升敏捷性和效率的关键。本篇文章将引导读者了解如何利用Docker进行容器化打包及部署,以及Kubernetes集群管理的基础操作,帮助初学者快速入门云原生的世界。通过实际案例分析,我们将深入探讨这些技术在现代IT架构中的应用与影响。
12 2
|
3天前
|
运维 Kubernetes Cloud Native
云原生技术:容器化与微服务架构的完美结合
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术以其灵活性和高效性成为企业的新宠。本文将深入探讨云原生的核心概念,包括容器化技术和微服务架构,以及它们如何共同推动现代应用的发展。我们将通过实际代码示例,展示如何在Kubernetes集群上部署一个简单的微服务,揭示云原生技术的强大能力和未来潜力。
|
1天前
|
运维 Cloud Native 虚拟化
一文吃透云原生 Docker 容器,建议收藏!
本文深入解析云原生Docker容器技术,涵盖容器与Docker的概念、优势、架构设计及应用场景等,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
一文吃透云原生 Docker 容器,建议收藏!
|
2天前
|
Cloud Native API 持续交付
云原生之旅:从容器到微服务的演进之路
【10月更文挑战第39天】在这篇文章中,我们将一起探索云原生技术的奥秘。通过浅显易懂的语言和生动的比喻,我们将了解云原生技术如何改变软件开发的世界。文章将带领读者从容器的基本概念出发,逐步深入到微服务架构的实践,揭示这些技术如何助力现代应用的快速迭代与可靠部署。准备好,让我们启程进入云原生的精彩世界吧!
|
4天前
|
Kubernetes Cloud Native Docker
云原生技术探索:容器化与微服务的实践之道
【10月更文挑战第36天】在云计算的浪潮中,云原生技术以其高效、灵活和可靠的特性成为企业数字化转型的重要推手。本文将深入探讨云原生的两大核心概念——容器化与微服务架构,并通过实际代码示例,揭示如何通过Docker和Kubernetes实现服务的快速部署和管理。我们将从基础概念入手,逐步引导读者理解并实践云原生技术,最终掌握如何构建和维护一个高效、可扩展的云原生应用。
|
12天前
|
Kubernetes Cloud Native 微服务
云原生之旅:从容器到微服务
【10月更文挑战第29天】在这篇文章中,我们将一起探索云原生的奥秘。云原生不仅仅是一种技术,更是一种文化和方法论。我们将从容器技术开始,逐步深入到微服务架构,最后探讨如何在云平台上实现高效的服务部署和管理。无论你是初学者还是有经验的开发者,这篇文章都将为你提供有价值的见解和实用的技能。让我们一起踏上这段激动人心的云原生之旅吧!
|
12天前
|
运维 Kubernetes Cloud Native
云原生之旅:容器化与微服务的融合
【10月更文挑战第28天】 在数字化转型的浪潮中,云原生技术如星辰般璀璨,引领着企业IT架构的未来。本文将带你穿梭于云原生的世界,探索容器化技术和微服务架构如何携手共舞,打造灵活、高效的应用部署和运维模式。我们将通过实际代码示例,揭示这股力量背后的奥秘,并展现它们是如何为现代软件开发带来革新。准备好了吗?让我们启航,驶向云原生技术的深海。
|
13天前
|
Kubernetes 负载均衡 Cloud Native
云原生应用:Kubernetes在容器编排中的实践与挑战
【10月更文挑战第27天】Kubernetes(简称K8s)是云原生应用的核心容器编排平台,提供自动化、扩展和管理容器化应用的能力。本文介绍Kubernetes的基本概念、安装配置、核心组件(如Pod和Deployment)、服务发现与负载均衡、网络配置及安全性挑战,帮助读者理解和实践Kubernetes在容器编排中的应用。
43 4
|
12天前
|
Cloud Native 持续交付 云计算
云原生入门指南:从容器到微服务
【10月更文挑战第28天】在数字化转型的浪潮中,云原生技术成为推动现代软件开发的关键力量。本篇文章将带你了解云原生的基本概念,探索它如何通过容器化、微服务架构以及持续集成和持续部署(CI/CD)的实践来提升应用的可伸缩性、灵活性和可靠性。你将学习到如何利用这些技术构建和部署在云端高效运行的应用,并理解它们对DevOps文化的贡献。
33 2
|
14天前
|
Kubernetes 监控 Cloud Native
云原生应用:Kubernetes在容器编排中的实践与挑战
【10月更文挑战第26天】随着云计算技术的发展,容器化成为现代应用部署的核心趋势。Kubernetes(K8s)作为容器编排领域的佼佼者,以其强大的可扩展性和自动化能力,为开发者提供了高效管理和部署容器化应用的平台。本文将详细介绍Kubernetes的基本概念、核心组件、实践过程及面临的挑战,帮助读者更好地理解和应用这一技术。
46 3