ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Cloudflare Workers 边缘计算实战:从零搭建 AI 应用后端

Cloudflare Workers 边缘计算实战:从零搭建 AI 应用后端

1. 从“cloudflare-os”这个标题说起:它到底是什么

第一次看到“cloudflare-os”这个词,很多人会误以为 Cloudflare 出了一款操作系统。其实不是。它更像是一个概念性的项目代号,指的是把 Cloudflare 的边缘计算能力(Workers、Pages、KV、D1、R2、Durable Objects 等)当作一套“操作系统”来用,在上面搭建完整的应用后端、AI 服务编排层、甚至前端托管。你可以把它理解成:把 Cloudflare 的全球边缘网络当成一台虚拟的、分布式的“电脑”,而 Workers 就是这台电脑上的进程调度器。

这个项目标题背后真正吸引人的点在于:它把过去需要自己买服务器、配 Nginx、装 Node、跑 Docker 的一整套流程,压缩成了“写一个 Worker 脚本 + 一条 wrangler 命令”。对于独立开发者、小团队、做 AI 应用原型的人来说,这种模式几乎是降维打击。你不需要关心机房在哪、不需要关心扩容、不需要关心证书续期,Cloudflare 帮你把这些全部吃掉。

那它适合谁?三类人最值得关注:第一类是前端转全栈的开发者,想给自己的项目加后端但不想碰运维;第二类是做 AI Agent、AI 聊天、AI 工具站的独立开发者,需要低成本、低延迟、全球可访问的部署方案;第三类是想学习边缘计算架构的技术爱好者,想搞清楚 Serverless 到底是怎么跑起来的。这篇文章我会从架构思路、核心组件、实操流程、踩坑经验四个维度,把这个“cloudflare-os”式的玩法讲透。

2. 为什么用 Cloudflare 这套东西当“操作系统”

2.1 传统部署方式的痛点在哪里

先说说为什么会有这个思路。假设你要做一个 AI 聊天应用,传统做法是什么?买一台云服务器,装 Ubuntu,配 Node 环境,装 pnpm,跑一个 Express 或者 Fastify 服务,前面挂 Nginx 做反向代理,申请 SSL 证书,配防火墙,然后还要考虑日志、监控、扩容。这一套下来,光是环境搭建就能耗掉一整天,而且每个月固定支出至少几十块,流量一大还得升级配置。

更麻烦的是冷启动和延迟。你的服务器如果放在某个区域,欧洲用户访问就要绕半个地球,延迟轻松上 200ms。想解决?那就多区域部署,成本翻倍,运维复杂度指数级上升。对于个人开发者来说,这几乎是不可能完成的任务。

Cloudflare 的 Workers 恰好把这些问题全部抹平了。它的运行时分布在全球数百个节点,用户请求会被自动路由到最近的节点执行。你写一份代码,全球生效。计费按请求数算,免费额度每天 10 万次请求,对绝大多数个人项目来说完全够用。

2.2 Workers 作为“内核”的核心能力

把 Workers 比作操作系统内核,是因为它提供了几个关键能力。第一是请求调度,每个 fetch 事件就像一次系统调用,你可以在里面做路由、鉴权、数据处理。第二是状态管理,KV 相当于文件系统(最终一致),D1 相当于内置数据库(SQLite),Durable Objects 相当于带锁的共享内存,R2 相当于对象存储。第三是进程间通信,Service Bindings 让不同的 Worker 之间可以像调用函数一样互相调用,不需要走公网。

这套组合下来,你实际上拥有了一个完整的应用运行环境。我试过用纯 Workers + D1 + R2 搭一个带用户系统的 AI 对话应用,从零到上线只用了两天,其中大部分时间还是在调 UI。后端代码加起来不到 500 行,没有一行是运维配置。

2.3 和传统 Serverless 的区别

有人会问,这不就是 Serverless 吗?AWS Lambda 也能做啊。区别在于冷启动和运行时限制。Lambda 的冷启动动辄几百毫秒甚至几秒,而 Workers 用的是 V8 Isolate 技术,冷启动基本在 5ms 以内,几乎无感。另外 Workers 支持 Web Standard API(Request、Response、fetch、crypto),写起来跟写浏览器代码很像,学习成本极低。

