我看過團隊花上幾個月爭論多租戶與多站點架構,最後選錯了,又花另外六個月進行遷移。這是那種在你深入三個衝刺之後才會意識到問題的決策——你的內容編輯可能會不小心發佈到錯誤的品牌,或者你的部署管道需要花 45 分鐘,因為你在重建十二個站點,而實際上只有一個改變了。

這不是理論上的比較。我已經構建了兩種模式——有時候對同一個客戶,因為第一次選擇沒有奏效。讓我帶你了解在做出這個決定時真正重要的是什麼。

目錄

多租戶與多站點架構:如何決策

清楚定義術語

這些術語經常被隨意使用,所以我們來確定一下。

多租戶架構

一個應用實例為多個租戶(品牌、客戶、地區)提供服務。他們共享相同的程式碼庫、相同的資料庫(通常是)和相同的部署。租戶隔離在應用層進行——通過中介軟體、資料庫模式或行級過濾。

把它想象成一棟公寓樓。每個人都共享結構、管道和電路。但每個單位都有自己的鎖。

多站點架構

每個站點是一個獨立的應用實例,具有自己的程式碼庫(或共享程式碼庫的分支)、自己的資料庫和自己的部署管道。他們可能共享設計系統或元件庫,但他們是獨立部署和運營的。

這更像一個住宅開發區。同一個建築商、類似的藍圖,但每棟房子都有自己的基礎。

混合區域

說實話,大多數生產系統都落在兩者之間。你可能有一個多租戶 CMS 為獨立部署的前端提供內容。或者一個共享程式碼庫,被部署為每個租戶的獨立實例。真正的問題不是「選哪一個」,而是「在頻譜上的哪個位置」。

多租戶架構何時勝出

當你的站點相似之處大於差異時,多租戶架構就大放光彩。

強大的品牌一致性要求

如果你管理同一品牌的 15 個地區站點,並且設計需要保持鎖定,多租戶是你的朋友。一個程式碼庫意味著元件、佈局和交互模式的一個信息來源。當品牌團隊更新按鈕樣式時,它會在所有地方推出。

快速擴展到新租戶

我與一個特許經營平台合作,需要每週推出新的位置。使用多租戶,添加新站點只需要一個資料庫條目和一個 DNS 記錄。沒有新的基礎設施,沒有新的部署。上線時間從兩週縮短到大約 30 分鐘。

集中內容運營

當你有一個小型內容團隊管理多個資產時,多租戶將所有內容保持在一個地方。編輯者登入一個系統,切換上下文,並管理所有租戶的內容。無需為十多個 CMS 實例處理認證。

共享功能開發

每個你構建的功能都同時造福所有租戶。錯誤修復、性能改進、新整合——部署一次,到處受益。開發工作的投資回報率是倍增的。

多站點架構何時勝出

當你的站點需要顯著差異時,多站點架構就勝出。

完全不同的用戶體驗

如果品牌 A 是電子商務店面,品牌 B 是內容出版物,將他們塞進一個程式碼庫會造成混亂。我見過多租戶程式碼庫,其中 60% 的程式碼在租戶特定的條件後面。在那一點上,你沒有一個應用——你有幾個糟糕的應用共享一個倉庫。

不同的技術要求

也許一個站點需要 Next.js 來實現其動態、應用程式式的體驗,而另一個是一個完美適合 Astro 的內容豐富的站點。多站點讓每個資產使用正確的工具。我們構建了投資組合,其中一些站點運行在 Next.js 上,其他運行在 Astro 上,所有這些都從 共享無頭 CMS 獲取。

獨立發布週期

當不同的業務單位擁有不同的站點並且需要按自己的時間表發布時,多租戶會造成瓶頸。租戶 A 的新功能的部署不應該需要對租戶 B 到 Z 進行回歸測試。多站點為每個團隊提供自主權。

監管或資料隔離

某些行業需要硬資料隔離——不只是應用層分離,而是物理上獨立的資料庫,可能在不同的地區。醫療保健、金融和政府專案通常強制要求這一點。多站點使合規變得簡單直接,因為隔離是架構上的,而不僅僅是邏輯上的。

不同的性能特性

如果一個租戶獲得 1000 萬次月度訪問,而另一個獲得 5 萬次,共享基礎設施意味著你要麼為小租戶過度配置,要麼為大租戶配置不足。獨立部署讓你為每個資產合理規模。

