CockroachDB 多區域指南:表本地性、延遲與容災取捨

数据库

CockroachDB 可以讓 SQL 資料庫跨區域運行,但多區域資料庫不是魔法。它可以提升韌性,並在資料靠近使用者時降低延遲;同時也可能帶來寫入延遲、交易衝突、維運複雜度和資料駐留設計問題。

這篇文章關注 CockroachDB 多區域設計中的實際選擇:應該加入哪些區域、如何選擇表本地性、什麼時候用 regional by row、什麼時候用 global table,以及生產前應該驗證什麼。

參考文件:

最重要的設計問題

改 SQL 之前,先確認應用最需要什麼。

目標 設計方向 取捨
降低區域使用者讀取延遲 把資料放到主要讀取它的區域附近 跨區域寫入仍可能更慢
資料駐留 使用區域放置和明確的資料歸屬 Schema 和路由必須嚴格
全球參考資料 對讀多寫少的小表使用 global table 寫入通常需要更謹慎
區域故障容忍 選擇合適的 survival goal 和拓撲 更多副本和協調可能增加延遲
多區域活躍使用者 流量路由到近端區域,並建模資料歸屬 衝突寫入仍需應用處理

好的多區域設計從訪問模式出發,而不是只從地圖出發。

核心概念

CockroachDB 多區域抽象圍繞這些概念:

  • Cluster region:節點啟動時透過 locality 設定的區域。
  • Database region:加入到資料庫的區域,其中一個是 primary region。
  • Primary region:資料庫預設使用的區域,除非表本地性另有設定。
  • Table locality:CockroachDB 如何放置和優化表資料。
  • Survival goal:資料庫設計上可承受的故障範圍。
  • Secondary region:部分配置中用於故障切換相關的區域。

這些設定會影響效能和可用性,不只是部署標籤。

基礎多區域配置

多區域叢集從節點 locality 開始。每個節點應知道自己的 region 和 zone。

cockroach start \
  --locality=region=us-east-1,zone=us-east-1a \
  --certs-dir=certs \
  --join=node1:26257,node2:26257,node3:26257

然後配置資料庫區域。

ALTER DATABASE global_app SET PRIMARY REGION "us-east-1";
ALTER DATABASE global_app ADD REGION "eu-west-1";
ALTER DATABASE global_app ADD REGION "ap-southeast-1";

SHOW REGIONS FROM DATABASE global_app;

這不會自動讓所有查詢在所有地方都變快。它只是建立區域基礎。使用者能感受到的延遲,更多取決於表本地性和應用路由。

選擇表本地性

表本地性決定資料如何放置和優化。

Locality 適合場景 說明
Regional by table 整張表主要屬於一個區域 適合區域專屬表
Regional by row 不同行屬於不同區域 適合使用者、租戶或帳戶資料
Global 小型讀多寫少參考資料 讀體驗好,寫入要更謹慎

Regional By Table

當整張表主要屬於一個區域時,使用 regional by table。

CREATE TABLE eu_tax_rules (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    country STRING NOT NULL,
    rule JSONB NOT NULL
) LOCALITY REGIONAL BY TABLE IN "eu-west-1";

它適合區域配置、法律規則、本地目錄,或與某個地理區域綁定的營運資料。

Regional By Row

當每一行都有自己的 home region 時,使用 regional by row。使用者或租戶資料很常見。

CREATE TABLE users (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email STRING NOT NULL,
    home_region crdb_internal_region NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
) LOCALITY REGIONAL BY ROW;

應用必須正確設定並維護 home region。不要把區域欄位當成普通附屬欄位,它是資料模型的一部分。

Global Tables

global table 適合各地都要讀、但很少寫的小表。

CREATE TABLE countries (
    code STRING PRIMARY KEY,
    name STRING NOT NULL
) LOCALITY GLOBAL;

