新钛云服已累计为您分享683篇技术干货
介绍
调优 Ceph 可能是一项艰巨的挑战。在 Ceph、RocksDB 和 Linux 内核之间,实际上有数以千计的选项可以进行调整以提高存储性能和效率。由于涉及的复杂性,比较优的配置通常分散在博客文章或邮件列表中,但是往往都没有说明这些设置的实际作用或您可能想要使用或避免使用它们的原因。这种现象的一个特别常见的例子是调优 Ceph 的 BlueStore RocksDB。
本文档将尝试解释这些选项的实际作用以及您可能想要调整它们或保持它们默认值的原因。同时还将展示基于新版 Ceph 在几种不同配置下的最新性能结果。
历史回溯
在过去的十年中,Ceph 的对象存储守护进程依赖于两个对象存储实现将用户数据写入磁盘。第一个(现已弃用)对象存储是 FileStore。
2016 年,我们开始编写一个名为 BlueStore 的新对象存储。
FileStore 使用现有的文件系统来存储对象数据,而 BlueStore 将对象数据直接存储在块设备上,并将对象元数据存储在 RocksDB 中。
在 BlueStore 开发过程的早期,我们观察到在 RocksDB 中存储元数据的开销会对性能产生巨大影响。
对于小型随机写入尤其如此,其中元数据几乎与对象数据一样大。在 2016 年秋天,我们开始调整 RocksDB,并重点关注对性能和写入放大有很大影响的 3 个设置:
max_write_buffer_number
在 RocksDB 将键值对写入数据库之前,它会将它们写入预写日志,并将它们存储在称为 memtables 的内存缓冲区中。此设置控制可以在内存中累积的最大内存表数。
请注意,此设置在整个数据库中不是全局的。相反,它应用于称为”列族“的单独数据库分区。最初编写 BlueStore 时,所有数据都存储在单个列族中。
现在我们跨多个列族对数据进行分区,这可能意味着更多的内存缓冲区和数据,除非还应用了全局限制。
write_buffer_size
在将内存表标记为不可变并将数据写入新内存表之前,可以将多少字节数据写入内存表。
min_write_buffer_number_to_merge
在这些内存表被刷新到数据库的级别 0 之前需要填充的最小内存表数。
正如我们在 2016 年(https://drive.google.com/uc?export=download&id=0B2gTBZrkrnpZRFdiYjFRNmxLblU) 发现的那样,这些设置相互交互的方式对性能和写入放大有巨大影响。为简洁起见,我们将只关注我们运行的一小部分测试用例:
Max Write Buffer Number | Min Write Buffer Number to Merge | Write Buffer Size | 4K Random Write IOPS | Data Written to RocksDB |
---|---|---|---|---|
32 | 8 | 32MiB | 64004 | 51569 |
32 | 1 | 32MiB | 40256 | 118022 |
4 | 1 | 256MiB | 62105 | 41374 |
大内存表通常比小内存表表现出更低的写入放大。如果使用小型内存表,则必须先累积几个内存表,然后再将它们刷新到数据库。每次刷新聚合大量小型 memtable 会导致性能小幅提升,但与使用大型 memtable 相比,会以额外的写入开销和驱动器磨损为代价。
出于这个原因,我们最终选择使用(最多)4 256MiB 内存表,这些内存表在满时会立即刷新。这些值作为 BlueStore 的 RocksDB 调优的一部分一直保留至今。
当前 Ceph
自从进行了最初的 RocksDB 测试以来,闪存驱动器变得更快了,BlueStore 发生了巨大变化,并且我们了解了更多关于 RocksDB 的使用如何影响性能的信息。
例如,BlueStore 不仅仅将对象元数据写入 RocksDB。它还存储内部 BlueStore 状态。这包括 pglog 更新、extents和磁盘分配等数据。其中一些数据的寿命很短:可能会被写入然后几乎立即删除。
RocksDB 处理这个问题的方式是首先将数据写入内存中的内存表,然后将其附加到磁盘上的预写日志中。当请求删除该数据时,RocksDB 会写入一个列族,指示应删除该数据。
当一次写入和随后的删除同时刷新时,只有最新的更新会保留在数据库中。但是,当这两个操作位于不同的刷新组中时(可能是因为使用了小型内存表),这两个操作可能会持久化到数据库中,从而导致写入放大增加和性能降低。
事实证明,这对我们在最初的 RocksDB 调优中看到更高的性能和更低的写入放大起到了重要作用。
随着时间的推移,其他各种 RocksDB 设置被调整或添加,最终导致 Ceph Pacific 的默认配置如下:
bluestore_rocksdb_options = compression=kNoCompression,max_write_buffer_number=4,min_write_buffer_number_to_merge=1,recycle_log_file_num=4,write_buffer_size=268435456,writable_file_max_buffer_size=0,compaction_readahead_size=2097152,max_background_compactions=2,max_total_wal_size=1073741824
附加选项总结如下:
compression = kNoCompression
不压缩数据库。由于担心 CPU 开销和延迟,在 bluestore 的开发过程中很早就被选中。
*recycle_log_file_num = 4
这个选项在 BlueStore 的开发早期就由 Sage Weil 提交给 RocksDB,以提高 WAL 写入的性能。不幸的是,在 2020 年,RocksDB 开发人员发现与他们的许多更强大的恢复模式一起使用并不安全。从RocksDB PR #6351(https://github.com/facebook/rocksdb/pull/6351)开始,RocksDB 本身通常会默认禁用此选项。
Ceph PR #36579(https://github.com/ceph/ceph/pull/36579)尝试在 RocksDB 中切换到不同的恢复模式以重新启用日志文件的回收,但最终因不安全而被关闭。到目前为止,我们还没有删除这个选项,以防 RocksDB 开发人员找到一种在幕后重新启用它的方法,但现在这似乎不太可能。
writable_file_max_buffer_size = 0
在很旧的 RocksDB 版本中,WritableFileWriter 默认总是分配 64K 的缓冲区。Ceph 不需要或使用此内存,但在将数据写入 BlueFS 时必须复制它。
RocksDB PR #1628(https://github.com/ceph/ceph/pull/36579)是为 Ceph 实现的,因此可以将初始缓冲区大小设置为小于 64K。
compaction_readahead_size = 2097152
这个选项是在Ceph PR #14932(https://github.com/ceph/ceph/pull/14932)中添加的,以大大提高压缩期间的性能。在设置此选项之前,CompactionIterator 将为每个 Next() 调用发出读取。因为读取是顺序的,所以 2MB