天天看點

java實作資料庫引擎,Key/Value儲存引擎——Bitcask的Java實作

Key/Value存儲引擎——Bitcask的Java實作

在關系資料庫存儲上,Btree一直是主角,但在讀寫性能要求更高的場景下,log(n)的讀寫操作并不是總是讓人滿意。 Bitcask是一種連續寫入很快速的Key/Value資料存儲結構,讀寫操作的時間複雜度均為常量。它是怎麼做到的呢?

BitCash連續寫入操作

Bitcask具有高效的連續寫入操作,連續寫操作像是不停的向log檔案append message,是以Bitcash也叫Log結構存儲。

BitCash中一個記錄由兩部分組成:

記憶體中的HashMap用來儲存索引索引

磁盤檔案存儲資料

當有資料需要寫入時,磁盤無需周遊檔案,直接寫入到資料塊或者檔案的末尾,避免了磁盤機械查找的時間,寫入磁盤之後,隻需要在記憶體的HashMap中更新相應的索引,記憶體中用HashMap來儲存一條記錄的索引部分,一條索引包含的資訊如下:

[Key: Jason, Filename: employee.db, Offset:0, Size:146, ModifiedDate:2343432312]

[Key: Bill, Filename: employee.db, Offset:146, Size:146, ModifiedDate:5489354345]

Key表示一條記錄的主鍵,查找通過它在HashMap中找到完整索引資訊

Filename是磁盤檔案名字,通過它和Offset找到Value在磁盤的開始位置

Offset是Value在檔案中偏移量,通過它和Size可以讀取一條記錄

Size是Value所占的磁盤大小,機關是Byte

假設目前資料庫中已有上述兩條的記錄,當我要寫入key為 "Jobs", value為: object的一條新記錄時, 隻需要在檔案employee.db的末尾寫入value=object,在HashMap中添加索引:[Key: Jobs, Filename: employee.db, Offset:292, Size:146, ModifiedDate:9489354343] 即可。

最後資料庫就包含了三條索引資訊:

[Key: Jason, Filename: employee.db, Offset:0, Size:146, ModifiedDate:2343432312]

[Key: Bill, Filename: employee.db, Offset:146, Size:150, ModifiedDate:5489354345]

[Key: Jobs, Filename: employee.db, Offset:294, Size:136, ModifiedDate:948965443]

BitCash随機讀取操作

由于資料在記憶體當中使用HashMap作為索引,查找索引的時間為常量,比如查找Bill,直接通過Key就可以找到它的索引資訊,再根據索引資訊,找到value在檔案位置和大小,精确讀取出bytes,反序列化成value對象。 當然在value存入檔案時需要序列化記憶體對象成bytes。磁盤讀取的過程的時間複雜度也是常量, 并不會随時資料的增大而增大。

BitCash 資料删除和更新

一條記錄包含了索引和資料兩個部分,删除索引容易,但要徹底的删除資料不是件容易的事情(不讨論,參考磁盤空間整理)。對于更新資料,Bitcash通常采用的政策是append一條新資料,并更新已有的索引,至于舊資料則在清理資料的時候把它删除掉。

BitCash适合的場景

适合連續寫入,随機的讀取,連續讀取性能不如Btree

記錄的key可以完全的載入記憶體

value的大小比key大很多,否則意義不大

key/value存儲結構

BitCash Java 實作

代碼:https://github.com/darlinglele/bitcask