適合國家代碼、很少變動的功能開關、公共配置和參考資料。不要把高頻交易寫入表預設設為 global,除非已經測試過延遲和衝突行為。

有意設計流量路由

資料庫放置只是設計的一半。應用流量通常也應路由到最近的健康區域。

需要檢查:

  • 每個使用者請求由哪個應用區域處理。
  • 連線池是否連線到本地資料庫節點。
  • 讀取流量是否靠近使用者資料 home region。
  • 寫入是否送到擁有該行或租戶的區域。
  • 故障切換後,流量是否進入可以安全服務的區域。

如果歐洲使用者訪問歐洲應用伺服器,但該伺服器寫入 home 在美國的行,資料庫無法完全隱藏跨區域延遲。

處理交易衝突

多區域不會消除寫入歸屬設計。如果兩個區域頻繁更新同一行,仍可能出現重試和競爭。

降低衝突風險的方法:

  • 為每個租戶、帳戶或文件指定清晰寫入歸屬。
  • 避免熱點全域計數器。
  • 使用冪等命令和可安全重試的交易邏輯。
  • 縮短交易時間。
  • 將高寫入記錄拆成更小的歸屬單元。
  • 把讀多共享資料放進參考表。

Serializable 隔離很有價值,但應用仍然需要明確的重試策略。

資料駐留

如果有資料駐留要求,要明確哪些資料必須留在哪些區域:

  • 使用者資料。
  • 付款或帳單資料。
  • 日誌和稽核紀錄。
  • 備份。
  • 派生分析資料。
  • 搜尋索引和快取。

正確放置主表還不夠。副本、匯出、日誌、備份和下游系統也必須遵守同一策略。

Survival Goals

Survival goal 定義資料庫設計上要承受什麼故障。更高韌性通常需要更謹慎的拓撲,也可能影響延遲。

需要問:

  • 需要承受 zone 故障,還是完整 region 故障?
  • 有多少 region 和 zone 可用?
  • 哪些表在故障時仍必須可寫?
  • 目前 table locality 是否和相關特性相容?
  • 是否用真實應用流量做過故障切換測試?

在沒有測試之前,不要在架構文件裡承諾固定 RTO 或 RPO。

生產檢查清單

上線前確認:

  • 節點啟動時 region 和 zone 配置一致。
  • 資料庫 primary region 和 secondary region 是有意設計的。
  • 每張表按訪問模式選擇 locality。
  • regional by row 表有可靠的區域賦值。
  • 應用路由匹配資料歸屬。
  • 交易重試邏輯已經實作。
  • 備份和下游系統遵守駐留規則。
  • Schema 變更從合適區域執行。
  • 監控覆蓋延遲、重試、leaseholder 變化和 unavailable range。
  • 故障演練有文件並且會重複執行。

常見錯誤

把所有表都設成 Global

Global table 有用,但不是預設選項。它適合小型讀多寫少資料。高寫入業務表必須謹慎測試。

忽略應用層

如果應用流量沒有按區域路由,資料庫本地性無法完全解決延遲。

缺少重試邏輯

分散式 SQL 系統需要應用處理可重試交易錯誤。重試應明確,並且操作要冪等。

把資料駐留當成單表設定

資料駐留包括備份、日誌、分析、搜尋和匯出。要稽核完整資料流。

不做故障測試

多區域設計應在節點、zone 和 region 故障場景下測試。不要假設架構圖等於生產行為。

總結

CockroachDB 多區域設計的核心是取捨:讓資料靠近使用者、滿足駐留要求、承受故障,並保持寫入路徑可理解。先從訪問模式和資料歸屬開始,再選擇表本地性、配置區域、實作重試並測試故障切換。

目標不是「所有地方都 active-active」,而是在正常流量和區域故障時都有可預期的行為。

本站提供瀏覽器本地工具,免註冊即可試用 →

#CockroachDB多区域#多活数据库#全球分布式#Geo分区#2026#数据库