文章 · 2026-02-18

个人网站全栈架构升级:从免费版到 Cloudflare $5 生产级方案

我的个人网站 yuxu.ge 承载了博客、相册、AI 助手、语义搜索、涂鸦评论等多种功能。最初,这一切都构建在 Cloudflare 慷慨的免费套餐之上。但随着功能越来越复杂,免费套餐的局限性也愈发明显。

最近,我下定决心将网站升级到 Cloudflare Workers 的 $5/月付费套餐。它解锁了 D1、Durable Objects、Workers AI、Vectorize 等生产级工具,让我有机会对整个网站架构进行彻底的重构。以下记录这次变革:从受限的妥协方案迈向生产级基础设施。

1. 升级前的架构:在免费镣铐中舞蹈

免费套餐约束了设计空间。本节梳理在这些限制下我搭建的系统。

架构概览 (免费版)

                  ┌────────────────────────────────┐
                  │         yuxu.ge 用户            │
                  └────────────────────────────────┘
                           │
                           │ HTTPS
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Cloudflare Edge                             │
│                                                                 │
│  ┌────────────────┐   ┌─────────────────┐   ┌───────────────┐  │
│  │  静态资源       │──▶│ Cloudflare Worker│──▶│ Cloudflare KV │  │
│  │ (GitHub Pages) │   └─────────────────┘   └───────────────┘  │
│  └────────────────┘           │                    │           │
│                               │                    │ (Session) │
│                               ▼                    │           │
│                       ┌────────────┐               │           │
│                       │ OpenAI API │◀──────────────┘           │
│                       └────────────┘                           │
└─────────────────────────────────────────────────────────────────┘
                  │
                  │ (浏览器端降级)
                  ▼
         ┌──────────────────────────┐
         │      Browser             │
         │ ┌──────────────────────┐ │
         │ │ ONNX Runtime (WASM)  │ │
         │ │ BGE-small-zh Model   │ │
         │ └──────────────────────┘ │
         └──────────────────────────┘

核心系统剖析

AI 助手 & 语义搜索:这是网站的亮点。我实现了一套 RAG (Retrieval-Augmented Generation) 系统:

涂鸦评论系统:允许用户在页面的任意位置发表评论。为了实现这一点,我将评论数据混合存储在静态构建的 JSON 文件和 KV 中。用户提交新评论时写入 KV,读取时则合并静态 JSON 和 KV 的数据。

认证系统:一个简单的 OTP (One-Time Password) 邮箱验证码系统。Session 信息、用户信息和 OTP 都存储在 KV 中,通过 HttpOnly Cookie 维持登录状态。

2. 瓶颈与阵痛:免费架构的"原罪"

这套架构虽然能跑,但随着访问量和功能复杂度的增加,问题也逐渐暴露。

安全问题:门户大开

数据一致性:评论的"薛定谔状态"

Cloudflare KV 是一个"最终一致性"的存储。这意味着一个数据中心的写入操作需要一些时间(通常是几十秒)才能同步到全球所有数据中心。这导致了几个诡异的问题:

性能问题:每次发布都是一次"大动干戈"

功能缺失:永远的"待办事项"

3. 解锁新世界:$5 付费套餐的能力矩阵

每月 5 美元的投资,像一把钥匙,打开了 Cloudflare 生态的另一扇大门:

能力 免费版限制 付费版解锁 ($5 Plan) 解决的问题
CPU 时间 10ms (Bundled) 15分钟 (Unbound) 复杂计算、增量索引、AI 推理
D1 数据库 不可用 边缘 SQLite,强一致性 数据一致性、复杂查询、关系数据
Durable Objects 不可用 强一致性状态存储、WebSocket、Actor 模型 实时协作、状态管理
Workers AI 不可用 边缘 GPU 推理 (Embeddings, LLM等) AI 成本、延迟、内容审核
Vectorize 不可用 原生向量数据库 向量搜索性能、可扩展性
Logpush 不可用 日志推送到对象存储 可观测性、问题排查
KV 配额 较低 更高的读/写/列表操作配额 满足更高流量

这不再是简单的量变,而是质变。我拥有了在边缘构建一个真正健壮、可扩展应用所需的一切。

4. 架构升级蓝图:分四阶段走向生产级