多租戶與多站點架構:如何決策 - 架構

決策框架

這是我與客戶一起使用的框架。為你的情況給每個因素打分:

因素 支持多租戶 支持多站點
站點相似度 80% 以上的共享 UI/功能 少於 50% 的共享
資產數量 10 個以上站點 少於 5 個站點
增長率 經常添加站點 穩定,很少添加
團隊結構 一個中央團隊 每個站點有獨立團隊
內容模型 相同或幾乎相同 顯著不同
合規需求 標準要求 嚴格的資料隔離
技術棧 所有地方相同的框架 需要不同的框架
發布節奏 協調發布可以 需要獨立發布
自定義深度 主題級(顏色、標誌) 結構級(佈局、功能)
預算 為效率優化 為靈活性優化

如果你大多在一列得分,決定很清楚。如果你在中間分裂,你可能在尋找混合方法——這很好。

實踐中的架構模式

讓我用程式碼具體化。

Next.js 的多租戶

我使用最常見的模式是基於中介軟體的租戶解析:

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';

const TENANT_MAP: Record<string, string> = {
  'brand-a.com': 'brand-a',
  'brand-b.com': 'brand-b',
  'brand-c.com': 'brand-c',
};

export function middleware(request: NextRequest) {
  const hostname = request.headers.get('host') || '';
  const tenantId = TENANT_MAP[hostname] || 'default';
  
  // 通過標頭傳遞租戶上下文
  const response = NextResponse.next();
  response.headers.set('x-tenant-id', tenantId);
  
  // 如果需要,重寫到租戶特定的路徑
  const url = request.nextUrl.clone();
  url.pathname = `/${tenantId}${url.pathname}`;
  
  return NextResponse.rewrite(url);
}

然後你的頁面元件拉取租戶特定的配置:

// lib/tenant-config.ts
export async function getTenantConfig(tenantId: string) {
  // 可能來自資料庫、CMS 或配置檔案
  return {
    theme: await fetchTheme(tenantId),
    navigation: await fetchNavigation(tenantId),
    features: await fetchFeatureFlags(tenantId),
    locale: await fetchLocaleConfig(tenantId),
  };
}

這在租戶開始需要不同的頁面結構、不同的資料獲取策略或不同的第三方整合之前效果很好。那時條件邏輯就開始偷偷進來了。

帶有共享套件的多站點

對於多站點,我使用帶有共享套件的 monorepo:

├── apps/
│   ├── brand-a/          # Next.js 應用
│   ├── brand-b/          # Astro 應用  
│   └── brand-c/          # Next.js 應用
├── packages/
│   ├── ui/               # 共享元件庫
│   ├── cms-client/       # 共享 CMS 整合
│   ├── analytics/        # 共享分析包裝器
│   └── config/           # 共享 TypeScript/ESLint 配置
├── turbo.json
└── package.json
// turbo.json
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "dist/**"]
    },
    "deploy": {
      "dependsOn": ["build"]
    }
  }
}

Turborepo(或 Nx)處理依賴圖,因此你只重建改變的內容。品牌 A 獲得新功能?只有品牌 A 重建和部署。共享 UI 套件更新?所有依賴於它的東西都重建。

混合:多租戶 CMS,多站點前端

老實說,這是我對大多數場景的最愛模式。你獲得集中內容管理和獨立前端部署:

┌─────────────────────┐
│   無頭 CMS          │
│  (Sanity/Contentful)│
│   多租戶            │
│   內容空間          │
└──────┬──────┬───────┘
       │      │
   ┌───┘      └───┐
   ▼              ▼
┌──────┐    ┌──────┐
│站點 A│    │站點 B│
│Next.js│   │Astro │
└──────┘    └──────┘

內容編輯者獲得一個登入,可以管理所有資產。開發者獲得獨立程式碼庫和部署管道。對於有預算的團隊,這是兩全其美。

CMS 考量

你的 CMS 選擇顯著限制——或啟用——你的架構決定。

多租戶 CMS 支持

CMS 多租戶模型 多站點支持 定價影響
Sanity 每個租戶的資料集 優秀(單個專案中的多個資料集) 免費層:2 個資料集;付費起 $99/月
Contentful 每個租戶的空間 良好(組織級管理) 每個空間計入計劃;$300+/月
Strapi 單個資料庫,按租戶過濾 需要手動實現 自託管,隨基礎設施擴展
Hygraph 環境和階段 本地多站點內容聯合 從 $199/月起,適用於團隊計劃
WordPress(無頭) WordPress 多站點 成熟但複雜 每個站點的託管成本擴展
Payload CMS 集合級多租戶 日益增長的支持(v3.0+) 自託管,開源

