4

Ceph RocksDB 深度调优

 2 years ago
source link: https://www.51cto.com/article/717546.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Ceph RocksDB 深度调优

作者:祝祥 翻译 2022-08-31 08:04:08
本文档将尝试解释这些选项的实际作用以及您可能想要调整它们或保持它们默认值的原因。同时还将展示基于新版 Ceph 在几种不同配置下的最新性能结果。

调优 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

32MiB

64004

51569

32MiB

40256

118022

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 的预读在减少读取开销方面非常有效。

  • max_background_compactions = 2  

这个选项是在Ceph PR #29027(https://github.com/ceph/ceph/pull/29027)中添加的,经过测试表明它不会损害 RBD 或 rados 写入工作负载,同时将繁重的 OMAP 写入工作负载性能提高约 50%。此选项不适用于在级别 0 中发生的压缩,但可能会允许在其他级别中进行并行压缩。RocksDB 现在建议使用max_background_jobs设置来控制压缩和刷新行为。

  • max_total_wal_size = 1073741824  

此选项限制预写日志中数据的总大小。在 RocksDB 列族分片合并后,观察到 RocksDB WAL 消耗的空间显着增加。这几乎可以肯定是因为每个列族最多可以有 4 256MiB 缓冲区,而我们现在有超过 1 个列族。在Ceph PR #35277(https://github.com/ceph/ceph/pull/35277)中添加了此选项,以将整体 WAL 大小限制为 1GB,这是以前使用 4 256MB 缓冲区可以增长到的最大大小。

为了尝试提高 NVMe 驱动器上的 OSD 性能,过去几年来 Ceph 邮件列表和博客文章中一直流传着一种常用的 RocksDB 配置:

bluestore_rocksdb_options = compression=kNoCompression,max_write_buffer_number=32,min_write_buffer_number_to_merge=2,recycle_log_file_num=32,compaction_style=kCompactionStyleLevel,write_buffer_size=67108864,target_file_size_base=67108864,max_background_compactions=31,level0_file_num_compaction_trigger=8,level0_slowdown_writes_trigger=32,level0_stop_writes_trigger=64,max_bytes_for_level_base=536870912,compaction_threads=32,max_bytes_for_level_multiplier=8,flusher_threads=8,compaction_readahead_size=2MB

除了已经描述的选项之外,备用调整也在调整:

target_file_size_base这是级别 1 中 sst 文件的基本大小。每个后续级别都会将target_file_size_multiplier的附加乘数应用于此基本文件大小

  • level0_file_num_compaction_trigger

这控制在触发压缩到级别 1 之前可以在级别 0 中累积的文件数。级别 0 的总大小由以下公式控制: write_buffer_size * min_write_buffer_number_to_merge * level0_file_num_compaction_trigger

  • level0_slowdown_writes_trigger

在限制写入之前可以在级别 0 中累积的文件数

  • level0_stop_writes_trigger

在写入停止之前可以在级别 0 中累积的文件数

  • max_bytes_for_level_base

这是级别 1 的总大小和其他级别的基本大小。根据 RocksDB 调优指南,最好将级别 1 配置为与级别 0 相同的大小。每个后续级别都会将max_bytes_for_level_multiplier的附加乘数应用于此基本级别大小

  • max_bytes_for_level_multiplier

这是级别 1 之后的后续级别的字节乘数。如果max_bytes_for_level_base = 200MB 且max_bytes_for_level_multiplier = 10,则级别 1 最多可以包含 200MB,级别 2 最多可以包含 2000MB,级别 3 可以包含 20000MB,依此类推

  • flusher_threadsRocksDB

的高优先级池中用于将 memtables 刷新到数据库的线程数。RocksDB 现在建议使用max_background_jobs选项控制压缩和刷新行为

这种交替调整中的一些选项看起来有点可疑。通常 Ceph OSD 最多只使用 6-10 个内核,并且通常配置为使用更少。这些设置允许 RocksDB 生成多达 32 个低优先级线程用于压缩和 8 个高优先级线程用于刷新。基于在编写 BlueStore 时执行的初始 RocksDB 测试,具有更频繁刷新的小型 memtable 可能更容易在数据库中产生更高的写入放大。此外,此调整缺少添加到 RocksDB for Ceph 的一些选项以及添加列族分片后引入的全局 WAL 限制。


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK