Badger Scan 性能探究

Badger 是go实现的高性能KV库,与RocksDB类似,也是使用LSM实现的。但不同的是,对于大value, 为了减少了LSM的读写放大的问题,把value记录到单独的value log 中。在LSM记录的value 只是相对应的value log 的offset , 也就是log file ID 和所在文件的offset。本文描述是基于 1.6.2 版本。 KKV是一种数据结构,尤其在推荐领域广泛用到。比如说用户浏览过的文章,视频或者商品列表。对于同一个用户来说,浏览过的物料实际是一个list 。可以简单表示如下: user_id Item_id Timestamp User1 Item1 1745070155 User1 Item2 1745070155 User1 Item3 1745070155 那么在底层,如果使用badger进行存储的时候,会把(user_id, item_id) 当成 key 存储。那么如果针对某个 user_id ,我们需要进行前缀匹配操作,匹配到user_id开头的数据都获取到,进而获取到item_id 列表。badger 的scan操作,官方的例子如下: db.View(func(txn *badger.Txn) error { it := txn.NewIterator(badger.DefaultIteratorOptions) defer it.Close() prefix := []byte("1234") for it.Seek(prefix); 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 !...

April 19, 2025 · 5 min · 880 words

Badger的GC初步探究

类似 RocksDB, badger 是 Go 基于 LSM 实现的 KV 数据库。本文介绍基于 badger 的 1.62 版本。 与传统的LSM 不同,对于 value 数据,badger 会写入 value log,来减少写放大和读放大。但是也会造成问题,就是磁盘会占用过多。 value log 的 gc 实现的比较简单。 我们先看下 badger 写入链路。 数据会优先写入 value log , 这里实际当成了 WAL 使用 value pointer 会记录 写入 value log 文件的 fid ,offset, len 然后把数据写入 memtable ,如何memtable 数据写满的话,会变成不可更改的 memtable , 然后写入到 SST Tables 中。 那么何时刷新 memtable , 目前有两种情况: 一个是 memtable 大小控制,超过 memtable 规定的大小,就会刷新。默认是 64M , 通过WithMaxTableSize 可以指定 在一个通过 LogRotatesToFlush 控制,这个参数是说 写入 value log 的文件轮转了多少次,默认是 2 次。 超过这个数值也会刷新。 当 badger 进行重启的时候,会对部分数据进行回放操作。从哪个点的数据进行回放,是通过 head pointer 实现的。 head pointer 记录了 fid 和 offset , 数据比这个 head pointer 晚的话,都会进行回放。...

March 4, 2025 · 2 min · 235 words