bolt:一個純Go實現的KV數據庫

簡介

bolt是一個純go語言實現的鍵值數據庫,支持完全的ACID實務操作,儘管不像SQLite那樣有完善的查詢語言,但是接口簡單易用。bolt本身通過使用一個內存映射的磁盤文件來管理數據,邏輯清晰,接口簡單易用。下面代碼就是bolt提供的簡單的操作接口示例。

  db, err := bolt.Open("example.db", 0600, nil)
  if err != nil {
    log.Fatal(err)
  }
  defer db.Close()

  // 當傳遞的函數中返回了error,bolt將會自動的執行
  // rollback操作,不需要手動執行任何操作
  err := db.Update(func(tx *bolt.Tx) error{
    // ...
  })

  // 只讀的實務操作定義在db.View函數中,僅僅可以讀取
  // 和迭代數據
  err := db.View(func(tx *bolt.Tx)error{
    // ...
  })

bolt設計靈感來源於LMDB(一個輕量級的內存映射數據庫)。LMDB本身可以提供高性能的讀操作和線程安全的寫入操作,並且支持ACID實務操作,bolt早期僅僅打算做成一個Go版本的LMDB,但是如今已得到越來越多的關注github的star數量也突破了7000。

一些常見的關係數據庫,比如MySQL以及Postgres這些數據庫,提供對於結構化數據的存儲以及SQL語句的支持,可以靈活的查詢和存儲數據來滿足業務的需求,但是解析和處理SQL層也會帶來很大的開銷。bolt所有的數據訪問都是通過鍵來完成,基於B+樹存儲結構的設計使得讀寫數據效率較高。同時常規數據庫往往與程序分離部署,通過網絡序列化完成傳遞,也會增加一部分處理延遲和降低處理效率。bolt通過一個文件來存儲數據,儘管訪問問題上不是足夠靈活,但是效率較高。

LevelDB,也屬於一個鍵值數據庫,Google開源C++語言實現。提供一個排序的數據存儲結構,但是不支持實務操作,通過LSM樹來存儲鍵值數據到,支持高效的隨機寫入但是對於讀取效率不高,特別是當數據的容量越來越大的時候。如果對於讀取效率要求比較高,可以考慮使用bolt來進行測試。 ·

代碼實例

Bolt的鍵值數據對存儲在一個有序的map結構中,由於是有序的因此可以獲得穩定的迭代數據,另外bolt定義了bucket的結構,類似於一堆鍵的集合或者類似於數據庫的表,另外可以在bucket中存儲其他的buckets。如下是一個簡單的存儲和查詢的流程

err = db.Update(func(tx *bolt.Tx) error {
  b, err := tx.CreateBucketIfNotExists([]byte("posts"))
  if err != nil {
    return err
  }
  return b.Put([]byte("2017-11-20"), []byte("new post"))
})

err = db.View(func(tx *bolt.Tx) error {
  b := tx.Bucket([]byte("posts"))
  v := b.Get([]byte("2017-11-20"))
  fmt.Printf("%s", v)
  return nil
})

如果需要存儲一個複雜的數據結構比如自定義的結構體數據則需要調用一些序列化的函數來獲得編碼後的數據存儲,比如使用json.Marshal來編碼:

type User struct {
  Name string `json:"name"`
  Address string `json:"address"`
  Age int `json:age`
}
…

  err = db.Update(func(tx *bolt.Tx) error {
    b, err := tx.CreateBucketIfNotExists([]byte("users"))
    if err != nil {
      return err
    }
    encoded, err := json.Marshal(user)
    if err != nil {
      return err
    }
    return b.Put([]byte(user.Name), encoded)
  })

  err = db.View(func(tx *bolt.Tx) error {
    b := tx.Bucket([]byte("users"))
    v := b.Get([]byte("mike"))
    user := new(User)
    err := json.Unmarshal(v, user)
    if err != nil {
      return err
    }
    fmt.Printf("%+v", user)
    return nil
 })

另外bolt提供命令行工具來完成對於數據庫狀態的檢查和測試。
Usage:

bolt command [arguments]

The commands are:

bench       run synthetic benchmark against bolt
check       verifies integrity of bolt database
compact     copies a bolt database, compacting it in the process
info        print basic info
help        print this screen
pages       print list of pages with their types
stats       iterate over all pages and generate usage stats

bolt儘管API比較簡單,但是實現較爲優雅,很多大的企業在內部使用bolt來存儲一些業務數據。如果有一些對於讀要求較爲高的應用可以考慮測試一下bolt的使用效果。

另外注意的是:對於bolt來說存儲的文件由於是內存映射的對象存儲內容,因此是大小端敏感的,可能會導致拷貝到特定的機器上不能正常使用。不過大部分的用戶使用現代的CPU來說是小端存儲,因此問題不大。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章