我将整个升级过程分为四个阶段,循序渐进,确保每一步都稳固可靠。

新架构概览 (付费版)

                  ┌────────────────────────────────┐
                  │         yuxu.ge 用户            │
                  └────────────────────────────────┘
                           │
                           │ HTTPS / WebSocket
                           ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Cloudflare Edge                             │
│                                                                 │
│  ┌────────────────┐   ┌─────────────────┐                      │
│  │  静态资源       │──▶│ Cloudflare Worker│──────────┐          │
│  │ (GitHub Pages) │   └─────────────────┘          │          │
│  └────────────────┘           │                    │          │
│                               │                    ▼          │
│  ┌────────────┐◀──────────────┤           ┌──────────────┐    │
│  │     D1     │               │           │   Durable    │    │
│  │ (Database) │               │           │   Objects    │    │
│  └────────────┘               │           │ (实时涂鸦墙)  │    │
│                               │           └──────────────┘    │
│  ┌────────────┐◀──────────────┤                               │
│  │ Vectorize  │               │                               │
│  │ (向量搜索)  │               │                               │
│  └────────────┘               │                               │
│                               ▼                               │
│  ┌────────────┐       ┌────────────┐                          │
│  │ Workers AI │◀──────│    KV      │                          │
│  │ (GPU 推理)  │       │ (缓存/OTP) │                          │
│  └────────────┘       └────────────┘                          │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

Phase 1: 奠定基石 - 安全加固与 D1 数据迁移

第一步是解决最核心的安全和数据一致性问题。

1. 安全加固:

2. 迁移到 D1:

D1 是 Cloudflare 的边缘 SQLite 数据库,提供强一致性,完美解决 KV 的痛点:

-- 用户表
CREATE TABLE users (
    id TEXT PRIMARY KEY,
    email TEXT UNIQUE NOT NULL,
    nickname TEXT,
    created_at INTEGER DEFAULT (strftime('%s', 'now'))
);

-- 会话表
CREATE TABLE sessions (
    id TEXT PRIMARY KEY,
    user_id TEXT NOT NULL,
    csrf_token TEXT NOT NULL,
    expires_at INTEGER NOT NULL,
    FOREIGN KEY (user_id) REFERENCES users(id)
);

-- 评论表
CREATE TABLE comments (
    id TEXT PRIMARY KEY,
    page_url TEXT NOT NULL,
    content TEXT NOT NULL,
    user_id TEXT NOT NULL,
    anchor_id TEXT,
    anchor_type TEXT,
    anchor_offset_x REAL,
    anchor_offset_y REAL,
    rotation REAL,
    status TEXT DEFAULT 'pending',
    created_at INTEGER DEFAULT (strftime('%s', 'now')),
    FOREIGN KEY (user_id) REFERENCES users(id)
);

CREATE INDEX idx_comments_page ON comments(page_url);
CREATE INDEX idx_comments_status ON comments(status);

Phase 2: 革新搜索 - 拥抱 Vectorize 和 Workers AI

接下来,重构整个搜索系统,用 Cloudflare 原生 AI 服务替代 OpenAI + KV 方案。

Vectorize 替代 KV 存储

// 插入向量到 Vectorize
const vectors = [{
  id: 'post_1_chunk_1',
  values: embedding, // from Workers AI
  metadata: { postId: 'post_1', text: '...' }
}];
await env.VECTOR_INDEX.insert(vectors);

// 查询相似向量
const results = await env.VECTOR_INDEX.query(queryVector, { topK: 5 });

Workers AI 替代 OpenAI Embeddings - 推荐 bge-m3

如果你想寻找"最强"的替代品,目前 Cloudflare Workers AI 上托管的 BAAI (智源) bge-m3 是首选:

⚠️ 迁移警告: OpenAI 的 text-embedding-ada-0023-small 默认是 1536 维。你不能直接混用。切换模型必须对向量数据库进行 Re-indexing (重新向量化)

Cloudflare 提供了 OpenAI 兼容接口,甚至不需要改代码逻辑:

from openai import OpenAI

client = OpenAI(
    api_key=os.environ.get("CLOUDFLARE_API_TOKEN"),
    base_url=f"https://api.cloudflare.com/client/v4/accounts/{CF_ACCOUNT_ID}/ai/v1"
)

