6.3 Serverless与边缘函数


6.3 Serverless 与边缘函数

接口写好了,跑到哪去?本节讲 Nitro 的部署抽象落到函数形态:preset 怎么切、Serverless 与边缘各自的长短、冷启动怎么治、全局状态怎么办。它是第 9 章部署实践的先导课——那一章讲流程与平台选择,本节先把两种函数形态的机理说透。

一份代码,多种产物

Nitro 的 preset 是构建目标参数。默认 node-server 产出常驻进程,切到函数类 preset,产物变成平台要求的函数包:

# 构建 Serverless(AWS Lambda 形态) NITRO_PRESET=aws-lambda npm run build # 构建边缘(Cloudflare Workers 形态) NITRO_PRESET=cloudflare npm run build # 或写进配置固定
// nuxt.config.ts:固定预设 export default defineNuxtConfig({ nitro: { preset: 'cloudflare' }, })

构建日志会明确告知产物形态与启动方式。函数形态意味着:平台收到请求时冷启动一个实例执行你的代码,闲置后回收,下次请求再冷启——这与常驻 Node 进程"永远在场"是两种世界观。

图 6-2:三种运行形态对比

图 6-2:三种运行形态对比

冷启动:函数形态的主税

实例从零到能处理请求的耗时就是冷启动。构成:平台调度、代码加载、依赖初始化(数据库连接池、配置读取)。三味药:

药一:把初始化挪出处理器。模块顶层的代码每次冷启动执行一次,实例存续期间的请求复用它——数据库连接放模块顶层:

// server/api/db-example.get.ts // 模块顶层:每个实例只跑一次(冷启动时),热请求直接复用 const connection = createDbConnection({ url: process.env.DATABASE_URL, }) export default defineEventHandler(async () => { // 热路径:不重复建连接 return connection.query('SELECT 1') })

药二:减包体。依赖越多加载越慢,serverless 场景审视每个 server 端依赖,能删则删;重型 SDK 换轻量 REST 调用。

药三:预热。定时 ping 一个轻量端点让平台不回收实例(平台若有 provisioned concurrency 更好)。

边缘运行时的冷启动天然短(V8 隔离区启动远快于容器),代价是运行时受限:没有完整 Node API,依赖必须兼容 Web 标准(fetch、Streams),一些老库直接跑不起来——迁移前先过一遍依赖清单。

全局状态的正确姿势

函数形态下"实例随时销毁、数量随时增减",内存里的全局变量不可靠:不同实例各自一份(不共享),实例回收即丢失(不持久)。6.2 的 storage 在这里成为刚需:

// 计数器:函数形态下唯一可靠的写法是外置存储 export default defineEventHandler(async () => { const storage = useStorage() const count = (await storage.getItem('visits')) || 0 await storage.setItem('visits', count + 1) return { visits: count + 1 } })

多实例共享与持久化交给 storage 后端(函数平台配 Redis 或平台自带 KV)。第 4 章"绝不裸写模块级可变状态"的警告,在函数形态下从"污染风险"升级为"根本不工作"。

选型演练:三个真实场景

把本节的机制放进决策现场,练一遍"按出行需求选交通工具":

场景一:内部审批工具。公司两百人用,工作时段访问,晚间与周末几乎零流量,团队两人维护没空运维。答案指向 Serverless:弹性到零的成本结构(闲时不付费)、免运维、冷启动在内部工具场景可容忍(用户对首击多等半秒无感)。若已有 K8s 集群则常驻容器亦可,但那是为了复用现有运维体系,不是形态本身更优。

场景二:跨境电商主站。全球用户、流量大且平稳、SEO 是生命线。答案分层:静态资源与预渲染页上 CDN(全球边缘分发);动态页面跑多区域的 Node 集群(渲染稳定、接口低延迟);轻量的边缘函数做地理重定向与 A/B 分流(6.3 的边缘形态用在高频轻逻辑上)。混合形态是这个场景的正常形态。

场景三:个人作品集。十几个页面,月流量几千,预算趋近于零。纯静态(generate 产物)加免费静态托管,完事。任何动态能力都用不上——别为了"技术先进"给简历站配 Serverless。

三个场景的共性启示:形态选择的第一变量是流量模式与运维能力,而不是技术新旧。边缘很酷但重数据库的应用上不去;Serverless 省心但低延迟交易链路受不了冷启抖动。把 6-2 的对比图贴在选型会上,逐行过一遍,答案通常自己浮出来。

迁移演练:从常驻到函数

已有 Node 部署的项目迁 Serverless,按四步走可以少走弯路。第一步清点全局状态:grep 所有模块级变量,逐一判定"请求间是否需要共享"——需要的迁 storage,不需要的确认无副作用。第二步清点长连接:数据库连接池、消息队列订阅这类常驻连接,改为每次冷启建立或使用平台代理连接层。第三步灰度双跑:函数版本与常驻版本并行,按流量比例切流对比错误率与延迟。第四步回滚预案:保留常驻版本的部署脚本至少一个迭代周期,出问题五分钟切回。这套节奏同样适用于反向迁移(函数回常驻)——形态没有终局,业务变了就跟着变。

⚠️ 常见坑:在边缘运行时用了 Node 专属 API(fs、Buffer 的部分方法)导致部署失败。写可能上边缘的代码时优先 Web 标准 API;已有依赖查它的运行时支持矩阵再引入。

💡 关键直觉:Node 服务器像自家车位(车常驻、随时出发),Serverless 像网约车(叫车有等待、用完就走),边缘像共享单车(遍地都是、骑上就走但载重有限)。按出行频率和行李量选交通工具。

本节要点回顾

  • preset 即编译目标:同一份代码构建出常驻服务、Serverless 函数、边缘 worker 三种产物;
  • 三种形态对比:Node 无冷启要运维、Serverless 弹性省心付冷启税、边缘最近最快但 API 受限;
  • 冷启动三药:初始化上移到模块顶层、减依赖缩包体、预热或预置并发;
  • 全局状态不可靠:函数形态下内存变量既不共享也不持久,storage 与外部服务是唯一正解;
  • 边缘兼容性先查:依赖须兼容 Web 标准 API,Node 原生模块是雷区。

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U