kudu設計-tablet

1. 邏輯組成

在這裏插入圖片描述

tablet

tablet是kudu表的一個水平分區,類似於Hbase的region概念。每個tablet包含一個連續主鍵範圍的記錄,不同tablet的鍵範圍不會有重疊,一個表的所有tablet就組成了這個表完整的鍵空間,充分利用kudu的分區功能,可以有效避免數據熱點問題。

RowSet

每個tablet由若干個RowSet構成,一個RowSet由一組行數據組成,對於給定一個key的那一行記錄,只會出現在一個RowSet裏面(MenRowSet或DiskRowSet)。但是RowSet的鍵空間不是連續的,所以不同RowSet的鍵空間範圍會有重疊,但鍵不會有重複。

mutation

對數據的插入、修改、刪除統一叫做mutation

MemRowSet

MemRowSet是一個按主鍵排序的內存B-tree(一行數據對應這個B-tree的一個entry,即一個MRSRow實例),數據插入時都會先進入MemRowSet,然後數據就對查詢可見了,而爲了維持快照的一致性(可以理解爲併發讀寫某行數據時候,可以讀到自己正確的快照數據),那麼就要求對每行數據的所有修改(叫做mutation)都需要保存下來,形成一個mutation鏈表,作爲該行的redo log。當內存滿後,MemRowSet會刷到磁盤中形成DiskRowSet,然後再創建新的MemRowSet。

DiskRowSet

MemRowSet刷到存盤形成DiskRowSet,而DiskRowSet真正存儲爲一系列的cfile;每個DiskRowSet中的每行記錄都會對應一個"rowid" (DiskRowSet有點像數組,"rowid"對應一個數組下標且對使用者不可見),"rowid"與主鍵之間會有一個映射關係:

  1. 當主鍵爲單列主鍵時,“rowid"其實就內置在存儲主鍵列的cfile中,主鍵是排序存儲的,所以每個主鍵默認對應着一個"rowid”,通過主鍵獲得"rowid",然後再從其它cfile快速定位其它列,這個就是所謂的主鍵索引
    在這裏插入圖片描述
  2. 當主鍵爲複合主鍵時,會有一個單獨的索引文件(index cfile)保存着編碼後的複合主鍵,這樣就可以像單主鍵提供一樣的功能。
    在這裏插入圖片描述

一行數據以列式格式儲存到不同的cfile,讀取一行完整記錄時,雖然要掃描多個cfile,但是具有有相同的rowid,所以還是可以快速地獲取到各個列的數據。

在邏輯上,每個DiskRowSet由三個部分組成,分別是:

在這裏插入圖片描述

Base data

MemRowSet刷到磁盤後形成的列式數據

UNDO records

可以對base data進行回滾到MemRowSet刷盤之前的歷史記錄

REDO records

數據刷新到磁盤後,對Base data所做的mutation集合 ,被應用於讀取更新版本的數據

落盤後Base data和REDO delta進行的Major compation會生成新的Base data和新的UNDO records

DeltaMemStore

是一個內存併發BTree,節點的鍵由rowid與mutation時間戳組合而成,當在讀取時,與MemRowSet中的mutation處理邏輯一樣。當DeltaMemStore大小到一定程度會被刷到磁盤形成DeltaFile,然後重置自己爲空。

DeltaFile

UNDO records 和 REDO records 存儲爲相同的文件格式,叫作DeltaFile,包含着一系列的mutation數據。

2. 讀寫過程

2.1 數據在MemRowSet中的讀寫

數據首次插入是會落到MemRowSet,隨後的更新、刪除、刪除後重新插入這些操作會有一個鏈表按時間順序把這些mutations保存起來,邏輯如下圖:
在這裏插入圖片描述