还有一个关键差异是边缘计算的位置。Lambda 虽然也有边缘版本,但生态和易用性远不如 Workers。Cloudflare 把 wrangler 这个 CLI 工具做得非常顺手,本地开发、预览、部署一条龙,体验接近 Vercel 但更底层、更灵活。

3. 核心组件拆解:这套“OS”里都有什么

3.1 Workers:你的主进程

Workers 是整个架构的核心。一个 Worker 就是一个 JavaScript 或 TypeScript 模块,导出一个 fetch 处理函数。你可以把它当成一个永远在线的 HTTP 服务,但它没有端口、没有进程、没有服务器。代码长这样:

export default { async fetch(request, env, ctx) { const url = new URL(request.url); if (url.pathname === '/api/chat') { return new Response(JSON.stringify({ msg: 'hello' }), { headers: { 'Content-Type': 'application/json' } }); } return new Response('Not Found', { status: 404 }); } }

就这么简单。env 参数里可以拿到你绑定的 KV、D1、R2 等资源,ctx 里有 waitUntil 用来做后台任务。注意:Workers 有 CPU 时间限制,免费版每次请求最多 10ms CPU 时间,付费版 30ms(可配置到更高)。这个限制指的是实际计算时间,不包括等待网络 IO 的时间,所以做 API 代理、AI 转发这类场景完全没问题。

3.2 KV、D1、R2:存储三件套

KV是键值存储,适合存配置、会话、缓存。它的特点是读取极快(边缘缓存),但写入有延迟(最终一致,通常几秒到几十秒全球同步)。我用它存过 API 密钥、用户偏好设置,效果很好。但千万别用它做需要强一致性的场景,比如库存扣减。

D1是 Cloudflare 的 SQLite 数据库,2024 年正式 GA。它支持标准 SQL,可以通过 wrangler 在本地跑迁移。适合中小规模的关系型数据,比如用户表、订单表。我实测下来,单表百万级数据查询在几十毫秒内,对个人项目绰绰有余。注意:D1 目前有单库大小限制(付费版 10GB),超大表要考虑分库或者用其他方案。

R2是对象存储,兼容 S3 API,但出口流量免费。这一点非常关键。如果你用 S3 存图片、视频,流量费能吓死人,R2 直接免掉。我把自己项目的所有静态资源都迁到了 R2,配合 Workers 做鉴权代理,成本几乎为零。

3.3 Durable Objects:带状态的协调者

Durable Objects 是这套架构里最容易被忽略但最强大的部分。它提供了一个单点、有状态、强一致的对象,可以用来做聊天室、协作编辑、游戏房间、限流器。每个 DO 实例在全球只有一个,所有请求都会路由到同一个实例,所以状态是强一致的。

举个例子,你要做一个多 AI 协作的应用,多个 AI Agent 需要共享上下文。用 DO 就很合适:每个会话创建一个 DO 实例,所有 Agent 的读写都走这个实例,天然避免了并发冲突。注意:DO 的计费是按请求数和持续时间算的,长时间保持连接(比如 WebSocket)会产生持续费用,要合理设计生命周期。

3.4 wrangler 和 pnpm:你的工具链

wrangler 是 Cloudflare 官方 CLI,相当于这套“OS”的包管理器和部署工具。pnpm 则是 Node 生态里越来越主流的包管理器,速度快、磁盘占用小。两者配合使用是当前最舒服的组合。

安装流程很简单:

# 安装 pnpm(如果还没装) npm install -g pnpm # 创建项目 pnpm create cloudflare@latest my-app # 进入目录 cd my-app # 本地开发 pnpm run dev # 部署 pnpm run deploy

但这里有个高频坑:pnpm 命令找不到。Windows 上经常报pnpm : 无法将“pnpm”项识别为 cmdlet,Mac 上偶尔报pnpm: command not found。原因通常是 npm 全局 bin 目录没加到 PATH 里。解决办法是先npm config get prefix看路径,然后手动加到环境变量。或者更省事,直接用npx pnpm代替。Ubuntu 上如果遇到权限问题,建议用 corepack 启用:corepack enable pnpm。

4. 从零搭一个 AI 应用后端:完整实操

4.1 项目初始化和依赖选择

假设我们要做一个 AI 聊天应用的后端,支持多轮对话、历史记录、多模型切换。先初始化项目:

