You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
王雪飞 22acc2d13e commit the first design 10 months ago
.github/workflows initialize the rep 删除 10 months ago
benchmarks initialize the rep 删除 10 months ago
cmake initialize the rep 删除 10 months ago
db initialize the rep 删除 10 months ago
doc initialize the rep 删除 10 months ago
helpers/memenv initialize the rep 删除 10 months ago
include/leveldb initialize the rep 删除 10 months ago
issues initialize the rep 删除 10 months ago
port initialize the rep 删除 10 months ago
table initialize the rep 删除 10 months ago
test initialize the rep 删除 10 months ago
third_party initialize the rep 删除 10 months ago
util initialize the rep 删除 10 months ago
.clang-format initialize the rep 10 months ago
.gitignore initialize the rep 10 months ago
.gitmodules initialize the rep 10 months ago
AUTHORS initialize the rep 10 months ago
CMakeLists.txt initialize the rep 10 months ago
CONTRIBUTING.md initialize the rep 10 months ago
LICENSE initialize the rep 10 months ago
NEWS initialize the rep 10 months ago
README.md commit the first design 10 months ago
TODO initialize the rep 10 months ago

README.md

设计文档

王雪飞,马也驰

1.项目概述

本项目的背景是提升 LevelDB 在高写入负载场景下的性能。LevelDB 是一种轻量级的键值存储引擎,但在数据频繁更新或大值(Large Values)存储场景下,由于数据写入和合并(Compaction)过程的设计,其性能可能受到显著影响。为解决这一问题,项目目标是实现 KV(Key-Value)分离机制,以降低写放大现象并提高存储效率。

具体实现内容包括在 LevelDB 内部引入 KV 分离功能,即将键(Key)与值(Value)存储到不同的存储介质中。通过修改 SSTable 的结构设计,将键与指向值的指针存储在原有的文件中,而将实际值存储到单独的文件或存储介质中,从而减少 Compaction 操作对大值的处理负担。此外,项目还优化了数据访问逻辑,实现了值文件的高效读写支持。

该功能的应用场景主要包括:

  1. 适用于大值写入频繁的场景,如日志存储、视频元数据管理等。
  2. 提升 SSD 等固态存储设备的寿命,减少写入放大带来的磨损。
  3. 在混合存储架构中,提高冷热数据分离的效率。

2. 功能设计

2.1 字段设计

设计目标: 能够准确描述kv的属性数量,以及每一个属性的名称和字节数量。

设计思路: key的格式:| key | vlog_fileno | value_offset | 单个value的格式:| {attr1名称长度(定长), attr1名称(变长), attr1的偏移量(定长)}, ...{attr1长度(定长), attr1内容(变长)}, ... |

2.1 KV分离

设计目标: 将value的存储和key在lsm tree中的存储分离,降低lsm tree的GC开销

设计思路:

  1. value的分离式存储 我们使用若干个vlog文件,为每一个vlog文件设置容量上限(比如16MiB),并在内存中为每一个vlog维护一个discard计数器,表示这个vlog中当前有多少value已经在lsm tree中被标记为删除。
  2. 存储value所在vlog和偏移量的元数据 我们在key和vlog中添加一个vlog_page的中间层,这一层存储每一个key对应的value所在的vlog文件和文件内偏移,而lsm tree中的key包含的实际上是这个中间层的slot下标,而每一个slot中存储的是key所对应的vlog文件号以及value在vlog中的偏移。这样,我们就可以在不修改lsm tree的基础上,完成对vlog的compaction,并将vlog的gc结果只反映在这个中间层vlog_page中。这个vlog_page实际上也是一个线性增长的log文件,作用类似于os中的页表,负责维护lsm tree中存储的slot下标到vlog和vlog内偏移量的一个映射。这样,通过vlog_page我们就可以找到具体的vlog文件和其文件内偏移量。对于vlog的GC过程,我们不需要修改lsm tree中的内容,我们只需要修改vlog_page中的映射即可。
  3. vlog_page文件和vlog文件的GC 对于vlog文件,我们在内存中维护一个bitmap,用来表示每一个slot的使用情况,并在插入和GC删除kv时进行动态的分配和释放。对于vlog文件的GC,我们用一个后台线程来扫描所有vlog的discard计数器。当某些vlog的discard计数器超过某个阈值(比如1024),我们就对这些vlog文件进行GC过程,当GC完成之后将vlog_page中的slot元数据进行更新,再将原来的vlog文件进行删除,GC过程就完成了。

3. 数据结构设计

key的格式:| key | vlog_page_slot | vlog_page: | slot0:{vlog_no, offset}, slot1:{vlog_no, offset}, ... |

对于每一次读取,用户线程先读取lsm tree中key的slot下标,然后到vlog_page中读取对应的slot内容(每一个slot都是定长的),之后再在这个slot中读取value所在的vlog文件号和偏移量offset,之后到对应的vlog文件中读取value。

但是这又带来了一个问题,我们该如何管理vlog_page这个文件?当插入新的kv时,我们需要在这个vlog_page中分配新的slot,在GC删除某个kv时,我们需要将对应的slot进行释放。这里我们选择在内存中维护一个可线性扩展的bitmap。这个bitmap中每一个bit标识了当前vlog_page文件中对应slot是否被使用,是为1,不是为0。这样一来,在插入新kv时,我们可以用bitmap来分配一个新的slot(将bitmap中第一个为0的bit设置为1),将内容进行写入;在GC删除某个kv时,我们将这个slot对应的bitmap中的bit重置为0即可。

4. 接口设计

这里只展示和vlog以及GC无关的接口,vlog的创建,管理以及后台线程的GC设计到vlog等新数据结构的实现,较为复杂和庞大,这里不做展示。我们只列出与kv的插入有关的新接口:

  1. 搜索vlog_page文件: Status find_slot(const Slice& key, Slot *slot);
  2. 搜索vlog文件: Status find_value(Slot *slot);
  3. 分配新的slot: Status allocate_slot(Bitmap *map, uint64_t *s);
  4. 释放slot: void deallocate_slot(Bitmap *map, uint64_t *s);

5. 功能测试

单元测试:

  1. 测试插入后,是否能读取成功。
  2. 测试插入超过初始vlog_page等slot数量之后,是否还能正常插入,检查vlog_page文件等线性可扩展性
  3. 测试插入后,进行删除,等待GC完成后再读取value和vlog的大小,看看GC过程是否正常进行。

性能测试:

  1. 测试插入的吞吐
  2. 测试在只有删除的情况下,GC的效率
  3. 测试在插入和删除不同比重的负载下,系统的吞吐情况

6. 可能遇到的挑战与解决方案

列出实现过程中可能遇到的技术难题及其解决思路,如如何处理GC开销、数据同步、索引原子更新等问题。 各种参数的设置,比如vlog的容量上限,以及vlog_page的bitmap管理方式是否足够高效?以及在GC过程中如果对被GC中的vlog进行写入该让用户线程和后台线程以什么样的方式进行同步?vlog_page的读写放大也是一个重要的问题。

7. 分工和进度安排

功能 完成日期 分工
vlog中value的存储格式 12.8 王雪飞
vlog_page实现 12.8 马也驰
vlog的GC实现 12.29 马也驰
性能测试 1.5 王雪飞
功能测试 1.5 马也驰