Badger簡介
badger 是 dgraph 開源的 LSMTree 的 KV 引擎,它相比 leveldb 有 KV 分離、事務、併發合併等增強,是 go 生態中比較生產級的儲存引擎了。
文件:https://dgraph.io/docs/badger/get-started/
Github 地址:https://github.com/dgraph-io/badger
安裝
安裝 Badger
要開始使用 Badger,請安裝 Go 1.12 或更高版本。
go get github.com/dgraph-io/badger/v3
注意:Badger 不直接使用 CGO,但它依賴於https://github.com/DataDog/zstd進行壓縮,並且需要 gcc/cgo。如果你想在沒有 gcc/cgo 的情況下使用 badger,你可以執行
CGO_ENABLED=0 go get github.com/dgraph-io/badger/…
它將下載不支援 ZSTD 壓縮演算法的 badger。
安裝 Badger 命令列工具
從 https://github.com/dgraph-io/badger/releases 下載並提取最新的 Badger DB 版本,然後執行以下命令。
cd badger-<version>/badger
go install
這會將 badger 命令列實用程式安裝到您的 $GOBIN 路徑中。
資料庫操作
開啟資料庫
func Open(path string) (*badger.DB, error) {
if _, err := os.Stat(path); os.IsNotExist(err) {
os.MkdirAll(path, 0755)
}
opts := badger.DefaultOptions(path)
opts.Dir = path
opts.ValueDir = path
opts.SyncWrites = false
opts.ValueThreshold = 256
opts.CompactL0OnClose = true
db, err := badger.Open(opts)
if err != nil {
log.Println("badger open failed", "path", path, "err", err)
return nil, err
}
return db, nil
}
記憶體模式/無盤模式
預設情況下,Badger 確保所有資料都儲存在磁碟上。它還支援純記憶體模式。當 Badger 在記憶體模式下執行時,所有資料都儲存在記憶體中。在記憶體模式下讀寫速度要快得多,但在崩潰或關閉的情況下,儲存在 Badger 中的所有資料都會丟失。要在記憶體模式下開啟 badger,請設定InMemory
選項。
opts := badger.DefaultOptions(path).WithInMemory(true)
關閉資料庫
func Close() {
err := badgerDB.Close()
if err == nil {
log.Println("database closed", "err", err)
} else {
log.Println("failed to close database", "err", err)
}
}
儲存操作
寫入資料
要儲存鍵/值對,請使用以下Txn.Set()
方法;
鍵/值對也可以通過首先建立來儲存Entry
,然後 Entry
使用Txn.SetEntry()
. Entry
還公開了在其上設定屬性的方法。
func Set(key []byte, value []byte) {
wb := badgerDB.NewWriteBatch()
defer wb.Cancel()
err := wb.SetEntry(badger.NewEntry(key, value).WithMeta(0))
if err != nil {
log.Println("Failed to write data to cache.","key", string(key), "value", string(value), "err", err)
}
err = wb.Flush()
if err != nil {
log.Println("Failed to flush data to cache.","key", string(key), "value", string(value), "err", err)
}
}
設定TTL的寫入資料
Badger 允許在鍵上設定可選的生存時間 (TTL) 值。一旦 TTL 過去,金鑰將不再可檢索,並且將有資格進行垃圾收集。 可以使用和API 方法將 TTL 設定為time.Duration
值。Entry.WithTTL() Txn.SetEntry()
func SetWithTTL(key []byte, value []byte, ttl int64) {
wb := badgerDB.NewWriteBatch()
defer wb.Cancel()
err := wb.SetEntry(badger.NewEntry(key, value).WithMeta(0).WithTTL(time.Duration(ttl * time.Second.Nanoseconds())))
if err != nil {
log.Println("Failed to write data to cache.","key", string(key), "value", string(value), "err", err)
}
err = wb.Flush()
if err != nil {
log.Println("Failed to flush data to cache.","key", string(key), "value", string(value), "err", err)
}
}
讀取資料
要讀取資料,我們可以使用以下Txn.Get()
方法。
func Get(key []byte) string {
var ival []byte
err := badgerDB.View(func(txn *badger.Txn) error {
item, err := txn.Get(key)
if err != nil {
return err
}
ival, err = item.ValueCopy(nil)
return err
})
if err != nil {
log.Println("Failed to read data from the cache.","key", string(key), "error", err)
}
return string(ival)
}
存在鍵
func Has(key []byte) (bool, error) {
var exist bool = false
err := badgerDB.View(func(txn *badger.Txn) error {
_, err := txn.Get(key)
if err != nil {
return err
} else {
exist = true
}
return err
})
// align with leveldb, if the key doesn't exist, leveldb returns nil
if strings.HasSuffix(err.Error(), "not found") {
err = nil
}
return exist, err
}
刪除鍵
使用Txn.Delete()
方法刪除 key。
func Delete(key []byte) error {
wb := badgerDB.NewWriteBatch()
defer wb.Cancel()
return wb.Delete(key)
}
查詢操作
遍歷key和value
要迭代鍵,我們可以使用Iterator
,可以使用 Txn.NewIterator()
方法獲得。迭代以按位元組排序的字典順序發生。
func IteratorKeysAndValues(){
err := badgerDB.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchSize = 10
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
k := item.Key()
err := item.Value(func(v []byte) error {
fmt.Printf("key=%s, value=%s\n", k, v)
return nil
})
if err != nil {
return err
}
}
return nil
})
if err != nil {
log.Println("Failed to iterator keys and values from the cache.","error", err)
}
}
遍歷keys
Badger 支援一種獨特的迭代模式,稱為key-only迭代。它比常規迭代快幾個數量級,因為它只涉及對 LSM 樹的訪問,它通常完全駐留在 RAM 中。要啟用僅鍵迭代,您需要將該IteratorOptions.PrefetchValues
欄位設定為false
. 這也可用於在迭代期間對選定鍵進行稀疏讀取,item.Value()
僅在需要時呼叫。
func IteratorKeys(){
err := badgerDB.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.PrefetchValues = false
it := txn.NewIterator(opts)
defer it.Close()
for it.Rewind(); it.Valid(); it.Next() {
item := it.Item()
k := item.Key()
fmt.Printf("key=%s\n", k)
}
return nil
})
if err != nil {
log.Println("Failed to iterator keys from the cache.","error", err)
}
}
字首掃描
要遍歷一個鍵字首,您可以組合Seek()
and ValidForPrefix()
:
func SeekWithPrefix(prefixStr string){
err := badgerDB.View(func(txn *badger.Txn) error {
it := txn.NewIterator(badger.DefaultIteratorOptions)
defer it.Close()
prefix := []byte(prefixStr)
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
item := it.Item()
k := item.Key()
err := item.Value(func(v []byte) error {
fmt.Printf("key=%s, value=%s\n", k, v)
return nil
})
if err != nil {
return err
}
}
return nil
})
if err != nil {
log.Println("Failed to seek prefix from the cache.", "prefix", prefixStr,"error", err)
}
}