Distributed SQL / NewSQL

分散式 SQL:把關聯式資料庫拆成全球可擴展的系統

Distributed SQL 想保留 SQL、交易與一致性語意,同時取得水平擴展、高可用與跨區部署能力。它不是單純把 PostgreSQL 放進多台機器,而是把 Query Planning、Sharding、Consensus、MVCC 與 Clock/Timestamp 重新組合成一個資料庫系統。

category: Distributed SQL NewSQL Consensus MVCC
01

總覽與定位

Distributed SQL 的核心矛盾:SQL + ACID + Scale-out + 多區容錯,四者很難同時便宜取得。

傳統單機關聯式資料庫擅長複雜查詢、索引、Join、交易與強一致語意,但垂直擴展有上限;NoSQL 系統擅長水平擴展與高可用,卻通常要求你放棄部分 SQL 能力或交易語意。Distributed SQL / NewSQL 站在兩者中間:它把資料切成 Range / Tablet / Shard,使用 Raft 或 Paxos 複製每個分片,並在 SQL 層維持關聯式模型。

goal
保留關聯式開發體驗
SQL、Index、Transaction、Schema migration 仍是主要介面。
scale
用分片擴展容量
資料按 key range 或 hash 分散到多個 leaseholder / replica group。
correctness
用共識保護提交
每個分片的寫入先進入 Consensus log,再對外宣告 committed。
座標承接 Replication 與 Distributed Transactions

Distributed SQL 把「複寫一致性」與「分散式交易」產品化:Replication 決定單一分片如何複製,Transaction protocol 決定跨分片寫入如何一起提交,SQL layer 則把這些複雜度藏在查詢介面後面。

一句話答法Distributed SQL 是把 SQL/ACID 放到分片與 Consensus 之上,用水平擴展與多副本容錯換取更高的協調成本與尾延遲。
02

核心架構

一個 NewSQL 系統通常可拆成 SQL Gateway、Metadata、Range / Tablet、Consensus Replica 與 Transaction Layer。

面試時不要只說「它會自動 sharding」。更完整的架構回答應該說清楚:Client 連到哪裡、SQL 在哪裡被解析與規劃、資料如何定位到分片、寫入如何複製、跨分片交易如何協調,以及 metadata 變更如何被安全傳播。

SQL Gateway 負責連線、SQL parse、logical/physical plan、predicate pushdown、分散式執行計畫與結果合併。
Metadata 記錄 table 到 range 的映射、range boundaries、leaseholder、replica placement 與 schema version。
Range / Tablet 資料分片單位;通常依 key range 切分,熱點或容量過大時會 split,負載不均時會 rebalance。
Consensus Group 每個 range 有多個 replica,寫入需經 Raft/Paxos majority 才算 durable;leader/leaseholder 通常處理主要讀寫。
Txn + MVCC 用 MVCC snapshot、timestamp、lock table / intent 與 transaction record 支援 Serializable 或 Snapshot Isolation。
層級 主要責任 常見風險
SQL Layer 查詢規劃、Join 策略、下推計算 跨分片 Join 造成大量 network shuffle
Storage Layer Range split、LSM/B-Tree、secondary index 熱 key、索引寫入放大、compaction 抖動
Replication Layer Raft/Paxos、leader election、log replication 跨區 majority 讓 commit latency 被 WAN 主導
Transaction Layer 跨分片 atomic commit、timestamp ordering 高衝突 workload 造成 retry storm

架構重點:Distributed SQL 不是單一技術,而是多層協調機制的組合。

一句話答法回答架構時用「SQL Gateway → Metadata → Range/Tablet → Consensus Replica → MVCC Transaction」這條鏈路,能比單講 sharding 更完整。
03

分片、複寫與交易

Distributed SQL 的 correctness 成本,主要來自「一次 SQL 寫入可能同時碰到多個 Consensus group」。

單一分片寫入相對直覺:找到該 key 所屬 range,把 mutation 發給 leaseholder,經過 Raft majority 後 committed。跨分片交易則更難,因為每個分片都有自己的 consensus log;系統必須保證「所有分片都提交」或「所有分片都撤銷」,避免只更新訂單沒有扣庫存。

01 route Gateway 根據 key range 與 index 找到相關分片。
02 write intent 各分片寫入 provisional intent 或 prepare record。
03 commit record Transaction coordinator 決定全域 commit timestamp。
04 resolve 背景或同步清理 intents,讓後續讀取看到 committed value。
陷阱Consensus 不等於跨分片交易

Raft/Paxos 只保證單一 replica group 的 log 一致;跨多個 group 的 atomicity 仍需要 transaction protocol、timestamp ordering、conflict detection 與 retry。把「每個分片都強一致」誤認成「任意多分片交易都免費」是常見錯誤。

實務系統會努力把常見交易限制在單分片內,例如用 tenant_id 或 account_id 做 locality-aware primary key。當交易跨分片時,系統仍可保持 correctness,但 commit path 會穿越更多 replica group,latency 與 abort probability 都會上升。

一句話答法單分片寫入靠該分片的 Consensus;跨分片交易還需要 transaction coordinator 與 timestamp/intent 機制來保證 atomic commit。
04

時間戳與一致性讀取

全域排序是 Distributed SQL 的靈魂:讀寫要能回答「我看到的是哪個時間點的資料」。

