Boltdb學習筆記之〇--概述

後端技術小屋發表於2021-03-07

更多精彩內容,請關注微信公眾號:後端技術小屋

看了boltdb也有一陣子了,看完之後總想寫點什麼,因為感覺到這可能是個不小的坑,所以遲遲沒有動筆(沒錯我的拖延症又犯了..)。最近有一種流行的說法:如果一個東西不能把它講清楚,便不能說你學會了它。因為看起來會和真的會之間有一個巨大的鴻溝,想跨越這個鴻溝便需要不斷的提問、思考與輸出,這是個相對枯燥但絕對值得的過程,因此趁著週末兩天的完整時間正式開始挖坑。

什麼是boltdb

Boltdb是一個go語言開發的嵌入式kv資料庫。其實現相對簡單:

  • 不支援網路請求和SQL查詢,因此也就沒有了網路互動、詞法分析、語法分析、查詢優化等成熟資料庫中必不可少的功能。
  • 使用了比較少見的shadow page技術,只支援一個writer和多個reader,在這種約束下,事務的隔離級別為可序列話,併發控制也比較簡單
  • 使用mmap將記憶體與磁碟建立對映,由OS管理磁碟page load到記憶體的過程,大大減少了boltdb手動管理的複雜度。

Boltdb所有程式碼加起來才1W行,但是麻雀雖小五臟俱全,非常適合用來學習資料庫中的一些基本原理和概念,例如page、transanction、cursor等。

值得一提的是,Boltdb還是etcd底層的kv儲存,目前Boltdb原倉庫(https://github.com/boltdb/bolt)已經是read-only狀態。而etcd維護了一個fork(https://github.com/etcd-io/bbolt), 主要是為了繼續增強可靠性、穩定性和效能。

如何使用boltdb

資料模型

在使用boltdb之前,我們需要對其資料模型有個直觀的瞭解。以下是boltdb與關係型資料庫的資料模型簡單類比:

boltdb中的概念 關係型資料庫中的概念
DB database
Bucket table
key value pair Tuple

Boltdb中的Bucket雖然可簡單類比成關係型資料中table,有一點卻不相同:前者可巢狀建立Bucket, 即一個Bucket下還可建立子Bucket, 而後者不行。

安裝

go get github.com/boltdb/bolt/...  

操作DB

操作DB包括建立(開啟)、關閉。

程式碼如下:在執行bolt.Open時,如果指定檔案路徑不存在,則根據路徑建立一個資料庫檔案;否則載入該路徑下的檔案。使用db.Close便可關閉DB.

package main  
  
import (  
	"log"  
  
	"github.com/boltdb/bolt"  
)  
  
func main() {  
	// Open the my.db data file in your current directory.  
	// It will be created if it doesn't exist.  
	db, err := bolt.Open("my.db", 0600, nil)  
	if err != nil {  
		log.Fatal(err)  
	}  
	defer db.Close()  
  
	...  
}  

操作事務

Boltdb中按照是否只讀將事務分為讀事務和寫事務。

使用者使用db.View建立讀事務時需傳入一個回撥函式,表示讀事務執行操作。如果回撥函式返回的err != nildb.View則會回滾該事務,並將err透傳給db.View

err := db.View(func(tx *bolt.Tx) error {  
	...  
	return nil  
})  

使用db.Update可建立寫事務。db.Update如何處理錯誤同db.View

err := db.Batch(func(tx *bolt.Tx) error {  
	...  
	return nil  
})  

操作Bucket

操作Bucket包括建立Bucket、刪除Bucket

建立Bucket屬於寫事務。這裡db.Update會建立一個寫事務,寫事務執行的操作是CreateBucket,即建立一個新的Bucket

db.Update(func(tx *bolt.Tx) error {  
	b, err := tx.CreateBucket([]byte("MyBucket"))  
	if err != nil {  
		return fmt.Errorf("create bucket: %s", err)  
	}  
	return nil  
})  

刪除Bucket也屬於寫事務。使用上同理

db.Update(func(tx *bolt.Tx) error {  
	b, err := tx.DeleteBucket([]byte("MyBucket"))  
	if err != nil {  
		return fmt.Errorf("create bucket: %s", err)  
	}  
	return nil  
})  

操作key/value

操作key/value包括:新建/更新/刪除/查詢。所有的key/value對都必須屬於某個具體的Bucket. 因此操作key/value之前必須找到Bucket物件。

新建/更新程式碼必須用寫事務封裝,程式碼如下,這裡在名為MyBucket的Bucket下新增了一對("answer", "42")

db.Update(func(tx *bolt.Tx) error {  
	b := tx.Bucket([]byte("MyBucket"))  
	err := b.Put([]byte("answer"), []byte("42"))  
	return err  
})  

刪除程式碼如下:

db.Update(func(tx *bolt.Tx) error {  
	b := tx.Bucket([]byte("MyBucket"))  
	err := b.Delete([]byte("answer")  
	return err  
})  

查詢程式碼如下:

db.View(func(tx *bolt.Tx) error {  
	b := tx.Bucket([]byte("MyBucket"))  
	v := b.Get([]byte("answer"))  
	fmt.Printf("The answer is: %s\n", v)  
	return nil  
})  

如何分析Boltdb

程式碼導讀

首先是讀程式碼,從微觀到巨集觀的層面瞭解這座房屋如何建成的。程式碼閱讀順序是

page.go: 磁碟上的page layout,包括meta page, freelist page, branch page, leaf page。  
node.go: 磁碟上的page反序列化到記憶體之後的資料結構,也作為B+樹節點。  
freelist.go: page管理, 支援page申請、釋放、回滾等操作。  
cursor.go: 用於訪問B+樹的迭代器  
bucket.go: Bucket資料結構,支援建立/刪除子Bucket、新建/更新/刪除kv資料。  
db.go.go: 用於訪問DB, 支援開啟/關閉DB、建立讀/寫事務、db file自動擴容。  

更詳細的程式碼細節將在該系列的後續內容中給出.

分析工具

Boltdb提供了一個好用的工具,可用於檢視db file中每個page的內容

安裝:

git clone https://github.com/boltdb/bolt   
cd cmd/bolt  
go build  
ls ./bolt  

檢視所有pages狀態

$ ./bolt  pages  /tmp/bolt.db   | head  
ID       TYPE       ITEMS  OVRFLW  
======== ========== ====== ======  
0        meta       0              
1        meta       0              
2        freelist   4              
3        leaf       141            
4        leaf       86             
5        leaf       85             
6        branch     117            
7        leaf       85      

其中ID表示page id, TYPE為page型別,ITEMS表示其中的資料條數,OVRFLW表示該page是否溢位。

檢視某個page的內容

$ ./bolt  page /tmp/bolt-624750664  3  | head  
Page ID:    3  
Page Type:  leaf  
Total Size: 4096 bytes  
Item Count: 141  
  
"9874": "9874"  
"9875": "9875"  
"9876": "9876"  
"9877": "9877"  
"9878": "9878"  

以上為某個leaf page的內容,底部為該page中儲存的key/value對。

推薦閱讀

更多精彩內容,請掃碼關注微信公眾號:後端技術小屋。如果覺得文章對你有幫助的話,請多多分享、轉發、在看。
二維碼

相關文章