基本操作

基本操作

rocksdb库提供了一个持久性键值存储。键和值是任意字节数组。键按用户指定的比较器函数在键值存储中排序。

打开一个数据库

rocksdb数据库有一个对应于文件系统目录的名称。数据库的所有内容都存储在这个目录中。 下面的例子展示了如何打开一个数据库,在必要时创建它:

  1. #include <cassert>
  2. #include "rocksdb/db.h"
  3. rocksdb::DB* db;
  4. rocksdb::Options options;
  5. options.create_if_missing = true;
  6. rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
  7. assert(status.ok());
  8. ...

如果您想在数据库已经存在的情况下引发错误,请在rocksdb::DB::Open调用之前添加以下行:

  1. options.error_if_exists = true;

如果要将代码从leveldb移植到rocksdb,可以使用rocksdb::LevelDBOptions将leveldb::Options对象转换为rocksdb::Options对象,该对象具有与leveldb::Options相同的功能:

  1. #include "rocksdb/utilities/leveldb_options.h"
  2. rocksdb::LevelDBOptions leveldb_options;
  3. leveldb_options.option1 = value1;
  4. leveldb_options.option2 = value2;
  5. ...
  6. rocksdb::Options options = rocksdb::ConvertOptions(leveldb_options);

RocksDB 选项

