beio Logobeio

【Cloudflare Workers 全端架構師之路 10】實戰篇:微服務架構與 Service Bindings 終極整合

發布於

01. 前言:從單體 (Monolith) 到微服務

在前九篇教學中,我們通常把所有邏輯(驗證、資料庫讀取、AI 推論)寫在同一個 Worker 專案裡。這對於中小型應用非常完美,因為部署快、結構簡單。

但當團隊擴張到 20 人,或者業務邏輯變得極度複雜時,單體架構會遇到瓶頸:

  1. 部署風險:修改 AI 邏輯可能會不小心弄壞結帳功能。
  2. 冷啟動變慢:隨著程式碼體積膨脹,Isolate 的載入時間會增加。
  3. 職責不清:所有人都改同一個 repo。

Cloudflare Service Bindings 讓我們能以微服務的方式組織程式碼,但完全沒有傳統微服務的缺點(HTTP 延遲)。

02. 核心技術:Service Bindings 與 RPC

在 AWS Lambda 中,Lambda A 呼叫 Lambda B 通常要透過 API Gateway (HTTP),這會增加 100ms+ 的延遲。

但在 Cloudflare Workers 中,Service Bindings 允許 Worker A 直接呼叫 Worker B 的匯出函式 (Exported Functions)

  • 零網路延遲:不走公開網路,直接在 Cloudflare 內部記憶體交換數據。
  • 強型別 RPC:你可以像呼叫本地函式一樣呼叫遠端 Worker,並保有 TypeScript 型別檢查。

03. 系統架構:全球電商平台

我們將系統拆分為一個 Gateway (入口) 與三個 Internal Services (內部服務)

  1. Gateway Worker: 負責路由、組合回應。
  2. Auth Service: 負責 JWT 簽發與驗證 (Part 6)。
  3. Product Service: 負責 D1 商品查詢與 R2 圖片 (Part 4, 5)。
  4. AI Service: 負責 RAG 客服機器人 (Part 9)。

這樣的架構讓我們可以單獨部署 AI 服務,而不影響核心的商品服務。

04. 實作 Part 1: 定義 Auth Service (被呼叫端)

我們使用 WorkerEntrypoint 來定義可以被外部呼叫的 RPC 方法。建立一個新專案 services/auth-service

// services/auth-service/src/index.ts
import { WorkerEntrypoint } from "cloudflare:workers";

// 定義公開的 RPC 介面
export class AuthService extends WorkerEntrypoint {
  async verifyToken(token: string) {
    // 這裡實作 Part 6 的 JWT 驗證邏輯
    // 為了示範簡潔,這裡回傳模擬數據
    if (token === "valid-token") {
      return { valid: true, userId: "user_123", role: "admin" };
    }
    return { valid: false, error: "Invalid token" };
  }

  async login(username: string) {
    return { token: "valid-token", expires: 3600 };
  }
}

// 仍然可以保留 fetch handler 供外部 HTTP 測試 (選擇性)
export default {
  async fetch(request: Request) {
    return new Response("Auth Service is running");
  }
}

wrangler.toml 中不需要特殊設定,只需部署即可。

05. 實作 Part 2: Gateway Worker (呼叫端)

建立主專案 apps/gateway。首先設定 wrangler.toml 來綁定其他服務:

# apps/gateway/wrangler.toml
name = "gateway-api"

# 綁定 Auth Service
[[services]]
binding = "AUTH_RPC" # 程式碼中的變數名
service = "auth-service" # 對方 Worker 的名稱

# 綁定 Product Service
[[services]]
binding = "PRODUCT_RPC"
service = "product-service"

接下來,在 Gateway 中透過 RPC 呼叫 Auth Service:

// apps/gateway/src/index.ts
import { Hono } from 'hono'
import { WorkerEntrypoint } from "cloudflare:workers";

// 引入對方的型別 (在 Monorepo 中可以透過 TypeScript Project References 共享)
// 這裡假設我們知道對方的介面
interface AuthServiceType extends WorkerEntrypoint {
  verifyToken(token: string): Promise<{ valid: boolean; userId?: string }>;
}