Sanity 的資料集模型對於多租戶設置特別優雅。每個租戶獲得自己的資料集,具有自己的模式,但它們位於一個專案下。你可以在資料集之間共享模式定義,同時允許租戶特定的自定義。規模大時(10 個以上租戶),這保持你的內容運營理智。

Contentful 的獨立空間方法有效,但成本增長很快。團隊計劃上的每個空間都花費真金白銀,你考慮添加空間之前已經在 $300/月。

內容建模含義

使用多租戶,你的內容模型需要適應所有租戶。這通常意味著:

  • 每個內容類型上的 tenantbrand 欄位
  • 租戶特定的驗證規則
  • 仔細的權限建模,使編輯者只看到他們租戶的內容
  • 需要租戶範圍的共享內容類型(如「全局設置」)

使用多站點,每個站點有自己的內容模型。每個站點更簡單,但你喪失在站點之間共享內容的能力,除非沒有額外的內容聯合層。

性能和擴展

多租戶性能特性

多租戶的最大風險是「吵鬧的鄰居」問題。如果租戶 A 執行病毒式活動,流量增加 10 倍,所有租戶都會感受到它。緩解策略:

  • 每個租戶的邊緣快取:使用 Vercel 或 Cloudflare 的邊緣網絡,快取鍵包括租戶識別符
  • ISR 與租戶感知的重新驗證:只重新驗證內容改變的租戶的頁面
  • 每個租戶的速率限制:保護共享資源免受任何單個租戶的壓倒
// next.config.js - ISR 與租戶感知的重新驗證
export async function generateStaticParams() {
  const tenants = await getAllTenants();
  const paths = [];
  
  for (const tenant of tenants) {
    const pages = await getTenantPages(tenant.id);
    paths.push(...pages.map(page => ({
      tenant: tenant.slug,
      slug: page.slug,
    })));
  }
  
  return paths;
}

多站點性能特性

每個站點獨立擴展。好消息就是這個。壞消息是你管理 N 個部署管道、N 個監控儀表板和 N 個性能預算集。超過 20 個站點,運營開銷成為瓶頸,而不是應用性能。

從我在 2025 年進行的基準測試,以下是你在 Vercel 上可能期望的大致情況:

指標 多租戶(1 個應用,10 個租戶) 多站點(10 個應用)
冷啟動(邊緣) 20-50ms 每個站點 20-50ms
構建時間 8-15 分鐘(所有租戶) 每個站點 2-4 分鐘
增量構建 30-90 秒 每個站點 30-90 秒
每個實例的內存 256-512MB 共享 每個 256-512MB
月度 Vercel 成本(Pro) ~$20 ~$200($20 × 10)

成本差異很大。多租戶在單個 Vercel Pro 計劃上以 $20/月,對比多站點需要企業版或創意專案組織。

成本分析

讓我們談談 12 個月內 10 個站點的投資組合的實際數字。

多租戶成本估計

項目 月度成本 年度成本
Vercel Pro(1 個專案) $20 $240
Sanity 團隊(1 個專案,10 個資料集) $99 $1,188
開發(初始構建) -- $40,000-60,000
維護(持續進行) $2,000 $24,000
第 1 年總計 -- $65,428-$85,428

多站點成本估計

項目 月度成本 年度成本
Vercel Pro(10 個專案) $200 $2,400
Sanity 團隊(10 個專案) $990 $11,880
開發(初始構建,共享套件) -- $50,000-80,000
維護(持續進行,10 個站點) $4,000 $48,000
第 1 年總計 -- $112,280-$142,280

多租戶大約便宜 40-60%,主要是因為維護負擔減少。但如果多租戶複雜性導致更多錯誤、較慢的功能開發或稍後的痛苦遷移,這些數字會翻轉。

想要針對你的具體情況的更精確估計?我們在我們的 發現流程 中詳細分解架構成本。

遷移策略

有時你從一種方法開始,需要切換。以下是如何在不燒毀一切的情況下進行的。

多租戶 → 多站點

這是更常見的遷移方向。跡象表明你需要它:

  • 租戶特定代碼超過程式碼庫的 30%
  • 部署被跨租戶回歸測試阻止
  • 團隊正在踩到彼此的變更