用户可以选择始终在代码中显式地设置选项字段,如上所示。或者,您也可以通过字符串到字符串映射或选项字符串来设置它。 参见选项字符串和选项映射 ( https://github.com/facebook/rocksdb/wiki/Option-String-and-Option-Map )

有些选项可以在DB运行时动态更改。例如:

  1. rocksdb::Status s;
  2. s = db->SetOptions({{"write_buffer_size", "131072"}});
  3. assert(s.ok());
  4. s = db->SetDBOptions({{"max_background_flushes", "2"}});
  5. assert(s.ok());

RocksDB自动将数据库中使用的选项保存在DB目录下的OPTIONS-xxxx文件中。通过从这些选项文件中提取选项,用户可以选择在重新启动DB后保留选项值。 参见RocksDB选项文件 (https://github.com/facebook/rocksdb/wiki/RocksDB-Options-File)。

有些选项可以在DB运行时动态更改。例如:

  1. rocksdb::Status s;
  2. s = db->SetOptions({{"write_buffer_size", "131072"}});
  3. assert(s.ok());
  4. s = db->SetDBOptions({{"max_background_flushes", "2"}});
  5. assert(s.ok());

RocksDB自动将数据库中使用的选项保存在DB目录下的Options-xxxx文件中。通过从这些选项文件中提取选项,用户可以选择在重新启动DB后保留选项值。参见RocksDB选项文件。( https://github.com/facebook/rocksdb/wiki/RocksDB-Options-File

Status 状态

您可能已经注意到了上面的rocksdb::Status类型。这种类型的值由可能遇到错误的rocksdb中的大多数函数返回。您可以检查这样的结果是否ok,并打印一个相关的错误消息:

  1. rocksdb::Status s = ...;
  2. if (!s.ok()) cerr << s.ToString() << endl;

Closing A Database 关闭数据库

使用数据库之后,只需删除数据库对象。 例子:

  1. ... open the db as described above ...
  2. ... do something with db ...
  3. delete db;

读和写

数据库提供Put、Delete和Get方法来修改/查询数据库。例如,下面的代码将存储在key1下的值移动到key2。

  1. std::string value;
  2. rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &value);
  3. if (s.ok()) s = db->Put(rocksdb::WriteOptions(), key2, value);
  4. if (s.ok()) s = db->Delete(rocksdb::WriteOptions(), key1);

现在,值大小必须小于4GB。RocksDB还允许单次删除,这在某些特殊情况下很有用。

从源到值字符串,每个Get结果至少进入一个memcpy。如果源在块缓存中,可以使用PinnableSlice避免额外的复制。

  1. PinnableSlice pinnable_val;
  2. rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &pinnable_val);

一旦销毁了pinnable_val或在其上调用了::Reset,就会释放源。点击这里了解更多内容。( http://rocksdb.org/blog/2017/08/24/pinnableslice.html

原子更新

注意,如果进程在key2的Put之后而在key1的delete之前死亡,那么相同的值可能被保存在多个键下。 可以通过使用WriteBatch类原子地应用一组更新来避免这些问题:

  1. #include "rocksdb/write_batch.h"
  2. ...
  3. std::string value;
  4. rocksdb::Status s = db->Get(rocksdb::ReadOptions(), key1, &value);
  5. if (s.ok()) {
  6. rocksdb::WriteBatch batch;
  7. batch.Delete(key1);
  8. batch.Put(key2, value);
  9. s = db->Write(rocksdb::WriteOptions(), &batch);
  10. }

WriteBatch包含一系列要对数据库进行的编辑,这些编辑按顺序应用于该批处理中。注意,我们在Put之前调用了Delete,这样如果key1与key2相同,我们就不会错误地完全删除该值。

除了原子性的好处之外,WriteBatch还可以通过将大量单个突变放入同一批中来加速批量更新。

同步写入

默认情况下,对rocksdb的每次写操作都是异步的: 它在将写操作从进程推入操作系统后返回。从操作系统内存到底层持久存储的传输是异步进行的。 可以为特定的写打开sync标志,使写操作在被写入的数据被一直推送到持久存储之前不会返回。 (在Posix系统上,这是通过调用fsync(…) 或 fdatasync(…) 或 msync(…, MS_SYNC),然后写操作返回。)

  1. rocksdb::WriteOptions write_options;
  2. write_options.sync = true;
  3. db->Put(write_options, ...);

非同步写入

对于非同步写,RocksDB只缓冲WAL写在操作系统缓冲区或内部缓冲区(当options.manual_wal_flush = true)。它们通常比同步写快得多。 不同步写入的缺点是,机器崩溃可能导致最后几个更新丢失。请注意,仅仅是编写过程的崩溃(i.e.,而不是重启)不会造成任何损失,因为即使同步是错误的,更新也会在被认为完成之前从进程内存推入操作系统。

非同步写通常可以安全地使用。例如,当将大量数据加载到数据库中时,您可以通过在崩溃后重新启动批量加载来处理丢失的更新。 当DB::SyncWAL()由单独的线程调用时,也可以使用混合模式。

我们还提供了一种方法来完全禁用特定写操作的写前日志。如果设置write_option.disableWAL 是 true,写操作根本不会进入日志,并且可能在进程崩溃时丢失。

默认情况下,RocksDB使用fdatasync()来同步文件,在某些情况下,这可能比fsync()更快。如果想使用fsync(),可以将选项::use_fsync设置为true。 在像ext3这样的文件系统上,您应该将其设置为true,因为在重新引导之后,这些文件可能会丢失。

并发性

数据库一次只能由一个进程打开。rocksdb实现从操作系统获得一个锁,以防止误用。在单个进程中,相同的rocksdb::DB对象可以由多个并发线程安全地共享。 即,不同的线程可以写入或获取迭代器或调用Get到相同的数据库上,而不需要任何外部同步(rocksdb实现将自动执行所需的同步)。 然而,其他对象(如Iterator和WriteBatch)可能需要外部同步。如果两个线程共享这样一个对象,它们必须使用自己的锁定协议来保护对该对象的访问。 更多细节可以在公共头文件中找到。

合并操作符

合并操作符为读写操作提供了有效的支持。更多关于接口和实现的信息,请浏览:

合并操作符 (https://github.com/facebook/rocksdb/wiki/Merge-Operator) 合并操作实现 (https://github.com/facebook/rocksdb/wiki/Merge-Operator-Implementation)

迭代

下面的示例演示如何在数据库中打印所有(键、值)对。

  1. rocksdb::Iterator* it = db->NewIterator(rocksdb::ReadOptions());
  2. for (it->SeekToFirst(); it->Valid(); it->Next()) {
  3. cout << it->key().ToString() << ": " << it->value().ToString() << endl;
  4. }
  5. assert(it->status().ok()); // Check for any errors found during the scan
  6. delete it;

下面的变量显示了如何处理范围[start, limit]中的键:

  1. for (it->Seek(start);
  2. it->Valid() && it->key().ToString() < limit;
  3. it->Next()) {
  4. ...
  5. }
  6. assert(it->status().ok()); // Check for any errors found during the scan

您还可以按相反的顺序处理条目。(注意:反向迭代可能比正向迭代稍微慢一些。)

  1. for (it->SeekToLast(); it->Valid(); it->Prev()) {
  2. ...
  3. }
  4. assert(it->status().ok()); // Check for any errors found during the scan

这是一个处理范围(限制,开始)中的条目的例子,从一个特定的键按相反的顺序处理:

  1. for (it->SeekForPrev(start);
  2. it->Valid() && it->key().ToString() > limit;
  3. it->Prev()) {
  4. ...
  5. }
  6. assert(it->status().ok()); // Check for any errors found during the scan

查阅 SeekForPrev (https://github.com/facebook/rocksdb/wiki/SeekForPrev)

有关错误处理、不同的迭代选项和最佳实践的说明,请参见Iterator。 (https://github.com/facebook/rocksdb/wiki/Iterator)

要了解实现细节,请参阅Iterator的实现 (https://github.com/facebook/rocksdb/wiki/Iterator-Implementation)

快照

快照为键值存储的整个状态提供一致的只读视图。snapshot可以是非空的,表示读取操作应该针对特定版本的DB状态。

如果ReadOptions::snapshot为NULL,那么read将对当前状态的隐式快照进行操作。

快照由DB::GetSnapshot()方法创建:

  1. rocksdb::ReadOptions options;
  2. options.snapshot = db->GetSnapshot();
  3. ... apply some updates to db ...
  4. rocksdb::Iterator* iter = db->NewIterator(options);
  5. ... read using iter to view the state when the snapshot was created ...
  6. delete iter;
  7. db->ReleaseSnapshot(options.snapshot);

注意,当不再需要快照时,应该使用DB::ReleaseSnapshot接口来释放它。这允许实现摆脱仅为支持读取快照而维护的状态。

切片

上面调用的it->key()和it->value()的返回值是rocksdb::Slice类型的实例。 Slice是一个简单的结构,它包含一个长度和一个指向外部字节数组的指针。 与返回std::string相比,返回一个片是一种更便宜的选择,因为我们不需要复制可能很大的键和值。 此外,rocksdb方法不返回以null结尾的c风格字符串,因为rocksdb键和值允许包含”\0”字节。

c++字符串和空结束的C风格的字符串可以很容易地转换成一个切片:

  1. rocksdb::Slice s1 = "hello";
  2. std::string str("world");
  3. rocksdb::Slice s2 = str;

切片可以很容易地转换回c++字符串:

  1. std::string str = s1.ToString();
  2. assert(str == std::string("hello"));

使用切片时要小心,因为这取决于调用者,以确保在使用切片时,切片点所在的外部字节数组仍然是活动的。例如,下面是bug:

  1. rocksdb::Slice slice;
  2. if (...) {
  3. std::string str = ...;
  4. slice = str;
  5. }
  6. Use(slice);

当if语句超出作用域时,str将被销毁,slice的备份存储将消失。

事务

RocksDB现在支持多操作事务。查看 Transactions (https://github.com/facebook/rocksdb/wiki/Transactions)

比较器

前面的示例使用默认的order函数for key,该函数按字典顺序对字节排序。 但是,您可以在打开数据库时提供自定义比较器。 例如,假设每个数据库键由两个数字组成,我们应该按第一个数字排序,按第二个数字断开连接。 首先,定义一个适当的rocksdb::Comparator子类,它表示以下规则:

  1. class TwoPartComparator : public rocksdb::Comparator {
  2. public:
  3. // Three-way comparison function:
  4. // if a < b: negative result
  5. // if a > b: positive result
  6. // else: zero result
  7. int Compare(const rocksdb::Slice& a, const rocksdb::Slice& b) const {
  8. int a1, a2, b1, b2;
  9. ParseKey(a, &a1, &a2);
  10. ParseKey(b, &b1, &b2);
  11. if (a1 < b1) return -1;
  12. if (a1 > b1) return +1;
  13. if (a2 < b2) return -1;
  14. if (a2 > b2) return +1;
  15. return 0;
  16. }
  17. // Ignore the following methods for now:
  18. const char* Name() const { return "TwoPartComparator"; }
  19. void FindShortestSeparator(std::string*, const rocksdb::Slice&) const { }
  20. void FindShortSuccessor(std::string*) const { }
  21. };

现在使用这个自定义比较器创建一个数据库:

  1. TwoPartComparator cmp;
  2. rocksdb::DB* db;
  3. rocksdb::Options options;
  4. options.create_if_missing = true;
  5. options.comparator = &cmp;
  6. rocksdb::Status status = rocksdb::DB::Open(options, "/tmp/testdb", &db);
  7. ...

列族

列族提供了一种逻辑分区数据库的方法。用户可以跨多个列族提供多个键的原子写入,并从中读取一致的视图。

批量加载

您可以创建和摄取SST文件,以便将大量数据直接批量加载到DB中,同时对实时流量的影响最小。

备份和检查点

备份允许用户在远程文件系统(考虑HDFS或S3)中创建定期增量备份,并从其中任何一个备份中恢复。

检查点提供了在单独目录中获取运行的RocksDB数据库快照的能力。 如果可能,文件是硬链接的,而不是复制的,因此这是一个相对轻量级的操作。

I/O

默认情况下,RocksDB的I/O通过操作系统的页面缓存。设置 速率限制器 (https://github.com/facebook/rocksdb/wiki/Rate-Limiter)可以限制RocksDB问题文件写入的速度,为读取I/Os腾出空间。

用户还可以使用 直接I/O 选择旁路页面缓存。(https://github.com/facebook/rocksdb/wiki/Direct-IO)

更多细节见IO。(https://github.com/facebook/rocksdb/wiki/IO)

向后兼容性

比较器的Name方法的结果在创建数据库时附加到数据库,并在以后打开的每个数据库上进行检查。如果名称更改,则rocksdb::DB::Open调用将失败。 因此,当且仅当新的密钥格式和比较函数与现有数据库不兼容时才更改名称,并且可以丢弃所有现有数据库的内容。

然而,您仍然可以随着时间的推移逐步发展您的关键格式,并进行一些预先计划。例如,您可以在每个键的末尾存储一个版本号(对于大多数使用,一个字节就足够了)。 当您希望切换到一个新的密钥格式(例如,添加一个可选的第三部分密钥由TwoPartComparator处理),(a)保持相同的比较器名称(b)增加新key版本号(c)改变比较器函数所以它使用版本号在决定如何解释他们的关键。

MemTable和Table工厂

默认情况下,我们将数据保存在内存中的skiplist memtable中,将数据保存在磁盘上的表格式保存在这里描述的表格格式中:RocksDB表格格式。(https://github.com/facebook/rocksdb/wiki/Rocksdb-Table-Format)

由于RocksDB的目标之一是使系统的不同部分易于插入,所以我们支持memtable和表格式的不同实现。您可以通过设置选项::memtable_factory来提供自己的memtable工厂,通过设置选项::table_factory来提供自己的表工厂。对于可用的memtable工厂,请参考rocksdb/ memtablerepd .h,对于表格工厂,请参考rocksdb/table.h。这些特性都处于活动开发阶段,请注意任何API更改,以免破坏您的应用程序。

您还可以在这里和这里阅读更多关于memtables的信息。

性能

从设置选项开始。有关RocksDB性能的更多信息,请参见右侧侧栏中的”性能”部分。

块大小

rocksdb 将相邻的键分组到同一个块中,这样的块是在持久存储之间来回传输的单元。 默认块大小约为4096个未压缩字节。主要对数据库内容进行批量扫描的应用程序可能希望增加这个大小。 如果性能测试表明性能有了改进,对小值进行大量点读取的应用程序可能希望切换到更小的块大小。 使用小于1 kb或大于几mb的块没有什么好处。还要注意,如果块的大小越大,压缩就越有效。 若要更改块大小参数,请使用Options::block_size。

写缓冲区

Options::write_buffer_size 指定在转换为排序的磁盘文件之前要在内存中构建的数据量。较大的值可以提高性能,特别是在批量加载期间。 max_write_buffer_number写缓冲区可能同时保存在内存中,因此您可能希望调整此参数以控制内存使用。 此外,更大的写缓冲区将导致下一次打开数据库时更长的恢复时间。

相关的选项是 Options::max_write_buffer_number,这是在内存中构建的写缓冲区的最大数量。 默认值是2,因此当一个写缓冲区被刷新到存储中时,新的写可以继续写到另一个写缓冲区。刷新操作在线程池中执行。

Options::min_write_buffer_number_to_merge 是写入存储之前合并在一起的写缓冲区的最小数量。如果设置为1,那么所有写缓冲区将作为单独的文件刷新到L0,这将增加读取放大,因为get请求必须检入所有这些文件。 此外,如果每个单独的写缓冲区中都有重复的记录,内存中的合并可能会导致向存储写入较少的数据。默认值:1

压缩

每个块在被写入持久存储之前都被单独压缩。默认情况下压缩是打开的,因为默认压缩方法非常快,并且对于不可压缩数据自动禁用。 在极少数情况下,应用程序可能希望完全禁用压缩,但只有在基准测试显示性能改进时才应该这样做:

  1. rocksdb::Options options;
  2. options.compression = rocksdb::kNoCompression;
  3. ... rocksdb::DB::Open(options, name, ...) ....

此外,字典压缩 (https://github.com/facebook/rocksdb/wiki/Dictionary-Compression) 也是可用的

Cache 缓存

数据库的内容存储在文件系统中的一组文件中,每个文件存储一系列压缩块。 如果options.block_cache是非空的,它用于缓存常用的未压缩块内容。 我们使用操作系统文件缓存来缓存压缩后的原始数据。 因此,文件缓存充当压缩数据的缓存。

  1. #include "rocksdb/cache.h"
  2. rocksdb::BlockBasedTableOptions table_options;
  3. table_options.block_cache = rocksdb::NewLRUCache(100 * 1048576); // 100MB uncompressed cache
  4. rocksdb::Options options;
  5. options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(table_options));
  6. rocksdb::DB* db;
  7. rocksdb::DB::Open(options, name, &db);
  8. ... use the db ...
  9. delete db

在执行批量读取时,应用程序可能希望禁用缓存,以便由批量读取处理的数据不会最终替换大部分缓存的内容。一个每迭代器选项可以用来实现这一点:

  1. rocksdb::ReadOptions options;
  2. options.fill_cache = false;
  3. rocksdb::Iterator* it = db->NewIterator(options);
  4. for (it->SeekToFirst(); it->Valid(); it->Next()) {
  5. ...
  6. }

还可以通过设置选项禁用块缓存。no_block_cache为true。

有关详细信息,请参见块缓存。 (https://github.com/facebook/rocksdb/wiki/Block-Cache)

key布局

注意,磁盘传输和缓存单元是一个块。相邻键(根据数据库排序顺序)通常放在同一个块中。 因此,应用程序可以通过将一起访问的键放在彼此附近,并将不常用的键放在键空间的单独区域,从而提高其性能。

例如,假设我们正在rocksdb上实现一个简单的文件系统。我们可能希望储存的项目类别如下:

  1. filename -> permission-bits, length, list of file_block_ids
  2. file_block_id -> data

我们可能想要在文件名键前面加上一个字母(比如’/‘),而file_block_id键前面加上另一个字母(比如’0’),这样只扫描元数据就不会强制我们获取和缓存大量的文件内容。

过滤器

由于rocksdb数据在磁盘上的组织方式,单个Get()调用可能涉及从磁盘的多次读取。 可选的FilterPolicy机制可用于大幅度减少磁盘读取的数量。

  1. rocksdb::Options options;
  2. rocksdb::BlockBasedTableOptions bbto;
  3. bbto.filter_policy.reset(rocksdb::NewBloomFilterPolicy(
  4. 10 /* bits_per_key */,
  5. false /* use_block_based_builder*/));
  6. options.table_factory.reset(rocksdb::NewBlockBasedTableFactory(bbto));
  7. rocksdb::DB* db;
  8. rocksdb::DB::Open(options, "/tmp/testdb", &db);
  9. ... use the database ...
  10. delete db;
  11. delete options.filter_policy;

前面的代码将基于Bloom Filter的过滤策略与数据库关联起来。基于Bloom filter的过滤依赖于每个键在内存中保留一定数量的数据位(在本例中,每个键保留10位,因为这是我们传递给NewBloomFilter的参数)。 这个过滤器将把Get()调用所需的不必要磁盘读取数量减少大约100倍。增加每个键的比特数将导致更大幅度的降低,但要付出更多内存使用的代价。 我们建议那些工作集不适合内存且执行大量随机读取的应用程序设置筛选策略。

如果使用自定义比较器,则应确保使用的筛选器策略与比较器兼容。例如,考虑一个比较器,它在比较键时忽略尾随空格。 NewBloomFilter不能与这样的比较器一起使用。相反,应用程序应该提供一个自定义过滤器策略,该策略也忽略尾随空格。

例如:

  1. class CustomFilterPolicy : public rocksdb::FilterPolicy {
  2. private:
  3. FilterPolicy* builtin_policy_;
  4. public:
  5. CustomFilterPolicy() : builtin_policy_(NewBloomFilter(10, false)) { }
  6. ~CustomFilterPolicy() { delete builtin_policy_; }
  7. const char* Name() const { return "IgnoreTrailingSpacesFilter"; }
  8. void CreateFilter(const Slice* keys, int n, std::string* dst) const {
  9. // Use builtin bloom filter code after removing trailing spaces
  10. std::vector<Slice> trimmed(n);
  11. for (int i = 0; i < n; i++) {
  12. trimmed[i] = RemoveTrailingSpaces(keys[i]);
  13. }
  14. return builtin_policy_->CreateFilter(&trimmed[i], n, dst);
  15. }
  16. bool KeyMayMatch(const Slice& key, const Slice& filter) const {
  17. // Use builtin bloom filter code after removing trailing spaces
  18. return builtin_policy_->KeyMayMatch(RemoveTrailingSpaces(key), filter);
  19. }
  20. };

高级应用程序可能提供一个过滤器策略,该策略不使用bloom过滤器,而是使用一些其他机制来汇总一组键。 有关详细信息,请参见rocksdb/filter_policy.h。

校验和

rocksdb将校验和与它存储在文件系统中的所有数据相关联。对于这些校验和的验证力度有两个单独的控制:

ReadOptions::verify_checksums 强制对代表特定读操作从文件系统读取的所有数据进行校验和验证。这是默认打开的。

Options::paranoid_checks 可能被设置为true,然后打开数据库,使数据库实现在检测到内部损坏时立即引发错误。 根据数据库的哪个部分已损坏,在打开数据库时或稍后由另一个数据库操作时可能会引发错误。 默认情况下,关闭偏执检查,这样即使数据库的部分持久性存储已经损坏,也可以使用数据库。

如果数据库损坏(可能在启用偏执检查时无法打开),则可以使用rocksdb::RepairDB函数来恢复尽可能多的数据。

压缩

RocksDB不断重写现有的数据文件。这是为了清除键的陈旧版本,并保持数据结构最适合读取。

有关压实的信息已转移到压缩。在操作RocksDB之前,用户不必知道压缩的内部信息。

近似的大小

GetApproximateSizes 方法可用于获取一个或多个键范围使用的文件系统空间的近似字节数。

  1. rocksdb::Range ranges[2];
  2. ranges[0] = rocksdb::Range("a", "c");
  3. ranges[1] = rocksdb::Range("x", "z");
  4. uint64_t sizes[2];
  5. db->GetApproximateSizes(ranges, 2, sizes);

前面的调用将把size[0]设置为键范围[a..c]使用的文件系统空间的近似字节数,并将[1]设置为键范围[x..z]使用的近似字节数。

环境

由rocksdb实现发出的所有文件操作(和其他操作系统调用)都通过rocksdb::Env对象路由。经验丰富的客户可能希望提供他们自己的Env实现来获得更好的控制。 例如,应用程序可能在文件IO路径中引入人工延迟,以限制rocksdb对系统中其他活动的影响。

  1. class SlowEnv : public rocksdb::Env {
  2. .. implementation of the Env interface ...
  3. };
  4. SlowEnv env;
  5. rocksdb::Options options;
  6. options.env = &env;
  7. Status s = rocksdb::DB::Open(options, ...);

移植

通过提供由rocksdb/port/port.h导出的types/methods/functions的平台特定实现,可以将rocksdb移植到新平台。有关详细信息,请参见rocksdb/port/port_example.h。

此外,新平台可能需要一个新的默认rocksdb::Env实现。有关示例,请参见rocksdb/util/env_posix.h。

可管理性

为了能够有效地调优应用程序,如果您能够访问使用统计数据,那么它总是很有帮助的。 您可以通过设置Options::table_properties_collector或Options::statistics来收集这些统计信息。 有关更多信息,请参考rocksdb/table_properties.h和rocksdb/statistics.h。这些不应该给您的应用程序增加很大的开销,我们建议将它们导出到其他监视工具。 看到统计数据。您还可以使用Perf Context and IO Stats Context.(https://github.com/facebook/rocksdb/wiki/Perf-Context-and-IO-Stats-Context) 分析单个请求。用户可以为一些内部事件的回调注册EventListener(https://github.com/facebook/rocksdb/wiki/EventListener)。

清除WAL 文件

默认情况下,当旧的预写日志超出范围且应用程序不再需要它们时,将自动删除它们。有一些选项允许用户存档日志,然后以TTL方式或基于大小限制懒洋洋地删除它们。

这些选项是Options::WAL_ttl_seconds和Options::WAL_size_limit_MB。下面是它们的用法:

  • 如果两者都设置为0,日志将被尽快删除,并且永远不会进入存档。
  • 如果WAL_ttl_seconds为0,而WAL_size_limit_MB不为0,那么将每10分钟检查一次WAL文件,如果总大小大于WAL_size_limit_MB,那么将从最早的地方开始删除这些文件,直到满足size_limit。所有空文件将被删除。
  • 如果WAL_ttl_seconds不为0,而WAL_size_limit_MB为0,那么将每隔WAL_ttl_seconds / 2检查一次WAL文件,并且删除那些比WAL_ttl_seconds更老的文件。
  • 如果两个值都不为0,则每10分钟检查一次WAL文件,两次检查都将在ttl为第一的情况下执行。

其他信息

设置RocksDB选项:

Set Up Options ( https://github.com/facebook/rocksdb/wiki/Set-Up-Options )

一些详细的Tuning Guide (https://github.com/facebook/rocksdb/wiki/RocksDB-Tuning-Guide)

有关rocksdb实施的详情可参阅以下文件:

  • RocksDB Overview and Architecture
  • Format of an immutable Table file
  • Format of a log file