欢迎光临

汤不热吧技术社区完成全站边缘计算架构迁移:基于 Cloudflare Workers 与 R2 存储的全球加速体系部署公告

各位社区用户大家好,经过团队近三个月的持续努力,汤不热吧(tbr8.org)技术社区已于 2026 年 7 月正式完成全站边缘计算架构迁移。本次迁移将核心内容分发、API 网关、静态资源托管及图片处理等关键服务全面迁移至 Cloudflare Workers 边缘计算平台,配合 R2 对象存储与 KV 全球分布式键值存储,实现了全球用户访问延迟降低 60% 以上的显著提升。本文将详细介绍本次架构迁移的技术方案、实施过程及性能收益。

一、迁移背景与目标

随着社区用户规模的持续增长,我们原有的中心化架构面临越来越多的挑战。原先基于单区域 Kubernetes 集群部署的 WordPress 应用,虽然通过 Nginx 反向代理和 Cloudflare CDN 做了基础的内容缓存,但动态 API 请求、图片上传处理、搜索服务等仍需回源至中心机房,导致海外用户和国内偏远地区用户体验不佳。

具体痛点包括:

  • 亚太地区用户首屏加载时间超过 3 秒,动态 API 请求延迟高
  • 图片上传后需等待中心服务器处理缩略图和 WebP 转换,流程耗时过长
  • 站内搜索回源延迟大,高峰期搜索响应时间超过 2 秒
  • 全球用户分布不均,单一机房难以覆盖多地域低延迟访问
  • 突发流量场景下中心化架构弹性不足,多次出现服务降级

基于以上问题,我们制定了以下迁移目标:

  • 全球 P95 延迟降至 200ms 以内
  • 图片处理和转换在边缘节点完成,零回源
  • 搜索服务边缘化,响应时间降至 500ms 以内
  • 静态资源 100% 边缘缓存,命中率 > 98%
  • 架构具备自动弹性扩容能力,无需人工干预

数据中心架构

二、整体架构设计

新架构采用「边缘优先」的设计理念,将计算和存储尽可能推送到离用户最近的 Cloudflare 边缘节点。整体架构分为三层:

2.1 边缘计算层(Cloudflare Workers)

边缘计算层是整个架构的核心,承载了以下关键功能:

  • API 网关:所有 REST API 请求通过 Workers 路由分发,实现请求鉴权、限流、缓存和负载均衡
  • 页面渲染加速:对 WordPress 页面进行边缘 HTML 缓存,通过 Cache API 实现 stale-while-revalidate 策略
  • 图片处理服务:基于 Workers 实现 WebP/AVIF 自动转换、尺寸裁剪、质量优化,替代原先中心化 ImageMagick 处理
  • 搜索代理:将搜索请求路由至边缘 KV 索引,减少回源搜索频次

核心 Workers 路由配置示例:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// wrangler.toml 路由配置
name = "tbr8-edge-gateway"
main = "src/gateway.ts"
compatibility_date = "2026-06-01"

[routes]
pattern = "tbr8.org/api/*"
zone_name = "tbr8.org"

[[kv_namespaces]]
binding = "SEARCH_INDEX"
id = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

[[r2_buckets]]
binding = "MEDIA_BUCKET"
bucket_name = "tbr8-media"

[vars]
ORIGIN_URL = "https://origin.tbr8.org"
CACHE_TTL = "3600"
IMG_MAX_WIDTH = "1920"

2.2 存储层(R2 + KV)

存储层由两个核心组件构成:

Cloudflare R2 对象存储:替代原先的 NFS + Nginx 静态文件服务,存储所有上传图片、附件和静态资源。R2 提供 S3 兼容 API,且出站流量免费,大幅降低了带宽成本。我们通过 Workers 在写入 R2 的同时自动生成多尺寸缩略图元数据,并写入 KV 索引。

Cloudflare KV 全球分布式键值存储:用于存储搜索索引、URL 映射表、配置热更新数据等。KV 的最终一致性模型适合读多写少的场景,全球 300+ 边缘节点均可低延迟读取。

R2 存储桶的生命周期策略配置:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// R2 生命周期规则 - 自动清理临时文件
{
  "rules": [
    {
      "id": "cleanup-temp-uploads",
      "prefix": "temp/",
      "status": "Enabled",
      "expiration": {
        "days": 7
      }
    },
    {
      "id": "cleanup-processed-images",
      "prefix": "processed/_tmp/",
      "status": "Enabled",
      "expiration": {
        "days": 3
      }
    }
  ]
}

2.3 源站层(WordPress + Kubernetes)

源站层保留 WordPress 作为内容管理系统,但职责大幅缩减:

  • 仅处理管理后台操作(文章编辑、评论审核等)
  • 作为内容权威数据源,Workers 缓存未命中时回源获取
  • Webhook 通知机制:文章发布/更新时主动刷新边缘缓存

数据架构可视化

三、关键技术实现

3.1 边缘图片处理 Pipeline

图片处理是本次迁移中技术难度最高的部分。原先基于 ImageMagick 的中心化处理流程需要 2-5 秒,迁移到 Workers 后我们使用 WASM 版本的 Sharp 库实现边缘图片处理,处理时间降至 100ms 以内。

图片处理 Worker 的核心逻辑:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// src/image-worker.ts
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const imagePath = url.pathname.replace('/uploads/', '');
    const width = parseInt(url.searchParams.get('w') || '800');
    const format = request.headers.get('Accept')?.includes('image/avif')
      ? 'avif'
      : request.headers.get('Accept')?.includes('image/webp')
        ? 'webp'
        : 'original';

    // 缓存键:路径+宽度+格式
    const cacheKey = new Request(
      `${url.origin}/img/${width}/${format}${imagePath}`
    );
    const cache = caches.default;
   
    // 尝试命中边缘缓存
    let response = await cache.match(cacheKey);
    if (response) return response;

    // 从 R2 获取原图
    const original = await env.MEDIA_BUCKET.get(imagePath);
    if (!original) return new Response('Not Found', { status: 404 });

    if (format === 'original') {
      response = new Response(original.body, {
        headers: { 'Content-Type': original.httpMetadata?.contentType || 'image/jpeg' }
      });
    } else {
      // 使用 WASM Sharp 处理
      const processed = await processImage(
        await original.arrayBuffer(),
        { width, format, quality: 80 }
      );
      response = new Response(processed, {
        headers: {
          'Content-Type': `image/${format}`,
          'Cache-Control': 'public, max-age=31536000'
        }
      });
    }

    // 写入边缘缓存
    await cache.put(cacheKey, response.clone());
    return response;
  }
};

该方案的巧妙之处在于:首次请求触发图片处理并缓存,后续相同参数的请求直接从边缘缓存返回,实现了「处理一次,全球加速」的效果。自动格式协商(AVIF > WebP > 原始格式)确保不同浏览器获得最优格式。

3.2 智能 HTML 缓存与增量刷新

WordPress 页面的边缘缓存是性能提升的关键。我们设计了基于 stale-while-revalidate 的缓存策略:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// src/html-cache.ts
async function handlePageRequest(
  request: Request,
  env: Env
): Promise<Response> {
  const cache = caches.default;
  const cacheKey = new Request(request.url);
 
  // 尝试获取缓存
  const cached = await cache.match(cacheKey);
 
  if (cached) {
    const age = (Date.now() - parseInt(
      cached.headers.get('x-cached-at') || '0'
    )) / 1000;
   
    // 缓存未过期:直接返回
    if (age < 3600) return cached;
   
    // 缓存过期但在容忍窗口内:返回旧内容,后台刷新
    if (age < 7200) {
      // 异步刷新,不阻塞当前请求
      env.FETCH_TRIGGER?.fetch(request);
      return cached;
    }
  }
 
  // 回源获取最新内容
  const originResponse = await fetch(
    new Request(env.ORIGIN_URL + new URL(request.url).pathname, {
      headers: request.headers
    })
  );
 
  const response = new Response(originResponse.body, {
    headers: {
      ...Object.fromEntries(originResponse.headers),
      'x-cached-at': Date.now().toString(),
      'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=3600'
    }
  });
 
  await cache.put(cacheKey, response.clone());
  return response;
}

当 WordPress 后台发布新文章或更新内容时,通过 Webhook 主动清除对应 URL 的边缘缓存:


1
2
3
4
5
6
7
8
9
10
11
// WordPress 端 Webhook 触发
add_action('save_post', function($post_id) {
    $permalink = get_permalink($post_id);
    wp_remote_post('https://tbr8.org/api/cache/purge', [
        'body' => json_encode([
            'urls' => [$permalink, home_url('/')],
            'secret' => defined('CF_PURGE_SECRET') ? CF_PURGE_SECRET : ''
        ]),
        'headers' => ['Content-Type' => 'application/json']
    ]);
});

3.3 边缘搜索索引

站内搜索是用户高频使用的功能。我们利用 Cloudflare KV 构建了轻量级边缘搜索索引,实现方式如下:

  • 文章发布时,由 Worker 提取标题、摘要、标签等文本,构建倒排索引条目写入 KV
  • 搜索请求在边缘节点直接查询 KV,无需回源
  • 支持中文分词(基于结巴分词 WASM 版本)和前缀匹配
  • 搜索结果与 WordPress 文章 URL 映射存储在 KV 中,确保链接准确性

虽然 KV 搜索的召回率不及 Elasticsearch,但对于社区规模的文章库(数千篇)完全够用,且 P95 搜索延迟从原来的 1.8 秒降至 180ms。

性能分析仪表盘

四、迁移实施过程

本次迁移采用渐进式灰度策略,分四个阶段完成:

4.1 第一阶段:静态资源迁移(2 周)

将所有 WordPress 上传目录的图片和附件迁移至 R2 存储桶。使用 rclone 进行批量迁移,总计迁移约 15GB 媒体文件。迁移期间保持双写(R2 + 原有 NFS),确保数据一致性。此阶段完成后的 URL 重写规则:


1
2
3
4
5
6
# Nginx 重写规则 - 将旧图片 URL 重定向到 R2
location /wp-content/uploads/ {
    rewrite ^/wp-content/uploads/(.*)$
        https://media.tbr8.org/$1
        redirect;
}

4.2 第二阶段:API 网关上线(3 周)

在 Cloudflare Workers 上部署 API 网关,逐步将 WordPress REST API 流量切换到 Workers 代理模式。关键配置包括请求限流(每 IP 每秒 20 次请求)、JWT 鉴权、响应缓存等。此阶段通过 Cloudflare 的 Split Testing 功能实现 10% → 50% → 100% 的渐进式流量切换。

4.3 第三阶段:图片处理边缘化(2 周)

上线边缘图片处理 Worker,替换中心化 ImageMagick 处理。由于 Workers 有 CPU 时间限制(免费版 10ms,付费版 50ms),我们选用 Bindings 版本的 Sharp WASM 库,并针对大图做了分块处理优化。对于超过 Worker 处理能力的超大图片(>10MB),设置回源降级路径。

4.4 第四阶段:HTML 缓存与搜索边缘化(3 周)

最后阶段实现页面级边缘缓存和搜索索引边缘化。此阶段最大的挑战是缓存一致性问题——确保文章更新后用户能立即看到最新内容。我们通过 Webhook 主动刷新 + 短 TTL + stale-while-revalidate 的组合策略解决了这个问题。

五、性能收益与监控数据

迁移完成后,我们通过 Cloudflare Analytics 和自建 Grafana 仪表盘持续监控各项性能指标。以下为迁移前后的对比数据:

指标 迁移前 迁移后 提升幅度
全球平均首屏时间 2.8s 1.1s ↓ 60.7%
亚太 P95 延迟 3.2s 0.9s ↓ 71.9%
图片处理平均耗时 3.5s 0.08s ↓ 97.7%
搜索 P95 延迟 1.8s 0.18s ↓ 90.0%
静态资源缓存命中率 82% 99.2% ↑ 17.2pp
月度带宽成本 $320 $45 ↓ 85.9%
突发流量承载能力 500 QPS 5000+ QPS ↑ 10x

特别值得关注的是带宽成本的降低——得益于 R2 出站流量免费的特性,以及边缘缓存命中率的提升,回源流量下降了 95%,带宽成本从月均 $320 降至 $45,年度节省约 $3,300。

六、踩过的坑与经验总结

在三个月的迁移过程中,我们遇到了不少技术挑战,以下是几个印象深刻的踩坑记录:

6.1 Workers CPU 时间限制

Cloudflare Workers 付费版有 50ms CPU 时间限制,对于复杂的图片处理任务来说非常紧张。我们的解决方案是将图片处理拆分为多个阶段:首次请求只做格式转换和基础尺寸调整(控制在 30ms 以内),更复杂的操作(如水印叠加、高级压缩)通过 Queue 异步处理。这样用户在首次请求时就能获得基础版本图片,后续请求则返回处理完成的最终版本。

6.2 KV 最终一致性问题

Cloudflare KV 采用最终一致性模型,全球传播延迟可达 60 秒。对于搜索索引更新场景,这意味着文章发布后可能存在短暂的全网搜索结果不一致。我们的解决方案是在文章发布后的 60 秒窗口内,搜索请求强制回源到中心 Elasticsearch,确保新文章立即可搜索。KV 索引更新完成后的后续搜索则走边缘路径。

6.3 WordPress 插件兼容性

部分 WordPress 插件假设所有请求都到达源站,在边缘缓存场景下出现异常。例如统计插件重复计数、评论表单 nonce 验证失败等。我们通过 Workers 对这些特定路径设置 bypass 缓存策略,确保涉及用户状态的请求始终回源。


1
2
3
4
5
6
7
8
9
10
11
12
// 特定路径缓存豁免规则
const BYPASS_PATHS = [
  '/wp-admin/',
  '/wp-login.php',
  '/wp-comments-post.php',
  '/?rest_route=/wp/v2/comments',
  '/sitemap',
];

function shouldBypassCache(pathname: string): boolean {
  return BYPASS_PATHS.some(p => pathname.startsWith(p));
}

服务器运维

七、后续规划

边缘计算架构迁移的完成只是起点,后续我们计划在以下方向继续优化:

  • Workers for AI:利用 Cloudflare Workers AI 在边缘节点运行轻量级推理模型,实现文章自动标签推荐、内容摘要生成等功能
  • Pages Functions 替代部分 WordPress 主题渲染:将文章详情页的 HTML 渲染逻辑迁移至 Workers,实现完全的边缘 SSR,进一步降低首屏延迟
  • D1 数据库边缘化:将评论数据和用户交互数据迁移至 Cloudflare D1 边缘 SQLite 数据库,减少核心数据库回源查询
  • Hyperdrive 加速 WordPress 数据库:通过 Cloudflare Hyperdrive 连接池优化数据库连接,降低回源查询延迟
  • 实时协作功能:基于 Durable Objects 实现文章协同编辑和实时评论推送

八、对社区用户的影响

本次架构升级对普通用户最直观的感受包括:

  • 页面加载速度显著提升:无论身处何地,打开文章页面的速度都有明显改善,特别是海外用户的体验提升最为显著
  • 图片加载更流畅:自动适配最优图片格式(AVIF/WebP),图片加载速度提升 3 倍以上
  • 搜索更快更准:站内搜索响应速度提升约 10 倍,且结果更加即时
  • 高峰期访问更稳定:边缘架构的弹性能力确保即使在流量高峰期,网站也能保持流畅访问

如您在使用过程中遇到任何异常,请通过社区反馈渠道或直接联系管理员,我们将第一时间处理。感谢大家一直以来对汤不热吧技术社区的支持!

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » 汤不热吧技术社区完成全站边缘计算架构迁移:基于 Cloudflare Workers 与 R2 存储的全球加速体系部署公告
分享到: 更多 (0)