目录
1 介绍 2
1.1 文件介绍: 2
2 架构 3
3 特性 4
3.1 Get,Interator(迭代器)和快照 4
3.2 前缀迭代器 5
3.3 更新 5
3.4 持久化 5
3.5 ReadOnly 模式 6
3.6 数据库调试日志 6
3.7 事务日志 6
3.8 Memtable 管道 6
3.9 合并 Merge 操作 7
3.9.1 合并条件 7
4 工具 8
5 应用 9
5.1 初始化 9
5.2 使用 9
5.3 参数配置 10
5.4 查看数据库数据 10
- 介绍
RocksDB 项目最开始是在 Facebook 作为一个试验项目开发的高效的数据库软件,可以实现在服务器负载下快速存储(特别是闪存存储)的数据存储的全部潜力。它是一个 C++ 库,可以用于存储 KV,包括任意大小的字节流。它支持原子读写。提供Java 调用api,可以通过Java api 对RocksDB数据库进行操作。
RocksDB 具有高度灵活的配置设置,可以调整为在各种生产环境(包括纯内存,闪存,硬盘或 HDFS)上运行。它支持各种压缩算法,并且有生产和调试环境的各种便利工具。 RocksDB 借用了来自开源 leveldb 项目的核心代码,以及来自 Apache HBase 的重要思想。初始代码是从开源 leveldb 1.5 fork 的。它还融入了 facebook 团队在开发 RocksDB 之前的若干代码及想法。
- 文件介绍:
图 1
- *.log: 事务日志用于保存数据操作日志,可用于数据恢复
- *.sst: 数据持久换文件
- MANIFEST:
数据库中的 MANIFEST 文件记录数据库状态。压缩过程会添加新文件并从数据库中删除旧文件,并通过将它们记录在 MANIFEST 文件中使这些操作持久化。
- CURRENT:记录当前正在使用的MANIFEST文件
- LOCK:rocksdb自带的文件锁,防止两个进程来打开数据库。
- 架构
RocksDB 是一个嵌入式 kv 存储,key 和 value 是任意字节流。RocksDB 按顺序组织所有数据,常用操作是 Get(key) ,Put(key) ,Delete(key) 和 Scan(key) 。
图 2
- 特性
- Get,Interator(迭代器)和快照
Key 和 value 被视为纯字节流。对 key 或 value 的大小没有限制。Get API 允许应用程序从数据库中提取单个 key。MultiGet API 允许应用程序从数据库中检索一堆 key。通过 MultiGet 调用返回的所有 key-value 彼此一致。
数据库中的所有数据按照排序顺序进行逻辑排列。应用程序可以定义 key 的排序比较方法。Iterator API 允许应用程序对数据库执行 RangeScan。Iterator 可以寻找指定的 key,然后应用程序可以从该点开始一次扫描一个 key。Iterator API 也可以用于对数据库中的 key 进行反向迭代。创建 Iterator 时,将创建数据库的一致时间点视图。因此,通过 Iterator 返回的所有 key 都来自数据库的一致视图。
Snapshot API 允许应用程序创建数据库的时间点视图。Get 和 Iterator API 可用于从指定的快照读取数据。在某种意义上,Snapshot 和 Iterator 都提供了数据库的时间点视图,但它们的实现是不同的。短期扫描最好通过迭代器完成,而长时间运行的扫描最好通过快照完成。迭代器对与数据库的该时间点视图相对应的所有底层文件保持引用计数 - 这些文件在 Iterator 被释放之前不会被删除。另一方面,快照不会防止文件被删除; 但在压缩过程中,压缩程序能够判断快照的存在,它不会删除在任何现有快照中可见的 key。
快照不会在数据库重新启动后保持持久化,因此重新加载 RocksDB 库(通过服务器重新启动)会释放所有预先存在的快照。
- 前缀迭代器
大多数 LSM 引擎不能支持高效的 RangeScan API,因为它需要查看每个数据文件。但大多数应用程序不需要对数据库中的 key 范围进行纯随机扫描; 而应用程序通常通过 key 前缀进行扫描。RocksDB 使用这个方法来体现了它的优势。应用程序可以配置 prefix_extractor 以指定 key 前缀。RocksDB 使用它来存储每个 key 前缀的 blooms。指定前缀(通过 ReadOptions)的迭代器将使用这些 bloom 位来避免查找不包含具有指定的 key 前缀的数据文件。
- 更新
Put API 将单个 key-value 插入数据库。如果 key 已经存在于数据库中,则以前的值将被覆盖。Write API 允许将多个 key-value 原子地插入到数据库中。数据库保证要么单个 Write 调用中的所有 key-value 将被插入数据库,要么它们都不会插入数据库。
- 持久化
RocksDB 有一个事务日志。所有 Put 都存储在称为 memtable 的内存中缓冲区中,并可选择插入到事务日志中。每个 Put 都有一组通过 WriteOptions 设置的标志,它们指定是否将 Put 插入到事务日志中。WriteOptions 还可以指定在 Put 被提交之前,是否向事务日志发出 sync 调用。在内部,RocksDB 使用批量提交机制将多个事务写入到事务日志中,以便它可以使用单个 sync 调用提交多个事务。
- ReadOnly 模式
数据库可以以只读模式打开,其中数据库保证应用程序不会修改数据库中的任何内容。这导致高得多的读取性能,因为被横穿的代码路径完全避免了锁的开销。
- 数据库调试日志
RocksDB 将详细日志写入名为 LOG* 的文件。这些主要用于调试和分析正在运行的系统。该日志可以被配置为以指定的周期滚动。
- 事务日志
RocksDB 将事务存储到日志文件中以防止系统崩溃。在重新启动时,它会重新处理日志文件中记录的所有事务。日志文件可以配置为存储在与 _sstfile_s 不同的目录中,比如某些场景,你可能会将所有数据文件存储在非持久性快速存储器中,同时,您可以通过将所有事务日志放在较慢但持久的存储上确保不会有数据丢失。
- Memtable 管道
RocksDB 支持为数据库配置任意数量的 memtable。当 memtable 已满时,它变成不可变的 memtable,后台线程开始将其内容刷新到存储。同时,新的写入继续累积到新分配的 memtable。如果新分配的 memtable 被填充到其限制,它也被转换为不可变的 memtable 并被插入到 flush 管道中。后台线程继续将所有流水线不可变的 memtables 刷新到存储。这种流水线提高了 RocksDB 的写吞吐量,尤其是在慢速存储设备上运行时。
- 合并 Merge 操作
RocksDB 本地支持三种类型的记录:Put 记录,Delete 记录和 Merge 记录。当压缩过程遇到 Merge 记录时,它调用应用程序指定的称为 Merge 的方法。合并可以将多个 Put 和 Merge 记录合并成一个。这个强大的功能允许通常执行读 - 修改 - 写的应用程序完全避免读。它允许应用程序将操作意图记录为合并记录,RocksDB 压缩过程将该意图延迟应用于原始值。此功能在合并运算符中详细描述。
- 合并条件
如果是Level-0层,会先算出当前有多少个没有进行Compact 的文件个数numfiles, 然后根据这个文件的个数进行判断
相关参数 | 值 | 说明 |
level0_file_num_compaction_trigger | 4 | 当有4个未进行Compact的文件时,达到触发Compact的条件 |
level0_slowdown_writes_trigger | 20 | 当有20个未进行Compact的文件时,触发RocksDB,减慢写入速度 |
level0_stop_writes_trigger | 24 | 当有24个未进行Compact的文件时,触发RocksDB停止写入文件,此时会尽快的Compact Level-0层文件 |
表格 1
Level-1 层 文件总大小由 max_bytes_for_level_base 参数控制,而 Level-2 层的大小通过: Level_max_bytes[N] = Level_max_bytes[N-1] * max_bytes_for_level_multiplier^(N-1)*max_bytes_for_level_multiplier_additional[N-1] 计算得出
参数 | 值 | 说明 |
max_bytes_for_level_base | 10485760 | 用于指定Level-1 层总大小,超过这个值满足触发Compact条件 |
max_bytes_for_level_multiplier | 10 | 每一层最大Bytes 乘法因子 |
max_bytes_for_level_multiplier_addtl[2] | 1 | Level-2 层总大小调整参数 |
max_bytes_for_level_multiplier_addtl[3] | 1 | Level-3 层总大小调整参数 |
max_bytes_for_level_multiplier_addtl[4] | 1 | Level-4 层总大小调整参数 |
max_bytes_for_level_multiplier_addtl[5] | 1 | Level-5 层总大小调整参数 |
max_bytes_for_level_multiplier_addtl[6] | 1 | Level-6 层总大小调整参数 |
表格 2
对于Level-0层文件,RocksDB总是选择所有的文件进行Compact操作,因为Level-0层的文件之间,可能会有key范围的重叠。
对于Level-N (N>1)层的文件,会先按照文件大小排序(冒泡排序),选出最大的文件,并计算这个文件Key 的起止范围,通过这个范围查找Level-N+1层文件,把选出的Level-N 文件和Level-N+1 文件做为输入,并且在Level-N+1新建一个或多个SST文件作为输出。
可以通过设置max_background_compactions 大于1 来使用并行Compact,不过这个并行Compact 不能作用到Level-0层。
- 工具
sst_dump 工具可以导出 sst 文件中的所有键值对。ldb 工具可以 put,get,scan 数据库的内容。ldb 也可以dump MANIFEST 内容、更改数据库的配置级别数或用于手动压缩数据库。也可以对数据库进行修复(ldb repair –db=数据库路径)
- 应用
Rocksdb在oJmw中作为嵌入式数据库使用,调用Java接口,需要引入rocksdbjni-版本号.jar包。
- 初始化
RocksDB.loadLibrary();//加载jni
RocksDB db = RocksDB.open(options, db_path_not_found)//打开数据库
- 使用
- 单条插入
db.put("hello".getBytes(), "world".getBytes());
- 批量插入
try (final WriteOptions writeOpt = new WriteOptions()) {
for (int i = 10; i <= 19; ++i) {
try (final WriteBatch batch = new WriteBatch()) {
for (int j = 10; j <= 19; ++j) {
batch.put(String.format("%dx%d", i, j).getBytes(),
String.format("%d", i * j).getBytes());
}
db.write(writeOpt, batch);
}
}
- 查询
value = db.get("world".getBytes());
- 迭代器查询
try (final RocksIterator iterator = db.newIterator()) {
for (iterator.seekToLast(); iterator.isValid(); iterator.prev()) {
values.add(iterator.value ());
}
}
- 参数配置
接口 | 描述 |
T setCreateIfMissing(boolean flag);
| 如果数据库不存在则创建 |
T setCreateMissingColumnFamilies(boolean flag);
| 如果表不存在则创建 |
T setErrorIfExists(boolean errorIfExists);
| 如果为真则在数据库open 时会抛出异常 |
T setLogger(Logger logger);
| 设置日志,可以指定到自己的日志系统 |
T setMaxOpenFiles(int maxOpenFiles);
| 指定最大文件打开数量 |
T setMaxTotalWalSize(long maxTotalWalSize);
| 设置事务日志最大值 |
T setUseFsync(boolean useFsync);
| 设置数据元数据同步下盘 |
setDbPaths(final Collection<DbPath> dbPaths);
| 设置数据库路径, [{"/flash_path", 10GB}, {"/hard_drive", 2TB}] 越新的数据,越靠前 |
T setDbWriteBufferSize(long dbWriteBufferSize);
| 设置数据库缓存 |
- 查看数据库数据
查看数据库信息两种方式,一种是通过rocksdb提供的ldb工具,一种是利用postman工具通过http请求,来查看