策略:

  1. 首先將共享程式碼提取為套件(UI 元件、實用工具、CMS 客戶端)
  2. 圍繞現有應用建立 monorepo 結構
  3. 為最不同的租戶分支應用
  4. 逐漸將其他租戶移至自己的應用
  5. 隨著每個應用變成獨立應用,從中刪除租戶切換邏輯

多站點 → 多租戶

不太常見但會發生,通常在公司收購多個品牌並想要整合運營時。

  1. 審計所有站點以尋找共享模式(你會找到比預期更多的)
  2. 從最佳實現中構建共享元件庫
  3. 用最簡單的站點創建多租戶應用
  4. 一次一個站點遷移,在每個步驟驗證奇偶校驗
  5. 隨著租戶上線,停用單個應用

兩次遷移都是破壞性的。預算 3-6 個月和大量測試工作。這正是為什麼正確地進行初始決定很重要——它不只是一個架構選擇,它是一個承諾。

如果你面對這個決定,想與曾經做過的人談話,聯繫我們

常見問題

多租戶和多站點架構之間有什麼區別? 多租戶使用單個應用實例為多個品牌或客戶提供服務,租戶隔離在應用層處理。多站點為每個站點部署獨立的應用實例,可能通過 monorepo 和元件庫共享程式碼。關鍵區別在於你運行一個應用還是許多應用。

我可以將多租戶 CMS 與多站點前端結合使用嗎? 絕對可以,通常是最好的方法。具有多個資料集的無頭 CMS(如 Sanity)為你提供集中內容管理,而獨立前端部署為每個站點在技術選擇、部署時間表和性能擴展方面提供獨立性。當你的站點共享內容結構但需要不同的用戶體驗時,這個混合模式特別有效。

多租戶架構如何影響 SEO? 多租戶應用根據域或子域提供不同內容,搜尋引擎處理得很好,只要你實現適當的規範 URL、每個租戶的唯一元資料和獨立站點地圖。風險在於租戶之間意外的內容重複——確保你的站點地圖生成和 robots.txt 是租戶感知的。從 SEO 角度來看,搜尋引擎不在乎你的站點是否共享程式碼庫;他們關心他們收到的內容和標記。

多租戶比多站點便宜嗎? 通常是的,通常在託管和維護成本上便宜 40-60%。你為一次部署、一個監控設置和一組基礎設施付費。然而,如果你的租戶明顯不同,多租戶在開發時間上可能變得更昂貴,因為管理租戶特定邏輯的複雜性非線性增長。損益平衡點取決於你的站點實際相似程度。

哪種方法對無頭 WordPress 多站點更好? WordPress 多站點本質上是多租戶——一個 WordPress 安裝,多個站點。如果你將 WordPress 用作無頭 CMS,多站點網絡為你提供集中內容管理。你的前端可以是多租戶(一個 Next.js 應用)或多站點(每個 WordPress 站點的獨立應用)。對於大多數基於 WordPress 的專案,我建議混合方法:WordPress 多站點作為 CMS,每個站點的獨立前端部署。

如何跨多租戶應用處理共享認證? 使用集中認證提供者(Auth0、Clerk 或 NextAuth.js)與租戶感知的會話管理。驗證令牌應包括租戶上下文,你的中介軟體應驗證經過認證的使用者有權訪問請求的租戶。資料庫中的行級安全(Supabase 和 Neon 都支持此)增加了防止跨租戶資料洩露的第二層保護。

多租戶應用最多可以處理多少個租戶? 沒有硬限制,但實際限制圍繞構建時間和運營複雜性出現。使用 Vercel 上的 Next.js ISR,我看過多租戶應用有效處理 50 個以上租戶。超過 100 個租戶,你會想查看按需 ISR,而不是預生成所有頁面,並且你需要複雜的快取策略。SaaS 平台(如 Shopify)有效地運行數千個租戶,但他們在那個基礎設施上投入了多年。

我應該為多站點架構使用 monorepo 嗎? 幾乎總是應該。具有 Turborepo 或 Nx 的 monorepo 為你提供多租戶的程式碼共享好處(共享元件、實用工具、配置),以及多站點的部署獨立性。關鍵是保持共享套件定義清晰和版本控制。沒有 monorepo,你最終會在倉庫之間複製貼上程式碼,這會立即分歧,並在幾個月內成為維護噩夢。