我以为 Vercel 的后端和其他后端一样……

发布: (2026年1月10日 GMT+8 10:29)
6 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的文章正文内容,我将把它翻译成简体中文并保留原有的格式、Markdown 语法以及技术术语。谢谢!

关于 Vercel 与传统后端的经验教训

在通过项目深入学习 Next.js 的过程中,我尝试把我的 Next.js 后端服务器像普通的 Go 后端(依赖注入)那样进行架构设计。结果发现这是不可能的。把 Vercel 的 /api 路由当作“迷你 Express 服务器”是一种根本性的架构错误。虽然两者都运行 Node.js,但它们底层的基础设施(无服务器 vs. 长期运行)决定了完全不同的规则。

类似的服务还有 Netlify、Cloudflare Pages / Workers 和 AWS Amplify。


1. 进程生命周期:短暂 vs 持久

传统后端(长运行)

  • Concept: 进程启动后会一直保持存活,直到你手动停止它或它崩溃。
  • Global root: 永久存在;内存只分配一次,并在成千上万的请求之间保持可用。
  • Implication: 你可以依赖服务器在内部 RAM 中“记住”信息,持续数天或数周。

Vercel(无服务器)

  • Concept: 进程是 ephemeral(短暂的)。它在请求到达时创建,并在响应发送的那一毫秒被终止(或冻结)。
  • Global root: 经常被销毁。
  • Implication: 所有内部状态都会被清除。把每个请求都当作服务器刚刚进行冷启动来处理。

2. 状态管理:全局变量陷阱

传统后端(长时间运行)

  • 内存:全局变量是共享的。如果 用户 A 更新了全局计数器,用户 B 会看到更新后的值,因为他们命中的是同一个进程。
  • 垃圾回收:只要进程仍在运行,GC 会忽略全局变量,因为它们是可达的,这使得内存缓存或简单计数器成为可能。

Vercel(无服务器)

  • 内存:全局变量是隔离的。如果 10 位用户访问你的 API,Vercel 可能会启动 10 个独立的执行环境(实例)。
  • 陷阱用户 A 在实例 #1 中更新计数器。用户 B 访问实例 #2,后者拥有自己的全局根,计数器仍然是 0。
  • 注意:温暖实例可以在连续请求之间保留全局变量,但空闲实例会恢复为冷状态并丢失所有全局变量。
  • 解决方案:不要依赖内存中的数据来实现持久化。请使用外部存储,例如 Redis 或 PostgreSQL。

3. 并发:线程池 vs. 横向扩展

传统后端(长时间运行)

  • 机制:一个服务器使用单线程事件循环(Node.js)并管理连接池来处理多个并发请求。
  • 扩展:高流量会让服务器更忙;如果超负荷,请求会排队。

Vercel(无服务器)

  • 机制:Vercel 通过复制——在流量激增时生成大量函数实例来实现扩展。
  • 挑战:如果 1,000 个函数同时启动,每个函数可能会打开一个新的数据库连接,导致连接耗尽并使数据库崩溃。
  • 解决方案:使用连接池(例如 Prisma Accelerate 或 Supabase pooling)。

4. Execution Timing: Synchronous vs. Background Tasks

Traditional Backend (Long‑Running)

  • 您可以发送响应后继续在后台运行代码(例如 res.send(); fireAndForgetEmail();)。
  • 进程保持存活,使后台任务能够完成。

Vercel (Serverless)

  • Flow: 一旦调用 res.send(),运行时环境会被暂停或终止。
  • Disaster: 响应后启动的后台任务可能在执行中途被中断,导致工作不完整或缺失(例如,邮件只发送了一半)。
  • Solution: 在响应之前完成所有工作,或将长时间运行的任务委托给诸如 Upstash Workflow 的队列服务。

5. Persistent Connections: WebSockets vs. HTTP

Traditional Backend (Long‑Running)

  • Connectivity: 支持有状态连接。客户端可以保持 TCP 套接字打开(WebSockets),用于实时聊天或实时更新;服务器进程保持可用以维持另一端。

Vercel (Serverless)

  • Connectivity: 仅支持无状态 HTTP 请求。函数在返回响应后即结束,无法保持连接打开。
  • Result: 使用 socket.io 或类似库会失败,因为“服务器”在每次请求后都会消失。
  • Solution: 使用第三方实时即服务方案,例如 PusherAbly

This article was created with AI assistance as a personal note.

Back to Blog

相关文章

阅读更多 »

你好,我是新人。

嗨!我又回到 STEM 的领域了。我也喜欢学习能源系统、科学、技术、工程和数学。其中一个项目是…