2.4 分佈層
CockroachDB結構爲集羣提供了統一的view。
**概要
--monolithic sortedmap結構
--使用monolithic sorted map(龐大的sorted map)
--與其他層的交互
**技術細節和組件
--gRpc
--BatchRequst
--DistSender
--元range KV 結構
--表數據KV結構
--range描述符
--range分裂
**與其他層的交互
--分佈層和事務層的交互
--分佈層和複製層的交互
2.4.1 概要
爲了保證集羣中的所有數據可以被所有節點訪問,cockroach數據以KV鍵值對形式存儲龐大的 sorted map中,這些key空間描述了集羣中所有數據及其位置,將數據分爲ranges。Ranges是key空間臨近的chunks,每個key總是被包含在一個range中。
Cockroach實現sorted map 通過:
--簡單的查找:節點包涵某一部分數據,query可以快速的定位他們想要的數據
--高效的掃描:定義數據的順序,通過掃描可以發現數據具體的range。
**Monolithicsorted map 結構
Monolithic sortedmap結構由兩個基本的組件組成
--系統數據,包括元ranges 描述了集羣中數據的位置(其他的集羣範圍和本地數據元素)
--用戶數據,存儲集羣的表數據
元ranges
集羣所有range的位置,存儲在key空間的兩個級別的索引中,即元ranges,第一個級別(meta1)指向第二級別,第二級別(meta2)指向集羣中的數據。每個節點被告知在哪裏定位meta1 range(即range 描述符,具體細節如下)。Range不會被拆分。
元range結構默認尋址4EB(1EB=1024PB,1PB=1024TB)的數據,可以尋址2^(18+ 18) = 2^36 ranges,每個range尋址 2^26 B,綜上, 2^(36+26) B = 2^62 B = 4EB,對於更大的range大小,我們可以在未來擴展它的能力。
元數據與其他正常的range處理相似,像集羣中的KV數據的其他元素
一樣,被訪問和複製。
Meta2 range緩存每個節點的已取過的值,用於優化未來的訪問。無論何時一個節發現meta2緩存是無效的,通過在meta2 range上定期的讀更新緩存。
表數據
在集羣中節點存儲的元數據是KV數據,這個數據被分成64MB的相鄰的連續key空間,即ranges。這個大小足夠小使節點之間可以快速移動, 也足夠大存儲有意義的可能被同時訪問的連續數據,是一個合適的值。這些ranges在集羣中清洗,保證集羣的耐受性。
這些range被複制(在複製層),每個複本的地址存儲在meta2 range中。
**使用monolithic sorted map(龐大的sorted map)
當節點接受到請求,通過比較請求中元ranges的keys與自己meta2range,查找將請求路由到哪個節點。
這些meta range大量的被緩存,所以很容易獲得,不需要向實際meta2 ranges節點發送RPC。
節點將這些KV操作發送給meta2 range的租戶。不過有可能發生,當數據移動,節點不再告知請求節點,數據現在存儲的位置。這種情況下,將回到meta2 range獲取最新信息,再重試。
**與其他層進行交互
與分佈層相關聯的其他層:
--在相同節點接受來自事務層的請求
--識別哪個節點可以接受請求,將請求發送到正確的複製層節點。
2.4.2 技術細節和組件
**gRPC
gRPC是與其他節點交流的一個軟件節點,分佈層是與其他節點交流的第一層,Cockroach在這裏實現了gRPC。
gRpc需要輸入輸出使用potocol buffers(protobufs)格式化,爲租用Grpc,cockroachDB實現了protocol-buffer-based API(基於緩衝協議的API)定義爲
api.proto
.
更多信息,查看gRpc的官方文檔。
gRpc是一個客戶端直接調用不同機器的服務端的方法,就像他是個本地客戶端,使創建分佈式應用和服務更加容易,在很多RPC(remote procedure call,遠程過程調用)系統中,gRpc基於定義服務思想,識別方法,該方法可以使用參數被遠程調用,並返回類型值。在服務器端,服務器實現這個接口,運行gRpc服務處理客戶端調用。在客戶端端,客戶端具有一個存根提供與服務端同樣的方法
GRpc客戶端和服務端在不同的環境中彼此可以運行和交流,可以使用java創建一個GRpc的服務端,客戶端使用go,python,ruby語言。可以獲取最近的google api獲得最新的實現。
potocol buffers
https://developers.google.com/protocol-buffers/docs/overview
potocol buffers CSDN(非官方文檔)
http://blog.csdn.net/manchew/article/details/39494901
**batchRequest
所有的KV操作輸入protobuf,叫做batchRequest.Batch的目標是被batchRequest頭識別,同時是一個請求的事務記錄的指針,在其他方面,一個節點使用batchRequest,調用protobuf,獲得batchResponse。
**DistSender
網關或者合作節點的DistSender接受到來自自己的TxnCoordSender的batchRequest。DistSender應答,解析batchRequests,並將通過meta2 range將一個新的batchRequests請求集路由到實際包含數據的節點。使用緩存發送請求給租戶,也會準備好去嘗試其他的副本,按照“鄰近”順序。緩存的副本是租戶,租戶在副本集list裏向前移動,並按順序向所有副本發送RPC。
請求收到非租戶失敗,直到副本的最後一個已知租戶返回一個失敗指針。
網關節點使用明顯更新的租約重試請求,不會到達客戶端。所有的節點開始依賴於這些命令,DistSender收集準備結果返回給客戶端。
**元range KV結構
像集羣中的其他數據一樣,metarange使用KV鍵值對構建他的結構,meta range都具有相同的結構
metaX/successorKey ->LeaseholderAddress, [list of other nodes containing data]
元素 |
描述 |
metaX |
Mata range級別,我們簡單使用meta1或者meta2,但是實際在cockroach分別爲是\x02和\x03 |
successorKey |
第一個比掃描到key更大的key,使cochroachDB的掃描是高效的,簡單的掃描keys直到發現一個值更大的key,獲取相關數據的位置。對於keyspace的末尾,successorKey即爲maxKey |
LeaseholderAddress |
副本主要負責讀寫,叫做LeaseholderAddress,複製層更多信息,請查看Leases |
例如
meta2/M-> node1:26257, node2:26257, node3:26257
在這種情況下,node1的副本是租戶,node2和node3同樣包含副本。
在這種情況下,node1的副本是租戶,node2和node3同樣包含副本。
例如:
想象我們有一個按照字母順序排序的列,我們使用去查詢,metarange數據類似:
1)Meta1 包含存儲meta2副本的節點地址
# Points to meta2 range for keys [A-M)
meta1/M -> node1:26257, node2:26257, node3:26257
# Points to meta2 range for keys [M-Z]
meta1/maxKey -> node4:26257, node5:26257, node6:26257
2) meta2包含集羣中每個range副本的位置,第一個是Leaseholder.
# Contains [A-G)
meta2/G -> node1:26257, node2:26257, node3:26257
# Contains [G-M)
meta2/M -> node1:26257, node2:26257, node3:26257
#Contains [M-Z)
meta2/Z -> node4:26257, node5:26257, node6:26257
#Contains [Z-maxKey)
meta2/maxKey-> node4:26257, node5:26257, node6:26257
**表的數據的KV結構
KV數據,表中數據使用如下結構:
/<tableId>/<index id>/<indexed column values> -><non-indexed/STORING column values>
表本身存儲1的index_id作爲主鍵列,表中剩下的列爲存儲/覆蓋列。
**Range描述
CockroachDB的每個range包含元數據,即range描述符。一個range描述符由如下組成:
--一個時序的rangeID
--range包含的key空間(key集)。例如,在表數據的KV結構中,第一個和最後一個<index column values> ,這個決定了meta2 range的key。
--節點的地址包含range的副本,它的leaseholder(負責讀寫)的第一位置。這決定了meta2 range key的值。
因爲range描述比較meta2 range的KV數據,每個節點的meta2緩存也存儲range描述。
Range描述更新:range的raft成員更改(具體的細節在複製層討論)—leaseholder改變—range分裂
所有的range描述更新發生在本地range,然後擴散到meta2 range。
**range分裂
默認,cockroachDB保存ranges或副本在64MiB中,一旦range達到限制將分裂成2個32MB的ranges(由連續的key空間組成)
在range分裂,節點創建一個新的raft group與被分裂的range相同的成員。事實上,兩個range意味着事務升級到meta2,使用新的表空間邊界,使用range描述的節點地址。
2.4.3 與其他層的交互
**分佈層與事務層
分佈層的DistSender接受到它自己節點的TxnCoordSender發送的BatchRequests
封裝在事務層
**分佈層與複製層
分佈式層路由BatchRequests到包含數據range的節點,最終路由到raft group leader 或者leaseholder,在複製層處理