gkvdb的介紹及設計
文章目錄
gkvdb是Go語言開發的基於DRH(Deep-Re-Hash)深度雜湊分割槽演算法的高效能Key-Value嵌入式資料庫,gkvdb是開源的、免費的,基於MIT協議進行釋出,專案地址:https://gitee.com/johng/gkvdb。gkvdb的使用方式極其簡單,可參考專案地址中的說明進行操作即可。為了保證gkvdb的高效能,除了使用簡單可靠的DRH演算法外,gkvdb的一些元件也進行了非常優秀的設計,本文主要對gkvdb的一些核心元件進行簡單的介紹。
單資料檔案
單資料檔案設計的目的是為提高在機械磁碟下的隨機資料讀寫效能問題,gkvdb資料庫只有4種檔案:binlog、xxx.ix、xxx.mt、xxx.db
其中binlog為資料庫日誌檔案,ix為資料表索引檔案,mt為資料表元資料檔案,db為資料表資料存放檔案。ix和mt檔案對應DRH演算法中的節點,db檔案對應DRH中的資料層。
鍵名最大長度為255位元組,鍵值最大長度為16MB,資料庫預設支援的資料庫大小為1TB,和資料大小有關係,例如,如果鍵值對長度為1KB,那麼支援的資料量為1024x1024x1024=1073741824,約為11億。
單資料檔案除了便於管理以外,對於提升磁碟IO效能也是極大的。在所有基於磁碟的資料庫設計中,影響效能的因素,除了演算法設計,往往就是磁碟IO,特別是在訪問量大的情況下將會更加明顯(當然同一檔案的鎖操作影響也會比較大)。
binlog日誌
binlog是介於介面層與底層資料庫檔案之間的日誌層,用於資料更新到資料持久化之間的緩衝,提升介面層的響應效率,是事務功能的基礎,並保證資料庫的高可用。所有的更新操作必須先寫入binlog檔案成功後,才算是成功,寫入失敗或者只寫入了操作的部分資料,都算是操作失敗。例如:批量寫入100條資料,如果在寫入的過程中系統異常斷電,造成只寫入了99條,那麼該批資料都算是寫入失敗,這批資料將不會被同步到底層資料庫檔案中。
此外,需要說明的是,gkvdb的binlog和mysql的binlog不同,不會保留所有的操作日誌,當binlog成功持久化到底層資料庫檔案之後,對應的日誌內容將會被清除。gkvdb被設計為是一個可嵌入式的單節點KV資料庫,保證簡單性、實用性及高效能,gkvdb本身不提供主備功能,如果想要支援資料庫主備或者多節點的資料庫支援,請參考
事務功能
gkvdb的所有資料更新操作,都是按照事務來實現,即使是一條單獨的資料寫入/刪除操作。
當一個事務開始後,所有的事務操作都是基於記憶體,直到事務Commit之後,才會真實地寫入到binlog中;反之,如果執行事務Rollback,那麼事務的資料將會在記憶體中被清除,沒有真實地提交到binlog中,也便不會有記錄。
binlog日誌是事務功能的基礎,同時binlog中的日誌存放,也是以事務為單位進行存放,日誌檔案格式如下:
1234 | [是否同步(8bit)資料長度(32bit)事務編號(64bit)]--事務開始[表名長度(8bit)鍵名長度(8bit)鍵值長度(24bit,16MB)表名鍵名鍵值](變長,當鍵值長度為0表示刪除)...[事務編號(64bit)]--事務結束 |
同一個操作的操作列表被包含在一對事務編號中間,也就是說,如果一個事務想要執行成功,必須按照這樣的格式寫入到binlog中,前後缺少一個字元都不行。當資料異常的情況下(資料不完整),整個事務操作都將會被忽略掉,binlog會自動定址到下一條事務進行同步。其中,“是否同步”的標誌位表示該事務資料是否已經同步到底層資料庫檔案,如果為0,表示未同步,那麼非同步執行緒將會自動將此資料同步到底層資料庫檔案中,並標識該標誌位為1。當所有的binlog資料的同步標誌位都為1的時候,binlog資料將會被清除。
資料更新操作圖例
空間管理器
在單資料檔案的設計中,離不開碎片的存在,碎片是指當磁碟檔案中的一段內容被刪除,或者內容修改時原有地址空間不足引起地址重新分配時,原有地址的空間沒有地方再引用,便成為了碎片(有點類似GC,可以將空間管理器看做基於檔案的GC)。gkvdb設計了一個專門的檔案空間管理器,來回收和再分配這些碎片,並且gkvdb的空間管理器可以對較小的碎片進行自動地合併,對於較大的碎片按需進行拆分。gkvdb的空間管理器的計算是基於記憶體的,底層採用了B樹進行索引(後期考慮替換為跳錶實現),效率相當高。gkvdb資料庫在初始化的時候會重新計算碎片,保證檔案空間的充分利用。
空間整理器
舉個例子:比如刪除了若干鍵值對後,造成了5000MB的碎片,後續繼續分配時也無法充分利用完這些碎片,因此這些碎片會繼續佔據磁碟空間,造成磁碟空間的浪費。
這個時候,就需要空間整理器來處理了,空間整理器相對空間管理器來說是獨立的,專注於不同的職責。針對於大型的檔案碎片,空間整理器會將資料進行自動遷移,使得檔案中的資料靠前緊湊,將碎片往檔案末尾遷移,最後進行truncate矯正檔案大小,以達到整理碎片的目的。
空間整理器是非同步進行的,針對空間大小超過1KB的碎片進行處理。
檔案指標池
檔案指標池和資料庫連線池比較類似,是基於IO複用的一種設計。
一般的檔案操作過程是這樣的:當檔案被開啟之後,會建立一個檔案指標,在檔案操作結束後,檔案指標就會被立即關閉掉。
這樣的話,在每一次操作或者請求中,對檔案的操作都會反覆建立/關閉指標,這樣產生的問題是:一個是操作效率比較低,另一個是系統的最大檔案開啟數是有限的,在檔案操作頻繁/訪問量大的情況下,會影響整體系統的執行效率(檔案鎖,資源競爭),甚至引發一些嚴重的問題。檔案指標池對於同一個檔案在非同步高併發下的讀取效能提升非常大(因為讀取不需要鎖,每一個協程一個檔案指標),但是對於寫入效能的提升不大,因為檔案寫入往往都必須加鎖以保證資料寫入的順序性。
在gkvdb中,對於同一個資料檔案,會有一個專門的檔案指標池,當檔案指標使用完畢之後會立即放回到這個池中,下一次使用的時候從池中獲取,免去了反覆建立/關閉指標的效能開銷。如果訪問量大的情況下,池中的檔案指標不夠時,也會建立新的檔案指標,使得池的容量不斷增加,沒有上限。
當然,如果池中的檔案指標在一段時間閒置後,會被自動關閉掉,預設閒置時間為60秒。