pnpm create cloudflare@latest ai-chat-backend --type=hello-world --ts cd ai-chat-backend pnpm add hono zod

为什么选 Hono?因为它是专为边缘运行时设计的 Web 框架,体积小、速度快、TypeScript 支持好,比 Express 更适合 Workers 环境。zod 用来做请求参数校验,避免脏数据进数据库。

项目结构建议这样组织:

src/ index.ts # 入口,路由注册 routes/ chat.ts # 聊天相关接口 user.ts # 用户相关接口 db/ schema.ts # D1 表结构 queries.ts # 查询封装 utils/ auth.ts # 鉴权 ai.ts # AI 调用封装 wrangler.toml # 配置文件

4.2 wrangler.toml 配置详解

wrangler.toml 是整套系统的配置文件,相当于操作系统的 config。一个典型的配置长这样:

name = "ai-chat-backend" main = "src/index.ts" compatibility_date = "2024-09-23" [[d1_databases]] binding = "DB" database_name = "ai-chat-db" database_id = "your-database-id" [[kv_namespaces]] binding = "KV" id = "your-kv-id" [[r2_buckets]] binding = "BUCKET" bucket_name = "ai-chat-assets" [vars] ENVIRONMENT = "production"

注意:database_id 和 kv id 需要你先用wrangler d1 create和wrangler kv:namespace create创建后拿到。vars 里不要放密钥,密钥要用wrangler secret put命令单独设置,这样不会进代码仓库。

4.3 D1 数据库设计和迁移

D1 的迁移文件放在 migrations 目录下,命名格式是0001_init.sql。一个聊天应用的核心表:

CREATE TABLE users ( id TEXT PRIMARY KEY, email TEXT UNIQUE NOT NULL, created_at INTEGER DEFAULT (unixepoch()) ); CREATE TABLE conversations ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, title TEXT, model TEXT DEFAULT 'default', created_at INTEGER DEFAULT (unixepoch()) ); CREATE TABLE messages ( id TEXT PRIMARY KEY, conversation_id TEXT NOT NULL, role TEXT NOT NULL, content TEXT NOT NULL, created_at INTEGER DEFAULT (unixepoch()) ); CREATE INDEX idx_messages_conv ON messages(conversation_id, created_at);

执行迁移:wrangler d1 migrations apply ai-chat-db。本地开发时加--local参数,数据存在本地 .wrangler 目录,不会污染线上。

实操心得:D1 的 unixepoch() 函数返回秒级时间戳,前端展示时要乘 1000。另外索引一定要建,我一开始没建 idx_messages_conv,查询历史消息时全表扫描,数据到几万条就明显卡了。

4.4 AI 调用层的封装

AI 调用是这类应用的核心。建议单独封装一个模块,方便切换模型和加缓存:

export async function callAI(env: Env, messages: Message[], model: string) { const cacheKey = `ai:${model}:${hashMessages(messages)}`; const cached = await env.KV.get(cacheKey); if (cached) return JSON.parse(cached); const response = await fetch('https://api.example-ai.com/v1/chat', { method: 'POST', headers: { 'Authorization': `Bearer ${env.AI_API_KEY}`, 'Content-Type': 'application/json' }, body: JSON.stringify({ model, messages }) }); const data = await response.json(); await env.KV.put(cacheKey, JSON.stringify(data), { expirationTtl: 3600 }); return data; }

这里用 KV 做了一层缓存,相同的问题在 1 小时内直接返回缓存结果,既省钱又快。注意:缓存 key 要用消息内容的哈希,不能只用最后一条,否则多轮对话会串。另外流式响应(SSE)没法缓存,要单独处理。

4.5 部署和自定义域名

部署就一条命令:pnpm run deploy。wrangler 会自动打包、上传、发布,通常 10 秒内完成。之后你可以在 Cloudflare 控制台绑定自定义域名,证书自动签发,不需要任何配置。

如果想做灰度发布,可以用wrangler versions upload先上传一个版本,然后在控制台按比例分流。这个功能对做 A/B 测试很有用。

5. 常见问题与排查技巧实录

5.1 pnpm 相关的各种报错

这是最高频的问题,我整理了一个速查表:

