每天约十亿次边缘函数(Edge Functions)在 Netlify(Netlify)上运行,Sunweb(Sunweb)个性化页面,Loto-Québec(Loto-Québec)借 cookie 检查路由流量,数十万网站做个性化、路由与认证。全部基于随客户流量扩展的完整 JavaScript 运行时。为尽可能降低延迟,每秒数十至数十万次函数需在毫秒内完成请求处理、路由、算力分配及代码启动。过去数月团队与 Unikraft(Unikraft)重建设施,使函数在自有边缘网络的微虚拟机(MicroVMs)运行,中位数快约5倍。
正文
Netlify 每天运行约十亿次边缘函数,例如 Sunweb 做页面个性化,Loto-Québec 根据 cookie 检查路由流量,还有数十万站点用于个性化、路由或鉴权等。这些都运行在完整的 JavaScript 运行时上,随客户流量伸缩。
要让延迟尽可能低是个技术挑战。每秒要处理数万甚至数十万次边缘函数,需对每个请求处理、正确路由、分配算力,并启动平台代码和客户代码,全部要在毫秒内完成。
过去几个月,我们团队与 Unikraft 合作重建了边缘函数底层设施。以前请求发往托管执行服务,现在跑在自己边缘网络内的 MicroVM 上,中位数快约 5 倍。这还提升了安全性和可靠性,也为边缘复杂计算带来更多可能。
边缘函数的编写和使用方式不变——URL 导入、npm 包、Node 内置模块、netlify.toml 声明、本地开发都和以前一样,只是更快更健壮。接下来分享新架构及构建低开销高并发计算平台的经验。
数字先行
边缘函数在站点前运行,匹配到的每个请求都会触发。耗时即用户等待时间,所以这里的毫秒比几乎其他地方都重要。
热调用——路由到计算节点、进入 MicroVM、运行函数、生成响应头——现在耗时:
- 中位数(p50)约 5–6 毫秒,之前为 25–40 毫秒
- p99 调用快 47.4%
- 可用性 99.998%
- 边缘函数日志投递快 5 倍
冷启动也值得一提:请求到达某区域且计算节点从未见过时,需先拉取相关镜像才能运行。这发生在约 1.2% 的调用中,平均耗时约 9 毫秒。
请求期间发生了什么
单个请求的路径依次如下:到达边缘节点,转为规格说明,路由到计算节点,再交给 MicroVM(冷或热启动决定其是否已存在)。
请求到达边缘节点
每个请求落在离客户端最近的 Netlify 边缘节点,节点终止 TLS 连接,并按该部署的边缘函数路由检查请求路径。
若无匹配,请求照常去缓存和源站。若匹配,旧架构下请求会离开我们的网络,经互联网执行函数再返回;新平台则转发到网内计算节点。
创建边缘函数服务
计算节点收到带机器规格和服务 ID 的请求后,先查该 ID 的服务是否存在。存在则转发给服务进而送入 MicroVM。服务让同一站点的边缘函数关联多个 MicroVM,并可配置伸缩参数。例如,每个服务只允许 MicroVM 处理固定数量请求后关闭,避免无限运行;据此也可预判关闭而提前启动新 MicroVM。
若不存在则创建服务,并检查磁盘是否有规格中的全部镜像。缺失则从边缘节点拉取写入。这样只拉取该区域有流量的边缘函数镜像。
边缘节点编写规格
请求发出前,边缘节点先写运行函数的机器规格,指定三个镜像:运行时、平台镜像、边缘函数镜像,并设置 CPU、内存和连接限制。
规格随每个请求传送。其哈希和站点信息算出服务 ID,从而实现隔离:代码或环境变量不同的两次部署是不同服务,从不共享 MicroVM。
隔离对防范故障至关重要。可能受损的部署跑在独立 MicroVM,即使逃逸运行时也无法毒害其他客户或计算层。V8 isolates 无论名称如何,都无此隔离级别。
选择运行边缘函数的计算节点
每个区域有一组计算节点。边缘节点用 rendezvous hashing 为服务选节点:同服务总落同节点,保持 MicroVM 热启动且代码已缓存。这种粘性即缓存策略,若均匀分散反而冷启动更多。
但需注意,全发同节点虽快,却易成热点:繁忙函数与同机其他资源竞争。若某服务占区域大量流量并钉在单节点,会撑饱和该节点而损及他服务。
我们放宽粘性来平衡:超阈值后把服务分散到部分节点,可吸收单客户突增流量而不影响同哈希其他服务。
节点选定后拉取函数代码。曾服务过的节点已有代码;首次见的节点拉一次并缓存,仅首请求付此成本。
启动 MicroVM
每个函数跑在自己的 Firecracker MicroVM 中,创建不到 1 毫秒,p99 启动约 2 毫秒,因它启动精简 Linux 而非完整 OS。边缘函数文件挂载为未压缩 EROFS 镜像并内存映射,VM 只读所需部分而非全载。
MicroVM 启动且 JS 服务器监听端口时,我们做快照。函数不调用时 MicroVM 缩容到零而非空转。下次调用从快照起新 VM,快照内存映射,故 VM 无需等全部读回内存即可执行。
VM 的生命周期(启动、快照、恢复、缩容到零)由 Unikraft 产品实现。迁移中我们紧密合作确保其承受我们的请求量与模式。
运行与响应处理
项目运行数年后,我们融入了提升性能和调试经验的收获。大规模下遇过各类问题,从虚拟交换机端口耗尽到 DNS(出人意料,但不总是 DNS 的错)。
此次迭代确保计算节点跑本地 DNS 解析器,并扩展指标收集,如启动时间、首端口开放时间、用户代码启动时间。还设多个断路器以及时重路由和停用节点。
整条路径在热实例上增约 6 毫秒,全程不出网,我们控制整个请求周期,上述皆在请求到达与响应返回之间。
设计弹性计算设施
构建上述系统需同时优化终端用户体验和部署弹性,既要快速推出变更,也要能同样快速回滚。
计算节点基于 Unikraft 发布的底包并装一组软件。与边缘节点分离构建,因可保持边缘节点轻快、计算节点用不同实例类型、且独立伸缩。
控制面记录计算节点存在与健康状态,边缘节点轮询获取。部署时新集群与旧并行,伸缩匹配后仅健康才接管流量。
构建计算设施需与 Unikraft 紧密合作,迁移中共同测试正确性、处理大请求量、建平台专属能力。
已上线
重建边缘计算架构不仅是提速,更是可控且能持续构建的更快基座。最佳处是现已以同价服务生产流量,无需迁移,项目零改动。
自有计算意味着边缘函数的上限由我们提升。此前做不到的三件事现在可行:
- npm 包支持走出测试期。 目前边缘函数已支持 npm 包(测试版),但对原生二进制和运行时导入文件有限制。真实 VM 加真实文件系统消除了多数限制原因。
- 有机会重审运行限制。 文档限每请求 CPU 50ms、内存 512MB、压缩代码 20MB,这些源自 isolate 模型。
- 自有网络内计算。 任何依赖控制网络路径而非跨互联网找第三方的能力,现在可构建。
评论
讨论整体对 Netlify 拿 v8 isolate 对比 microVM、并宣称中位数快 5 倍的说法持怀疑态度:多数人质疑 25–40ms 这个延迟数据本身和对比口径,同时普遍认可 Firecracker/microVM 的技术价值;少数人为 microVM 在边缘计算的组合辩护,并强调 v8 isolate 仍有不可替代的场景。
质疑 25–40ms 的 v8 isolate 延迟数据
- 同为 v8 isolate 的 Cloudflare Workers 跑得远快于这个数字,说明瓶颈可能在 Netlify 自己的实现或链路上,而非 isolate 模型本身(较多人) > 同样是 v8 isolate,Cloudflare Workers 比 Netlify 说的 25–40 毫秒快得多,我很难相信这个数据。(@nchmy)
- 文章没有交代延迟究竟来自 isolate 启动、运行时初始化还是别处,读者希望看到拆解(较多人)
- 也有人反问:既然毫秒级延迟这么关键,为什么还要选 JavaScript(少数人)
「快 5 倍」可能只是省掉了网络跳数
- 原文说过去请求发往托管执行服务,现在跑在自己的边缘网络,这只能证明去掉了网络往返,不能证明执行本身变快了,对比有误导之嫌(较多人) > 执行本身可能反而更慢,他们只是把中间的网络环节去掉了,这个说法有误导性。(@yencabulator)
从快照恢复 microVM 会复制随机数状态,风险被低估
- 在 JavaScript 服务开始监听端口时拍快照、再从快照启动新实例,会让多个实例共享同一 RNG 状态,UUID 生成和加密场景可能出灾难性故障(少数人) > 从快照 fork 出来的随机数状态一旦重复,UUID 生成器和加密都可能出大问题。(@CodesInChaos)
Firecracker 本身是行业级基础设施,值得肯定
- Firecracker 是最优秀的 microVM 技术之一,也是不少非 AWS 产品的底座,Netlify 只是最新的采用者(较多人) > 下次想骂 AWS 时记得,他们贡献了 Firecracker,这是目前最好的 microVM 技术之一。(@jedberg)
- 反直觉的是,microVM 概念本就是 AWS 为 Lambda 提出的,但 Node 在 Lambda 上延迟和吞吐都很差;发帖者认为鉴权校验、规则检查等场景与 Netlify 高度相似,这套技术本可帮上忙(较多人)
v8 isolate 在边缘函数场景不会被 microVM 取代
- 中型公司更受益于 isolate:JS/TS 可被较好地静态分析,安全历史和漏洞可追溯;microVM 更灵活,但要达到同等封闭性需要做大量额外锁定。文章的场景是租用别人的 isolate,多了几跳,并不具普遍代表性(少数人) > Firecracker 未来可能取代 Docker,但替代不了大多数边缘函数里的 v8 isolate。(@Normal_gaussian)
有价值的补充
- Unikraft 的 Alex 在帖中现身,表示愿意回答 microVM 部分的问题,并给出两篇相关技术写作,为讨论提供了第一手工程视角(@nderjung)。
- 有用户长期用 SlicerVM 在本机运行本地「边缘」负载,包括 Agent 和本地开发 CI,用它替换了 Proxmox 虚拟机编排;它支持 Dockerfile 风格构建,可作为从容器升级到安全隔离的路径(@Normal_gaussian)。
- 讨论中反复出现的实用判断:Firecracker 替代 Docker 与替代 v8 isolate 是两条不同的路线,前者看隔离与打包,后者看静态可分析性与启动开销。