概述
-
CockroachDB是一個分布式關系型數據庫,主要設計目標是可擴展,強一致和高可靠。
-
在無人干預情況下, 能以極短的中斷時間容忍磁盤、主機、機架甚至整個數據中心的故障。
-
采用完全去中心化架構, 集群中各個節點的地位完全對等。
-
所有功能封裝在一個二進制文件中, 可以做到盡量不依賴盤配置文件直接部署。
-
對外提供標准SQL接口,集群中任意節點都可以作為接入節點處理用戶的SQL請求。
- 接入節點把SQL請求轉換為KV操作,並且在必要時將該操作發送至其它節點進行處理,完成后將結果返回給客戶端。
- CockroachDB底層將數據組織成有序的Key-Value對形成一個KV map,其中Key和Value均為字節串。
- KV map邏輯上按照范圍被切分成大量的Key空間,每個Key空間稱為Range。
- 每個Range數據由本地KV存儲引擎(RocksDB,LevelDB的變體)存儲。
- 每個Range被復制多份分布到多個CockroachDB節點上,Range副本數量可配置。
- 每個Range默認大小為64M,合理的Range大小有利於加速節點故障恢復和擴容,及均衡讀寫負載。
- Range大小應該根據系統壓力進行設置,以便管理更多Range。
-
支持水平擴展
- 添加更多節點可以提升整個集群的存儲容量, 理論上最大可以支撐4EB的數據存儲
- 客戶端的查詢請求可以發送到集群任意節點, 且每個查詢可獨立並發執行, 集群的吞吐能力可以隨着節點數的增加線性提升。
- 查詢以分布式任務的方式在各個數據節點並發執行,可以通過增加節點數來提升單個查詢的性能。
-
支持強一致性
- Range的多個副本之間使用Raft一致性協議, 所有一致性狀態都存儲在RocksDB中。
- 對同一個Range內數據的單一或批量修改, 由Raft保證Range操作的ACID語義。
- 涉及多個Range的操作, CockroachDB使用高效的無鎖分布式事務保障ACID語義。
-
支持高可用
- 將Range副本分布在一個數據中心, 可以確保低延遲復制, 同時能容忍磁盤或機器故障。
- 如果將副本分布在不同機架, 即使某些網絡交換機故障, CockroachDB仍可提供服務。
- Range副本可以跨數據中心和跨地域分布, 以應對來自數據中心電源中斷或網絡中斷, 以及區域電力故障等問題。
-
隔離級別
-
基於歷史快照時間和當前時間, 提供外部一致的無鎖讀寫。
-
快照隔離(SI) [Snapshot Ioslation]
- SI提供無鎖讀寫, 但是存在寫偏序問題(write skew)
-
串行快照隔離(SSI) [Serializable Snapshot Isolation]
- SSI消除了寫偏序, 但在競爭激烈的系統中會存在性能問題
-
SSI是默認的隔離級別, 用戶須根據實際性能情況, 選擇合適的隔離級別。CockroachDB只提供有限的linearizability(嚴格的順序一致性)。
-
架構
-
架構圖
-
采用分層架構
-
SQL層
- CockroachDB支持標准SQL, 當CockroachDB集群的某個節點收到SQL請求時,會經過SQL解析、SQL執行計划生成、SQL執行等重要步驟。
- CockroachDB兼容PostgreSQL協議,對於報文的封裝和解析完全按照PostgreSQL的方式進行,所以用戶可以直接使用PostgreSQL的客戶端訪問CockroachDB。
- CockroachDB對於用戶的SQL語句按照PostgreSQL的語法進行解析,解析完成后生成抽象語法樹(AST)
- CockroachDB 會根據不同的語法樹生成對應的執行計划。目前執行計划基本是基於規則的方式來生成的。
- 對於OLAP的SQL Statement, CockroachDB會將邏輯計划轉化為物理執行計划,即通過分布式任務的方式進行並行執行。
- 當執行計划生成完畢后,CockroachDB會按照約定的方式開始執行,此時CockroachDB將調用事務性的KV接口。執行完成后通過協議層將執行結果返回給客戶端。
-
分布式KV存儲
-
負責Range路由尋址,提供統一的key-value存儲。
-
可以由任意數量的CockroachDB物理節點組成,每個節點包含一個或多個Store(通常一個Store獨占一塊磁盤)
-
每個Store包含多個Range,Range為KV層數據管理的最小單元,每個Range的多個副本之間使用Raft協議進行同步
-
Range示意圖
- 這個其實可以類比下hdfs的分片和elasticSearch的分片, 思想上都是相似的。
- 節點和Range可以根據不同的物理網絡拓撲結構進行編排,從而在可靠性和性能之間折衷。
- 假設一個Range包含三個副本,每個副本可以位於不同的位置:
- 如果副本分布於同一台服務器上的多塊磁盤,可以容忍單塊磁盤故障。
- 如果副本分布於同一機架上的不同服務器,可以容忍單台服務器故障。
- 如果副本分布於同一個數據中心不同機架,可以容忍單個機架電源和網絡故障。
- 如果副本分布於不同數據中心,可以容忍大規模網絡中斷或斷電。
-
關鍵字
-
CockroachDB key可以是任意字節數組
-
key有兩種類型:系統表key和用戶表key
- 系統表key被CockroachDB用於內部數據結構和元數據。用戶表key包含用戶表數據(以及索引數據)
- 系統表key和用戶表key通過前綴區分,並保證系統表key始終小於用戶表key
-
系統表key有以下幾種類型:
- Global key存儲集群級別的數據,例如“meta1”和“meta2” ,以及系統級別的key,例如節點和Store 的ID標識。
- Store local key用於標識該Store的本地元數據(例如,StoreIdent結構),該部分元數據與所處Store生命周期相關,因此無需復制,即不會通過Raft同步到其它Store。
- Range local key存儲Range的元數據,並與Global key(實際存儲層的全局Key)相關聯。Range local key由一個特殊前綴,加Global key及一個特殊后綴組成。例如,事務記錄是Range local key,形如: \x01k
txn- 。 - Replicated Range ID local key存儲Range元數據(RangeDescriptor),該元數據包含Range所有副本的元信息,這些元數據的變更會通過Raft同步。例如Range lease狀態和事務的abort緩存記錄。
- Unreplicated Range ID local key存儲該Range副本的元數據,例如Raft狀態機的狀態信息以及持久化后的Raft日志。
-
用戶表key用於存儲所有非系統數據
多版本數據
-
CockroachDB維護了數據的歷史版本,版本之間通過事務的提交時間戳區分。
-
指定快照時間可以讀取此時間戳之前的最新版本數據。
-
所有版本都有一個最小有效期,當系統進行compaction時,過期的版本數據會被系統回收。
-
為了防止長時間數據掃描(例如MapReduce)中歷史數據被清理,用戶也可自行指定數據有效期。
-
通過RocksDB存儲每個key的提交時間戳和GC有效期,支持多版本數據。
無鎖分布式事務
- CockroachDB提供無鎖分布式事務
- 支持的兩種事務隔離界別
- 快照隔離級別(SI)
- 隔離級別實現簡單,性能較好, 但是存在write skew 問題。
- 串行化快照隔離級別(SSI)
- 實現上稍微復雜一些, 但仍然能保證較高性能 (讀寫沖突嚴重的情況下稍弱), 但是不存在write skew問題。
- 快照隔離級別(SI)
- 默認使用SSI隔離級別
- 在對性能要求較高,並且沒有write skew的情況下可使用SI隔離級別。
- 在沖突較少的情況下,SSI和SI性能相當,不需要加鎖或額外寫操作。
- 在沖突激烈的情況下,SSI仍然不需要加鎖,但是會有更多事務被終止。
- 在任何長事務場景中,SI和SSI都能防止事務餓死。
- SI和SSI之間的核心區別在於事務提交時,SI允許事務的候選時間戳變大,而SSI不允許。
- SI和SSI都要求緩存該Range上發生的讀操作結果
- 如果寫操作時間戳比最近一次讀操作時間戳要小, 則寫操作失敗。
- 每個Range都有一個緩存 (timestamp cache), 保存該Range中key被讀取的最新時間戳。
- 讀操作會更新相應的timestamp cache, 部分寫操作 (例如Range刪除) 也會更新timestamp cache。
- timestamp cache中最老時間戳會被優先剔除。
- 每一個CockroachDB事務開始時都會分配一個隨機優先級和一個“候選時間戳”。
- 候選時間戳是接收事務請求時節點分配的本地當前時間戳 (HLC), 作為事務提交的臨時時間戳。
- 如果沒有事務沖突,在事務完成所有操作后,該時間戳會成為事務的最終提交時間戳。
- 在跨多個節點的分布式事務執行過程中, 候選時間戳可能會變大, 但不會回退。