ArangoDB 中集成的 RocksDB 存储引擎常见问题解答

2022-04-08 00:00:00 数据 文档 磁盘 冲突 引擎

全新的 ArangoDB 3.2 版本已经发布了,该版本包含了一些主要的改进内容,例如:基于 Pregel 的分布式图处理以及强大的数据导出工具。但该版本值得关注的是集成了 Facebook 的 RocksDB 作为 ArangoDB 可插入式的存储引擎。有了 RocksDB,我们就可以让 ArangoDB 支持更多的数据,只要你的磁盘足够大。

因为这是一个非常重要的改进,社区中有很多关于该引擎的问题,在这篇文章中我们将集中对这些问题予以解答。

问:我的数据能否超过系统内存的限制?

答: 是的,一旦选择了 RocksDB 存储引擎,数据库支持的数据大小仅受限于磁盘存储的大小。

问: ArangoDB 中的 RocksDB 的锁机制是怎样的?

答: 当使用 RocksDB 存储引擎时,锁是基于文档级别的写锁,而读是不会锁的。对同一个文档的并发写操作会导致 write-write 冲突,错误会返回给调用代码,因此一旦碰到这种问题,用户只需重试即可。

问: 你说的“对同一个文档的并发写操作会导致 write-write 冲突,错误会返回给调用代码”这个问题,是不是意味着跟现有内存映射文件的存储方式的锁行为是不同的?写操作不会尝试在一个文档上先申请锁吗?

答: 是的,这个锁行为更当前 MMAP 内存映射的方式是不同的。MMAP 引擎是集合级别的锁,因此不可能会出现 write-write 冲突。而 RocksDB 引擎是文档级别的锁,因此可能会导致 write-write 冲突。

请看下来的例子:两个事务 T1 和 T2 都尝试往集合 C 中写入一个文档。

在老的 MMAP 引擎中,这些事务是穿行的,如:

T1 begins
T1 writes document “a” in collection “c”
T1 commits
T2 begins
T2 writes document “a” in collection “c”
T2 commits

因此这里不会发生写冲突。

而采用 RocksDB 引擎,事务的运行的并行的,但一旦它们修改了同一个文档,就需要通过锁来阻止一些数据更新的丢失。厦门的调度会导致 write-write 冲突:

T1 begins
T2 begins
T1 writes document “a” in collection “c”
T2 writes document “a” in collection “c”

在这里,T2 将会被终止,来放置更新的丢失。对相同文档的并发写操作会导致 write-write 冲突,错误信息会返回给调用代码,因此用户只需在需要时候重试即可。

问:当使用 RocksDB 存储引擎时,我是否需要一个更快的磁盘(如 SSD)?

答: 是的,使用速度更快的磁盘对性能是有好处的,不管是 RocksDB 还是 MMAP 文件存储,都是一样的。

问: 我能否给不同的集合选择不同的存储引擎,或者为不同的数据库选择不同的存储引擎?

存储引擎的选择是针对服务器和集群的,相同的 ArangoDB 实例或者集群不能混合使用不同的存储引擎。

问: 我能否将 ArangoDB 的某个集合或者数据库的存储引擎从 RocksDB 改为内存映射文件方式?

这个每个服务器或者集群的选择。该选择是在服务器启动时就确定了。服务器启动后将会在磁盘文件中保存存储引擎的选择,并且每次重启都会验证这个文件。如果需要在服务器初始化后修改存储引擎,你可以使用 arangodump 将数据导出,然后使用一个空的数据库目录和不同的存储引擎重启 ArangoDB 服务,然后再通过 arangorestore 将之前备份的数据恢复即可。

问: 索引是只存储在磁盘吗? 或者只是存储索引的类型?

答: 如果你选择了 RocksDB 存储引擎,那么所有的索引都会持久化到磁盘中。

问: 我使用微软 Azure 云主机,有非常快的本地 SSD 磁盘,不过很不幸这个是临时的(意味着主机如果重启后就会丢失),也有速度较慢的、但是不会丢失的网络存储盘(当然也是 SSD 的)。有什么方法让我可以利用这个高性能的本地 SSD 磁盘呢?例如用它来做一些快速的查询,然后使用网络存储盘来存储持久化数据?

RocksDB 一般可以为不同级别的数据库指定不同的数据库。一般较新的数据是比较低级别的,因此可以将低级别数据先写入 SSD,然后 RocksDB 会在需要移到别数据库时将它移到慢一点的 HDD 或者网络存储盘。需要注意的是,这是 RocksDB 提供的选项,而不是 ArangoDB 提供的。一般情况下,我们不认为可以实现针对每一个查询来分别基于快的 SSD 或者慢的磁盘去做,因为一个查询可能会触及到任意的数据。但是新的数据以及一些访问比较频繁的数据会存在于 RocksDB 的内存缓存块中。

相关文章