Distributed SQL 常用 MVCC 讓同一筆資料保存多個版本,讀取以 timestamp 選擇可見版本。難點在於:多台機器沒有完美同步的時鐘,跨分片交易又需要一個能比較先後的 commit timestamp。不同系統會採用 TrueTime、Hybrid Logical Clock (HLC)、timestamp oracle,或透過 lease 與 uncertainty interval 限制時鐘不確定性。

機制 用途 代價
MVCC Snapshot 讀取某個 timestamp 前已提交的穩定版本 需要保存歷史版本並處理 GC / compaction
HLC / TrueTime 產生可比較的 commit timestamp 時鐘不確定性可能導致等待或重試
Follower Read 從本地副本讀較舊但一致的 snapshot 必須接受 staleness bound,例如讀 5 秒前資料
Serializable Retry 衝突時重跑交易以維持隔離語意 高爭用 workload 的尾延遲與應用複雜度上升
關鍵Follower Read 是 latency 工具,不是免費最新讀

跨區讀取可以從本地 follower 讀取已確定不會被未來寫入推翻的舊 snapshot;這能大幅降低 read latency,但產品必須接受 bounded staleness。若「付款完成後立刻看到最新狀態」是硬需求,仍要用 leader/leaseholder read 或 session token 保護。

一句話答法Distributed SQL 用 MVCC + 全域 timestamp 定義讀取視角;越想讀最新、越想跨區一致,就越需要付出等待、協調或重試成本。
05

互動:把一條 SQL 拆成分散式執行計畫

同一條語句,換個 key、換個切分、換個客戶端所在區,執行計畫與延遲組成就完全不同。

下方的拆解器不播劇本:它先用你給的 key 區間去對照 range 邊界,算出這條語句會落在哪幾個 Raft group,再逐階段攤開每一層做了什麼、花掉幾次跨區往返、哪些往返可以並行。三個最值得盯的翻轉:觸及一個 range 的寫入走 1PC、觸及兩個以上就必須走 2PC;扇出的多個 range 是並行的,關鍵路徑取最慢那一個,不是加總;Follower Read 是逐 range 判定的——同一條 scan 完全可能一半由本地副本服務、一半還是得跨區找 leaseholder。

互動 · SQL 執行計畫拆解器 改語句、key 區間、切分與副本擺放
語句型態
WHERE 起始 key 240
WHERE 區間寬度 180
表切成幾個 range 4
客戶端所在區
跨半圈 RTT 70 ms
副本擺放(3 副本)
Follower Read
SELECT …
拖動左側控制項,執行計畫會即時重算。

尺上的邊界是由「切分數」算出來的,不是畫死的;上方括號是 WHERE 的 key 區間,被它蓋到的 range 才會進入執行計畫。每段下方標的是實際服務者(F=本地 follower、L=leaseholder)。時鐘模型採 HLC,所以計畫裡沒有 commit wait;若換成 TrueTime,提交後還要多等一段 2ε 的 commit wait 才能回覆客戶端。

未觸及 range 本地副本服務 跨區 leaseholder 寫入(含 quorum 等待)

扇出那一列的細條是每個 range 各自的往返,它們共用同一段 x(同時發出),所以該階段的長度是取最慢的一條,不是把它們加總。虛線框的 intent resolve 畫在總延遲右側,代表它是背景清理、不計入關鍵路徑,但仍然要花 RPC。扇出列裡的 quorum 等待,就是 Leader Election 與 Raft 篇談 commitIndex 要靠 majority ack 才能推進的那一段。

觀察重點:把區間寬度從 1 拉大到跨越切分邊界的那一刻,提交協定會從 1PC 翻成 2PC、計畫多出一段 transaction record 往返——這正是「跨分片交易貴在哪裡」的具體數字。

一句話答法Distributed SQL 的 request path 越跨分片、越跨區、越要求最新,就越容易被 Consensus、timestamp uncertainty 與交易重試主導延遲。
06

選型與風險

NewSQL 適合需要強語意與水平擴展的核心資料,不適合把所有資料庫問題都一鍵外包。

Distributed SQL 最適合的場景,是你同時需要 relational model、交易、一致性、高可用與資料量/地理範圍擴展。例如金融帳務、訂單狀態、庫存、身份與多租戶 SaaS metadata。但如果 workload 主要是 append-only analytics、超高吞吐 event ingestion、或可以接受 eventual consistency 的 key-value lookup,專用 OLAP、log system 或 NoSQL 可能更簡單。

適合選用 謹慎選用 設計提醒
核心交易資料需要 ACID 與 HA 大量跨分片 Join / aggregation 把 transaction boundary 與 partition key 一起設計
多區部署且需要自動 failover 每次寫入都要求全球同步低延遲 用 locality-aware schema 把常見路徑留在同區
團隊希望保留 SQL 生態 極端熱 key 或高衝突 counter 對熱點使用分桶、預聚合或重新建模
風險不要把 NewSQL 當成無痛水平擴展

如果 schema 沒有 locality 設計、交易任意跨租戶、或 secondary index 過多,Distributed SQL 會把問題從「單機容量」轉成「跨節點協調」。系統仍然正確,但 payload、latency 與 retry rate 可能快速上升。

面試標準回答框架

先說需求:資料量、交易語意、地理分布與 latency SLA。再說架構:SQL Gateway、Range sharding、Consensus replication、MVCC timestamp。最後說取捨:單分片快、跨分片慢,Follower Read 可降讀延遲但有 staleness,熱點與 retry 是主要風險。

一句話答法選 Distributed SQL 是選「強語意下的 scale-out」,不是選免費效能;成功關鍵在 schema locality、交易邊界、replica placement 與可接受的 staleness 設計。