# 代码完全不用变,只需换 model name
response = client.embeddings.create(
    model="@cf/baai/bge-m3",  # 替换 text-embedding-3-small
    input=["User intends to apply for a PhD in AI Agents.", "用户想申请人工智能博士"]
)

# 注意:返回的 embedding 长度是 1024,记得修改数据库 Schema
print(len(response.data[0].embedding))  # 1024

好处

图像智能打标 - Llama 3.2 Vision

不要用老旧的 resnet-50(它只能输出像 "Egyptian cat" 这种死板的 ImageNet 分类)。在 Paid 计划下,可以使用 Vision-Language Model (VLM)

// 智能打标器 Worker 示例
export default {
  async fetch(request, env) {
    const imageUrl = "https://example.com/your-image.jpg";

    const imageRes = await fetch(imageUrl);
    const imageBuffer = await imageRes.arrayBuffer();
    const imageArray = [...new Uint8Array(imageBuffer)];

    const response = await env.AI.run(
      "@cf/meta/llama-3.2-11b-vision-instruct",
      {
        prompt: "Analyze this image and provide 5-10 relevant tags. Output ONLY a JSON array of strings.",
        image: imageArray
      }
    );

    return new Response(JSON.stringify(response));
  }
};

对比:

Phase 3: 赋予生命 - 用 Durable Objects 实现实时涂鸦墙

Durable Objects (DO) 是强一致性的、有状态的 Worker 实例,非常适合实现实时协作功能。

为每个可评论页面创建一个 DO 实例:

export class DoodleWall {
  state: DurableObjectState;
  sessions: WebSocket[] = [];

  constructor(state: DurableObjectState) {
    this.state = state;
  }

  async fetch(request: Request) {
    // 升级为 WebSocket
    const { webSocket, response } = new WebSocketPair();
    this.sessions.push(webSocket);
    webSocket.accept();

    // 加载持久化的涂鸦数据发送给新客户端
    const doodles = await this.state.storage.get('doodles') || {};
    webSocket.send(JSON.stringify({ type: 'INIT', payload: doodles }));

    webSocket.addEventListener('message', async (msg) => {
      const data = JSON.parse(msg.data as string);
      // 更新状态并持久化
      await this.state.storage.put('doodles', updatedDoodles);

      // 广播给所有客户端
      this.broadcast(JSON.stringify({ type: 'UPDATE', payload: data }));
    });

    return response;
  }

  broadcast(message: string) {
    this.sessions.forEach(session => {
      try { session.send(message); } catch (e) {}
    });
  }
}

现在,当一个用户拖动涂鸦时,其他所有正在看这个页面的用户都能实时看到位置变化。

Phase 4: 迈向智能 - Workers AI 的深度应用

内容审核:在用户提交评论到 D1 之前,先调用 Workers AI 进行审核:

const { result } = await env.AI.run('@cf/meta/llama-2-7b-chat-fp16', {
    prompt: `Is the following comment spam, hateful, or inappropriate?
             Answer with only "safe" or "unsafe".
             Comment: "${commentText}"`
});

if (result.includes('unsafe')) {
  // 标记为待审核或直接拒绝
  comment.status = 'rejected';
}

情感分析:可以对评论进行情感分析,用不同颜色或 emoji 标识评论的情绪。

5. 成本分析:$5 真的够吗?

这是大家最关心的问题。答案是:绰绰有余。

资源 免费额度 预估使用 额外成本
基础费 - - $5/月
D1 数据库 5亿读/500万写/1GB 远低于限制 $0
Durable Objects 按需计费 用户在线时计费 $1-3/月
Workers AI 按神经元计算 ~$0.0001/条评论 <$1/月
Vectorize 免费公测 - $0
总计 $6-9/月

这笔投资换来的是系统的稳定性、可扩展性和无限的可能性。

总结:从"能用"到"好用"的蜕变

这次架构升级是个重要里程碑。它不仅仅是一次技术栈的更新,更是一次从妥协到工程的转变。

对于像我一样热爱折腾个人项目的开发者来说,Cloudflare Workers 生态提供了一条非常平滑的成长路径。从免费开始验证想法,当项目成长到一定阶段时,只需一顿午餐的钱就能获得一整套世界级的边缘计算基础设施。

这,就是 yuxu.ge 的下一章。

© 2026 Yuxu Ge ·