报错信息原因解决方案
pnpm 不是内部或外部命令PATH 未配置把 npm 全局 bin 目录加到 PATH
pnpm 无法将“pnpm”项识别PowerShell 执行策略用 cmd 或改执行策略
pnpm install 卡住网络源问题切换 registry 或配代理镜像
pnpm 离线安装失败缓存不完整用 pnpm fetch 先拉全量
删除 pnpm 后命令还在残留 shim手动删 npm 目录下的 pnpm 文件

Ubuntu 上安装 pnpm 推荐用 corepack:corepack enable && corepack prepare pnpm@latest --activate。这样版本管理更干净,不会和 npm 全局包冲突。

5.2 Workers 运行时的坑

坑一:Node API 不可用。Workers 用的是 Web Standard API,没有 fs、path、process 这些 Node 模块。如果你依赖的库用了这些,要么找替代品,要么用 nodejs_compat 兼容标志(在 wrangler.toml 里加compatibility_flags = ["nodejs_compat"])。

坑二:CPU 时间超限。免费版 10ms 很容易超,尤其是做加密、大量 JSON 解析的时候。解决办法是把重计算拆到多个请求,或者升级付费版。我做过一个图片处理的功能,免费版直接跑不动,后来改成客户端处理才解决。

坑三:环境变量读取。本地开发时 .dev.vars 文件里的变量不会自动加载到 process.env,要通过 env 参数拿。这个和传统 Node 习惯不一样,容易踩。

5.3 D1 查询性能优化

D1 底层是 SQLite,单条查询很快,但批量操作要注意。我试过循环插入 1000 条数据,每次都 await,结果超时了。正确做法是用 batch:

const stmt = env.DB.prepare('INSERT INTO messages (id, content) VALUES (?, ?)'); const batch = messages.map(m => stmt.bind(m.id, m.content)); await env.DB.batch(batch);

这样一次网络往返搞定,速度快几十倍。另外查询时尽量只 select 需要的字段,避免SELECT *,减少数据传输。

5.4 多 AI 协作场景的特殊处理

如果你要做多 AI 协作(比如让几个不同模型互相讨论),Durable Objects 是首选。但要注意并发控制。多个 Agent 同时写同一个 DO 时,要用事务或者队列串行化。我的做法是每个会话一个 DO,内部维护一个消息队列,Agent 的回复按顺序追加,避免上下文错乱。

还有一个经验:给每个 AI 调用设超时。不同模型的响应时间差异很大,有的 2 秒有的 30 秒。用 Promise.race 加超时兜底,避免一个慢请求拖垮整个会话。

6. 成本控制和扩展思路

6.1 免费额度到底够不够用

Cloudflare 的免费额度相当慷慨:Workers 每天 10 万请求,KV 每天 10 万读 1000 写,D1 每天 500 万行读 10 万行写,R2 每月 100 万次操作。对个人项目和早期产品来说,基本不用花钱。我自己的一个 AI 工具站,日活几百,跑了大半年没产生任何费用。

真正会产生费用的是AI API 调用,那是另一回事。Cloudflare 自己也提供 Workers AI,按 neuron 计费,小模型很便宜,可以作为备选。

6.2 什么时候该考虑升级

三个信号说明你该升级付费版了:第一,每天请求超过 10 万;第二,CPU 时间经常超 10ms;第三,需要用到 Durable Objects 的长时间连接。付费版 5 美元一个月,包含 1000 万请求,性价比依然很高。

6.3 后续可以怎么扩展

这套架构往上长,可以做的事情很多。加 Pages 做前端托管,加 Queues 做异步任务,加 Cron Triggers 做定时任务,加 Analytics Engine 做数据分析。基本上一个完整产品的所有基础设施,Cloudflare 都覆盖了。

我个人在实际操作中的体会是:先用最小可用架构跑起来,遇到瓶颈再逐个替换组件。不要一开始就追求完美架构,那样容易陷入过度设计。我第一个版本就是单个 Worker 加 KV,后来数据多了才迁到 D1,再后来才加 R2。每一步都是被真实需求推着走的,这样最稳。

最后分享一个小技巧:wrangler 的--remote参数可以让你在本地直接操作线上资源,调试线上问题时特别有用。但千万别在生产环境直接跑迁移,先在本地验证 SQL,再 apply 到线上,这个习惯能帮你省掉很多麻烦。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进