實現分散式 kv—1 Standalone KV

roseduan發表於2021-11-27

TinyKV 是 PingCAP 的一個開源課程:https://github.com/tidb-incubator/tinykv,旨在實現一個簡易的分散式 kv,其中很多程式碼框架它已經提供了,我們只需要填充具體的邏輯即可。
這個課程分為了 4 個 Project:

  • Standlone KV
  • Raft KV
  • Multi Raft KV
  • Transaction

分別需要實現單機版 kv、基於 raft 一致性演算法的 kv、具有分散式事務的 kv,除了第一個 standalone kv 沒有什麼難度之外,其他的幾個 Project 都非常的有挑戰,涉及到手寫 raft 演算法以及分散式事務。
當然這個課程也是入門分散式儲存領域是挺好的學習資源,因此記錄一下自己的學習歷程。


第一個 Project 是整合 Badger,實現一個簡易的單機版 kv。

Badger 是一個很優秀的開源的單機版 kv 儲存引擎,基於 LSM Tree 實現,讀寫效能都很好,需要簡單熟悉下 Badger 的用法,可以參考下官方示例:https://github.com/dgraph-io/badger

在 TinyKV 中,儲存層是一個抽象介面,分別實現了 raft storage、mem storage、standalone storage,這裡我們只需要實現 standalone storage 就行了。

具體的實現,在 kv/storage/standalone_storage/standalone_storage.go 中,需要封裝一下 Badger,然後實現 storage 介面中定義的幾個方法。

這裡貼一下結構體的定義:

type StandAloneStorage struct {
  // Your Data Here (1).
  badgerDB *badger.DB
  options  badger.Options
}

需要說明的是,在 Reader 方法中,需要返回一個 StorageReader 介面,這是一個抽象介面,具體邏輯需要我們自定義。

func (s *StandAloneStorage) Reader(ctx *kvrpcpb.Context) (storage.StorageReader, error) {
  // Your Code Here (1).
  txn := s.badgerDB.NewTransaction(false)
  reader := NewStandaloneReader(txn)
  return reader, nil
}

例如我定義了一個 StandaloneReader:

type StandaloneReader struct {
  txn *badger.Txn
}
​
func NewStandaloneReader(txn *badger.Txn) *StandaloneReader {
  return &StandaloneReader{
    txn: txn,
  }
}

這裡完成之後,還需要在 kv/server/raw_api.go 中完善相應的 gRPC 介面,直接解析傳過來的引數,然後呼叫 Storage 介面中的方法即可。這裡展示一個示例:

func (server *Server) RawGet(_ context.Context, req *kvrpcpb.RawGetRequest) (resp *kvrpcpb.RawGetResponse, err error) {
  // Your Code Here (1).
  resp = &kvrpcpb.RawGetResponse{}// get storage reader.
  var reader storage.StorageReader
  reader, err = server.storage.Reader(req.Context)
  if err != nil {
    return
  }
  defer reader.Close()
​
  val, err := reader.GetCF(req.Cf, req.Key)
  if len(val) == 0 {
    resp.NotFound = true
  }
  resp.Value = val
  return
}

這裡的幾個介面完成之後,一個完整的 Standalone KV 就完成了。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章