
在可擴展軟體架構的領域中,多租戶的概念至關重要。單一應用程式實例為多個客戶(稱為租戶)提供服務,同時保持資料的邏輯分離。設計底層資料結構需要精確性。實體關係圖(ERD)為此架構提供藍圖。它們可視化表、鍵與約束之間的關係,以確保跨租戶的資料完整性。 📐
在為多租戶環境建構ERD時,主要挑戰在於平衡隔離性、效能與成本。並無一種萬能方案適用於所有情境。相反地,架構師必須選擇符合安全需求與營運預算的模式。本文探討建模這些架構的核心策略,深入剖析技術實作細節,且不依賴特定供應商工具。 🛠️
理解核心模式 🔍
多租戶建模的基礎在於租戶資料的實際儲存方式與邏輯分離方式。業界有三種主要模式。每種模式在資料隔離與維護複雜度之間都呈現獨特的權衡。
1. 每個租戶專用資料庫 🏢
在此方法中,每位客戶都會獲得自己的獨立資料庫實例。ERD結構在所有實例中保持一致,但物理邊界非常嚴格。
- 隔離等級:最高。一個資料庫的故障不會影響其他資料庫。
- 安全性:高。物理分離可防止意外的資料外洩。
- 成本:較高,因每個實例都需額外資源開銷。
- 遷移:複雜。結構變更需在每個實例上執行腳本。
從ERD觀點來看,此模式看起來像標準的單租戶圖表。然而,部署流程必須管理多個連接。這通常用於具有嚴格合規要求的企業客戶。
2. 共用資料庫,獨立模式 📂
在此模式中,所有租戶都位於單一資料庫系統內,但每位租戶擁有自己獨立的模式(命名空間)。每個模式都重複建立表格。
- 隔離等級:高。資料庫引擎內的邏輯分離。
- 安全性:強。存取控制清單(ACL)可限制模式的可見性。
- 成本:中等。共用資料庫引擎的開銷。
- 維護:比專用資料庫更容易,但模式更新必須傳播至所有模式。
在ERD中,這以特定命名空間標籤下的表格群組來表示。關係保持一致,但圖表範圍擴展以顯示多個模式容器。
3. 共用資料庫,共用模式 🔗
這是通用SaaS應用程式中最常見的模式。所有資料都儲存在同一組表格中,並由特定欄位區分。
- 隔離等級: 合理。所有資料行都存在同一張表格中。
- 安全性: 取決於應用程式邏輯與資料列層級安全性(RLS)。
- 成本: 最低。最大化資源使用效率。
- 維護: 簡單。結構變更會立即套用至所有租戶。
此模式的實體關係圖引入了一個關鍵欄位:tenant_id。此外來鍵將每個記錄連結至特定客戶。這是此模型中資料隔離的基石。
在實體關係圖中視覺化租戶資料 📊
為多租戶建立有效的實體關係圖,需要使用特定符號來清楚傳達資料分割策略。利益相關者必須了解資料的流動方式以及邊界所在位置。
租戶 ID 欄位
在共用結構中,tenant_id必須出現在每張儲存使用者特定資料的表格中。這不是可選的。若在交易表格中遺漏此欄位,可能導致嚴重的資料外洩。
- 主要鍵: 通常,
tenant_id與本地 ID 的組合會形成複合主要鍵。 - 索引: 對效能至關重要。以
tenant_id篩選的查詢必須快速。 - 限制條件: 外來鍵通常參考一個中央
tenants主表格。
主租戶表格
通常會有一張專用表格,用來儲存每個租戶的相關元資料。此表格會儲存設定細節、訂閱狀態與帳單資訊。
- 主要屬性:租戶 ID、名稱、方案層級、建立日期。
- 關係:與所有其他資料表為一對多關係。
比較資料結構策略 📋
為了做出明智的決策,請使用以下表格比較每種策略的運營影響。
| 功能 | 專用資料庫 | 共用結構 | 共用資料表 |
|---|---|---|---|
| 資料隔離 | 物理 | 邏輯 | 邏輯 |
| 查詢複雜度 | 簡單 | 複雜 | 複雜 |
| 資源成本 | 高 | 中等 | 低 |
| 結構遷移 | 困難 | 中等 | 容易 |
| 備份策略 | 細粒度 | 細粒度 | 完整轉儲 |
安全與資料分割 🔒
建立資料結構模型僅是戰鬥的一半。資料存取層必須強制執行圖表中定義的界限。使用共用表格時,邏輯隔離是目標。
資料列層級安全 (RLS)
現代資料庫引擎支援 RLS,可在資料列層級強制執行存取政策。這使得資料庫本身能夠根據目前使用者的環境過濾結果。
- 政策定義: 一項規則指出,只有當
tenant_id符合目前會話時,資料列才可見。 - 實作: ERD 應反映儲存會話內容的能力。
- 優勢:降低應用層級錯誤導致資料外洩的風險。
審計與記錄
所有對租戶特定資料的變更都應被記錄。ERD 中必須包含審計表格,以追蹤誰在何時修改了何項資料。這對於合規性與除錯至關重要。
- 必要欄位:租戶 ID、使用者 ID、動作、時間戳記、舊值、新值。
- 保留期限:政策必須明確規定日誌保留的時間長度。
效能考量 ⚡
共用表格會增加查詢執行計畫的複雜性。隨著資料量增加,資料庫引擎必須有效分離租戶資料,而無需掃描整個表格。
索引策略
標準索引不足。您需要建立以租戶識別碼為優先的複合索引。
- 主要索引: 應以
tenant_id為起點,接著是自然鍵。 - 查詢優化: 確保所有查詢都包含租戶過濾條件於
WHERE子句中。 - 分割: 某些系統允許根據以下方式對表格進行物理分割:
tenant_id依範圍或雜湊。
查詢複雜度
當在多個架構或租戶之間的表格進行連接時,連接條件必須包含租戶 ID。若未如此操作,可能會導致來自不同客戶的資料產生笛卡爾積。
- 連接邏輯: 始終根據
tenant_id以及關係鍵。 - 應用層: 中間件應自動注入租戶過濾條件。
維護與遷移 🔄
架構並非靜態的。隨著需求變更而演進。多租戶會為這些變更增加一層難度。
架構演進
在共享表格中新增欄位相當簡單。刪除欄位會影響所有租戶。在專用資料庫模型中,您必須為每個實例撰寫變更腳本。
- 版本控制: 跟蹤架構版本以管理向後相容性。
- 回滾: 若遷移在部分租戶上失敗,應有計畫地回滾變更。
備份與恢復
恢復策略因模式而異。專用資料庫可讓您恢復單一租戶而不影響其他租戶。共享資料庫則需恢復整個實例。
- 細粒度: 共享表格使單一租戶的時點恢復變得困難。
- 測試: 定期在測試環境中測試還原程序。
應避免的常見陷阱 ⚠️
即使擁有設計良好的實體關係圖,實作錯誤仍可能危及系統。請對這些常見問題保持警覺。
- 硬編碼租戶邏輯: 永遠不要在應用程式程式碼中硬編碼租戶 ID。應使用設定或會話內容。
- 全域變數: 避免將租戶內容儲存在可能跨請求持續存在的全域變數中。
- 缺少約束: 如果資料庫未強制執行
tenant_id唯一性,應用程式必須嚴格驗證。 - 忽略分析: 為報告目的跨租戶聚合資料需要謹慎處理,以避免混合敏感資訊。
命名慣例的最佳實務 🏷️
命名的一致性有助於開發人員立即理解資料結構。如果共享架構中存在租戶特定的資料表,請使用前置詞或後置詞來標示。
- 資料表命名:
tenant_name_orders或orders_tenant_id. - 欄位命名: 始終包含
tenant_id明確地包含在每個記錄資料表中。 - 索引: 清晰命名索引,例如
idx_orders_tenant_id.
架構選擇的結論 🎯
選擇正確的多租戶架構模式需要在技術可行性與業務需求之間取得平衡。ERD 是將此選擇傳達給整個團隊的工具。無論是為安全性選擇物理隔離,還是為效率選擇共用資料表,圖示都必須明確顯示邊界。
透過遵守嚴格的建模標準、實施強大的索引並維持清晰的分離邏輯,您可以建立一個可安全擴展的系統。當基礎穩固時,租戶的複雜性是可以管理的。從圖示的第一行開始,就專注於資料完整性與效能。 🚀









