Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

posts: add lsm-kv-separation-overview #5

Merged
merged 4 commits into from
Aug 7, 2021

Conversation

skyzh
Copy link
Owner

@skyzh skyzh commented Aug 7, 2021

No description provided.

@skyzh skyzh changed the title posts: add lsm-kv-separation-overview posts: add lsm-kv-separation-overview Aug 7, 2021
@skyzh skyzh merged commit c8b826e into master Aug 7, 2021
@skyzh skyzh deleted the posts/2021-08-07-lsm-kv-separation-overview branch August 7, 2021 17:16
@mapleFU
Copy link

mapleFU commented Sep 27, 2021

由于 Titan 没有类似 Badger 的内置 MVCC 功能,在回写 LSM 树时,需要注册 WriteCallback,在 callback 中检测当前回写的 key 是否已经被删除或更新。这会对引擎 GC 过程中的用户写入吞吐造成巨大的影响。

俺没太懂这里详细的流程是什么样子的,可以举个例子吗?

@skyzh
Copy link
Owner Author

skyzh commented Oct 7, 2021

比如 compaction 的时候要写入 key A,用户在 key A 写了新的数据。对 Titan 来说,要注册 WriteCallback,才能防止 compaction 写入的 key A 覆盖掉用户新写入的值。

对于 BadgerDB 来说,compaction 写入旧的数据也没有问题,因为所有的 key 都带 timestamp,最新的 key 在 get 时永远会被优先读到。

@mapleFU
Copy link

mapleFU commented Oct 8, 2021

好的,感谢,话说 badger 分离大小是不是 1M 呀,瞅了眼代码:
https://github.com/dgraph-io/badger/blob/master/options.go#L506

@skyzh
Copy link
Owner Author

skyzh commented Oct 8, 2021

这个 PR 从 1KB 改到了 1MB(hypermodeinc/badger#1664

@mapleFU
Copy link

mapleFU commented Oct 8, 2021

这个 PR 从 1KB 改到了 1MB(dgraph-io/badger#1664

(但是你文章里面既不是 1KB 也不是 1MB 啊 ( ;´Д`)

@mapleFU
Copy link

mapleFU commented Apr 25, 2022

话说,我在想,如果不考虑 Sequence,Badger 的 GC 能不能只写前台,然后存在于 LSM 中的 key 被写入之后,记录 seq。等 seq 之前的快照都没了,再回收物理空间,是不是也可以做?

@skyzh
Copy link
Owner Author

skyzh commented Apr 25, 2022

话说,我在想,如果不考虑 Sequence,Badger 的 GC 能不能只写前台,然后存在于 LSM 中的 key 被写入之后,记录 seq。等 seq 之前的快照都没了,再回收物理空间,是不是也可以做?

我觉得是可以的,这样可以省掉一次读,但是有更大的写开销(

@mapleFU
Copy link

mapleFU commented Apr 25, 2022

话说,我在想,如果不考虑 Sequence,Badger 的 GC 能不能只写前台,然后存在于 LSM 中的 key 被写入之后,记录 seq。等 seq 之前的快照都没了,再回收物理空间,是不是也可以做?

我觉得是可以的,这样可以省掉一次读,但是有更大的写开销(

感觉写没有吧,相当于回收空间由垃圾收集器积极回收变成了由最低 seq 的读者来触发回收?

@motecshine
Copy link

package main

import (
	"sync/atomic"
	"fmt"
	"unsafe"
)

const (
	maxHeight = 20
)

const (
	offsetSize  = int(unsafe.Sizeof(uint32(0)))
	nodeAlign   = int(unsafe.Sizeof(uint64(0))) - 1 // 这里是7
	MaxNodeSize = int(unsafe.Sizeof(node{}))
        defaultLevel = 20
)

type node struct {
	value uint64

	keyOffset uint32 // Immutable. No need to lock to access key.
	keySize   uint16 // Immutable. No need to lock to access key.

	height uint16

	tower [maxHeight]uint32
}

type Arena struct {
	n   uint32
	buf []byte
}

func newArena(sz int64) *Arena {
	return &Arena{
		n:   1,
		buf: make([]byte, sz),
	}
}

func (a *Arena) alloc(sz uint32) uint32 {
	return atomic.AddUint32(&a.n, sz) - sz
}

func (a *Arena) putNode(height int) uint32 {
	unusedSize := (defaultLevel - height) * offsetSize
	l := uint32(MaxNodeSize - unusedSize + nodeAlign) // 这里
	n := a.alloc(l)
	m := (n + uint32(nodeAlign)) & ^uint32(nodeAlign) // 还有这里计算 buf offset 看不太懂,这是通用做法吗
	fmt.Println(m)
        return m
}

func main() {
	a := newArena(65535)

	a.putNode(4)
	a.putNode(3)
	a.putNode(2)
	a.putNode(1)
}

@jyizheng
Copy link

BadgerDB 在重写 vLog 过程中,会扫描当前处理的 key 在 LSM 树中是否存在。若不存在或已更新,则忽略这个 key。

当新的 vLog 生成完成后,BadgerDB 会将这些 KV 的新位置写回到 LSM 树中。因此,BadgerDB 的 GC 过程会对 LSM 树的用户写入吞吐量造成影响。这里就会产生一个问题:如果用户已经删除了一个 key,但 GC 时把这个 key 对应的旧 value 写回了 LSM 树,是否会在读取时造成正确性问题?

这里在扫描老的vlog时,已经判断key是否存在了。如果添加valid的key到LSM之前,再判断一次,是不是就没有你说的问题了?

@jyizheng
Copy link

我wisc的实现跟你描述的Badgerdb的gc过程一样。
Screenshot 2023-06-14 at 9 46 14 PM

Wisckey是不是也存你说的这个问题?

@mapleFU
Copy link

mapleFU commented Jun 15, 2023

@jyizheng 是的,WiscKey 的 GC 描述应该是存在问题的。

如果添加valid的key到LSM之前,再判断一次

应该有一些实现是这样的,不过问题就是读放大吧

@jyizheng
Copy link

jyizheng commented Jun 15, 2023

@jyizheng 是的,WiscKey 的 GC 描述应该是存在问题的。

如果添加valid的key到LSM之前,再判断一次

应该有一些实现是这样的,不过问题就是读放大吧

只是想理解一下正确性的问题。对,这样实现会有读放大。请问哪些system是这样实现的?

@skyzh
Copy link
Owner Author

skyzh commented Jun 15, 2023

BadgerDB 实现了 MVCC,因此会出现需要把一个 key 的旧版本写回去的情况。

@jyizheng
Copy link

LevelDB也有MVCC?
怎样判断一个旧版本是否需要些回去呢?

@skyzh
Copy link
Owner Author

skyzh commented Jun 15, 2023

RocksDB+Titan/TerarkDB 的 ts 是不暴露给用户的,所以回写时只需要考虑最新版本。BadgerDB 的 managed mode 会暴露 ts,由用户指定 watermark 和 ts,所以 gc 的时候需要保留旧版本的 vptr。

@jyizheng
Copy link

那WiscKey的实现有问题吗?往LSM添加新的value地址时,需要再check key是否存在吗?

@skyzh
Copy link
Owner Author

skyzh commented Jun 15, 2023

从论文描述来看,我觉得不够完整。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants