跳至主要内容
Deno 2 终于来了 🎉️
了解更多
Deno helps Windmill.dev serve their enterprise clients.

Deno 中不可变脚本如何帮助 Windmill.dev (YC S22) 构建生产级运维

  • Ruben Fiszel

这是一篇由 Ruben FiszelWindmill.dev 创始人兼 CEO)撰写的客座博客文章。

Windmill.dev 是一个 开源开发者平台,公司可以在此构建内部工作流和 UI,这些工作流和 UI 来自脚本。包括 PhotoRoom 在内的 300 多家公司,包括像 PhotoRoom 这样的企业客户,都将 Windmill 作为生产基础设施的核心部分,用于各种操作,例如 ETL 管道、将内部和外部 API 拼接在一起等等。

由于公司依赖 Windmill 来处理由脚本组成的关键任务工作流,因此我们的技术必须具有高性能、安全性和灵活性。

  • 脚本的冷启动时间最短
  • 安全运行不受信任的任意代码
  • 一种简单的方式来共享和组合脚本

Windmill 可以运行 Python、Typescript、Bash 和 Go 代码。对于 TypeScript,我们选择了 Deno,因为它性能出色、安全可靠,并且能够创建自包含的脚本

脚本作为一等公民

由于其灵活性和可控性,脚本是构建工作流和 UI 的最小“单元”。Windmill 工作流由各种脚本组成。

A sample Windmill workflow composed of immutable Deno scripts

一个简单的单分支流的示例,该流在 HackerNews 消息包含提及且情绪分析完成时在 Slack 上发布。

上面的示例表明,工作流不仅由现成的脚本组成,还使用不同语言的脚本,这些脚本具有各种输入和资源。

由于脚本用于各种工作流,因此它们的共享性和一致性非常重要。此外,Windmill 是社区驱动的:脚本在 Hub 上共享,所有经过批准的脚本都集成到产品中。

有了这些要求,脚本必须可靠、安全和高效。只有 Deno 才能在一个中提供所有这些。

Deno 使脚本不可变

Windmill 要求每个脚本公开一个主函数并在同一个文件中声明其依赖项。主函数的参数被解析以推断触发此类脚本的有效负载的相应 JSON 模式。此模型非常适合 Deno。

Deno 的依赖项要求可以在使用它们的同一个文件中声明。此外,导入语句可以指定正在使用的精确版本,即使对于 npm 导入也是如此。

import mysql from "npm:mysql2@^2.3.3/promise";
import * as wmill from "https://deno.land/x/[email protected]/mod.ts";

当依赖项版本被指定时,我们可以保证脚本执行的可重复性,而与环境无关。最重要的是,共享 Deno 脚本就像共享单个文件一样简单——不需要单独的依赖项清单,例如 package.json。

一旦脚本被创建或更新,它的新版本就会与一个不可变且永久的哈希值关联,然后存储在 Postgres 中,并包含相关的元数据。

借助 Deno,Windmill 上的脚本是不可变的,并且是第一类原始类型——整个社区可共享的、可组合的构建块。

使用 Deno 安全运行任意代码

Windmill 在多租户环境中运行用户生成的代码,因此必须将每个脚本的执行隔离起来(对于自托管安装,为了方便起见,这些安全性可以被禁用)。Deno 的 选择性许可模型 使我们能够细化控制每次执行的访问权限。

对于 Windmill 中其他语言的脚本,沙盒化通过 NSJail 进行,这会产生很大的性能开销,并且使用和配置复杂。Deno 由于其默认安全的特性,在多租户环境下的性能方面具有优势

Deno 使冷启动时间最短

借助 Deno 与 V8依赖项的不可变缓存 的集成,我们已经能够实现 15 毫秒的冷启动时间。

缓存的依赖项还会通过一个由 S3 支持的同步系统传播到集群的各个工作程序,因此任何引用缓存依赖项的 Deno 脚本都不需要下载它,从而可以获得性能优势。

执行 Deno 脚本的冷启动时间大约为 15 毫秒,这意味着大多数轻量级脚本的端到端运行时间为 30 毫秒。

下一步是什么?

我们很高兴在 Windmill 的生产环境中使用 Deno——它简化了开发,添加了一层安全性,并确保了我们企业客户的最佳性能。

未来,我们旨在通过更深入地集成 Deno 并将其在进程中运行,以匹配无服务器/AWS Lambda 的性能。

不要错过更新——在 Twitter 上关注我们.