type Bindings = {
  AUTH_RPC: Service<AuthServiceType>; // Service Binding
  PRODUCT_RPC: Service<any>;
}

const app = new Hono<{ Bindings: Bindings }>()

// Middleware: 透過 RPC 驗證身分
app.use('/api/*', async (c, next) => {
  const token = c.req.header('Authorization')?.split(' ')[1];
  if (!token) return c.json({ error: 'No token' }, 401);

  // 🚀 關鍵:像呼叫本地函式一樣呼叫遠端 Worker
  // 沒有 HTTP Overhead,極速回傳
  const result = await c.env.AUTH_RPC.verifyToken(token);

  if (!result.valid) {
    return c.json({ error: 'Unauthorized' }, 401);
  }
  
  c.set('userId', result.userId);
  await next();
})

app.get('/api/products', async (c) => {
  // 呼叫 Product Service 撈資料
  // const products = await c.env.PRODUCT_RPC.getProducts();
  return c.json({ message: "Products from RPC" });
})

export default app

06. 實作 Part 3: 整合 AI 與 Queues

我們甚至可以把 AI 服務綁定進來,讓 Gateway 也能處理聊天請求。

// apps/gateway/src/index.ts (續)

app.post('/api/chat', async (c) => {
  const { question } = await c.req.json();
  
  // 呼叫 AI Service (Part 9 的邏輯)
  // 這樣 Gateway 不需要掛載 Vectorize 或 AI Binding,保持輕量
  const answer = await c.env.AI_RPC.askRAG(question);
  
  return c.json({ answer });
})

這就是微服務的威力:Gateway 專注於路由與聚合,複雜的運算交給專門的 Worker。

07. Monorepo 專案管理

為了管理這些分散的 Worker,建議使用 npm workspacesTurborepo

資料夾結構建議:

/my-edge-app
  /package.json (workspaces: ["apps/*", "services/*", "packages/*"])
  /apps
    /gateway       (面向使用者的 API)
  /services
    /auth-service  (JWT 邏輯)
    /product-service (D1 + R2)
    /ai-service    (Workers AI + Vectorize)
  /packages
    /database      (Drizzle Schema 共用定義)
    /types         (RPC 介面型別定義)

這樣做的好處是,你可以把 Drizzle Schema 定義在 /packages/database,然後同時讓 product-servicegateway 引用它,確保型別一致。

08. 系列總結:你的架構師之路

恭喜你!你已經完成了這趟從 Hello World 到 微服務架構的旅程。

讓我們回顧一下你的武器庫:

  1. 運算: Workers (V8 Isolates) 取代了笨重的容器。
  2. API: Hono 讓你用熟悉的語法開發 Edge API。
  3. 資料: KV (快取)、D1 (SQL)、R2 (檔案) 構成了完整的資料層。
  4. 安全: Middleware 與 JWT 在邊緣攔截威脅。
  5. 狀態: Durable Objects 解決了分散式系統的一致性難題。
  6. 非同步: Queues 幫你處理耗時任務,削峰填谷。
  7. 智慧: Workers AI 讓你的應用天生具備 LLM 能力。
  8. 架構: Service Bindings 讓你能夠構建可擴展的微服務艦隊。

Cloudflare Workers 不再只是一個「CDN 腳本」,它是下一代雲端開發的標準。

未來的應用程式將是 預設全球化 (Global by Default) 的。你的程式碼、資料、甚至 AI 模型,都將運行在距離使用者幾毫秒的地方。

保持好奇,繼續構建。Edge is the limit!


Ken Huang

關於作者

Ken Huang

熱衷於嘗試各類新技術的軟體開發者,現階段主力為 Android / iOS 雙平台開發,同時持續深耕前端與後端技術,以成為全端工程師與軟體架構師為目標。

最廣為人知的代表作為 BePTT。開發哲學是「以做身體健康為前提」,致力於在工作與生活平衡的基礎上,打造出擁有絕佳使用體驗的軟體服務。

這裡是用於紀錄與分享開發經驗的空間,希望能透過我的實戰筆記,幫助開發者解決疑難雜症並提升效率。

Android APP DevelopmentiOS APP DevelopmentBePTT CreatorFull Stack Learner