每個mutation都會標記一個時間戳,用來用爲MVCC的主要依據,當在tx時提交一個查詢,

  1. 如果tx<tx1,表示tx1還沒提交,會跳過該行數據
  2. 否則會把tx1時的行數據copy到scanner的緩衝區,然後遍歷mutation鏈表,找到所有時間戳小於tx(表示發生在查詢之前)的mutation與buffer中的行數據進行合併。

如果對單行更新得太頻繁,那麼每次在鏈表尾部插入mutation都是一個O(n)操作;另外讀取數據的時候要遍歷連接,這也會造成許多cpu緩存的丟失。

2.2 數據在DiskRowSet中的讀寫

2.2.1 更新過程:

數據刷新到磁盤後的修改刪除操作不會再進MemRowSet,而是執行如下步驟:

  1. 根據主鍵結合元數據和布隆過濾器快速定位到行記錄所在的DiskRowSet
  2. 尋找主鍵索引(index cfile)來確定行的rowid
  3. 然後mutation會進入DeltaMemStore,到時DeltaMemStore會刷到磁盤形成DeltaFile,所以DeltaMemStore和DeltaFile包含的內容相同,但是後者經過序列化壓縮得更緊湊,這些DeltaFile被稱作爲REDO files,而裏面的mutations被稱作REDO records

HBase中採用了非原地更新的方式,將更新操作和刪除操作轉換成插入一條新數據的形式,雖然這樣能夠較快的實現更新與刪除,但是將導致滿足指定rowkey,列族、列名要求的數據有多個,並且可能分佈在不同的storefile中。

2.2.2 讀過程:
  1. 當想要在MemRowSet刷新之後立即讀取最新版本的數據時,只需要掃描Base data即可
  2. 如果想對歷史記錄進行回溯查詢,那麼還是先讀取base data,然後根據當前掃描器的時間戳會找到一系列的UNDO records與base data合併恢復歷史的狀態。
    在這裏插入圖片描述
  3. 在數據落盤一段時間後,數據可能變更過,所以會產生DeltaFiles,這個時候的掃描除了讀取base data之外,還需要將REDO records進行合併得到新版本的數據
    在這裏插入圖片描述

3. RowSet內的Delta compaction

DeltaMemStore每次flush都會生成新的delta file,每次掃描都需要將delta文件與base data進行合併,讀取性能會越來越差,所以kudu會有後臺任務,負責將RowSet低效的物理儲存佈局轉換爲更高效的佈局,這個過程叫做“delta compactions”,主要分爲兩種類型

3.1 Minor REDO delta compaction

不涉及base data,主要是爲了減少delta文件數量
在這裏插入圖片描述

3.2 Major REDO delta compaction

除了可以減少delta文件數量之外,還能把REDO records轉爲UNDO records,因爲major需要讀取並重寫base data,而base data一般比delta data大得多,所以major任務比minor任務消耗更大的性能。
在這裏插入圖片描述

因爲兩種compaction都是發生在RowSet內,而RowSet內維護着rowid,所以可以完全獨立在後臺運行,而不需要對compaction目標數據進行鎖定,compaction後將結果與輸入數據進行原子交換,再把compaction前的文件刪除

4. RowSet之間的Merging compactions

隨着tablet的數據增加,DiskRowSet也會逐漸累積起來,對下面幾種情況會有性能影響:

  1. 隨機訪問(或根據主鍵更新),由於RowSet的鍵範圍可能會有重疊,所以需要查詢所有的RowSet鍵範圍來確定指定的鍵可能存在哪些RowSet,通過bloom filter可以有效的過濾一些RowSet而減少物理掃描,但是額外對bloom filter的訪問也會增加內存和cpu的消耗
  2. 範圍掃描,這種情況下,有重疊鍵範圍的RowSet都需要進行掃描,bloom filter不能像隨機訪問那樣有效進行過濾。
  3. 排序掃描,從各個RowSet掃描到目標數據後,需要將各個RowSet的掃描結果進行彙總合併排序,RowSet越多,這個過程就會越耗性能。
    在這裏插入圖片描述
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章