当前位置: 首页 > 科技观察

CephRocksDB深度调优

时间:2023-03-12 03:29:36 科技观察

简介调优Ceph可能是一项艰巨的挑战。在Ceph、RocksDB和Linux内核之间,实际上有数以千计的选项可以调整以提高存储性能和效率。由于涉及的复杂性,最佳配置通常散布在博客文章或邮件列表中,但通常没有解释这些设置的实际作用或者为什么您可能想要使用或避免它们。这种现象的一个特别常见的例子是调优Ceph的BlueStoreRocksDB。本文档将尝试解释这些选项的实际作用以及为什么您可能想要调整它们或将它们保留为默认值。它还将显示基于新版本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级之前需要填充的最小内存表数。Aswediscoveredin2016(https://drive.google.com/uc?export=download&id=0B2gTBZrkrnpZRFdiYjFRNmxLblU),thewaythesesettingsinteractwitheachotherhasahugeimpactonperformanceandwriteamplification.为简洁起见,我们将只关注我们运行的一小部分测试用例:MaxWriteBufferNumberMinWriteBufferNumbertoMergeWriteBufferSize4KRandomWriteIOPSDataWrittentoRocksDB32832MiB640045156932132MiB4025611802241256MiB6210541374大内存表通常比小内存表表现出更低的写入放大.Ifyouusesmallmemtables,youmustaccumulateseveralmemtablesbeforeflushingthemtothedatabase.Aggregatingalargenumberofsmallmemtablesperflushresultsinasmallperformancegain,butatthecostofadditionalwriteoverheadanddrivewearcomparedtousinglargememtables.Forthisreason,weendedupoptingtouse(upto)4256MiBmemtablesthatareflushedimmediatelywhenfull.Thesevalues??havebeenpreservedtothisdayaspartofBlueStore'sRocksDBtuning.CurrentCephFlashdriveshavegottenfastersincetheinitialRocksDBtests,BlueStorehaschangeddramatically,andwe'velearnedmoreabouthowRocksDBusageaffectsperformance.Forexample,BlueStoredoesn'tjustwriteobjectmetadatatoRocksDB.ItalsostoresinternalBlueStorestate.Thisincludesdatasuchaspglogupdates,extents,anddiskallocations.Someofthisdatahasashortlifespan:itmaybewrittenandthendeletedalmostimmediately.ThewayRocksDBhandlesthisisbyfirstwritingthedatatoanin-memorymemtable,whichisthenappendedtoawrite-aheadlogondisk.Whenarequestismadetodeletethatdata,RocksDBwritesacolumnfamilyindicatingthatthedatashouldbedeleted.Whenawriteandsubsequentdeleteareflushedatthesametime,onlythemostrecentupdateremainsinthedatabase.However,whenthesetwooperationsareindifferentflushgroups(perhapsbecauseoftheuseofsmallmemtables),thetwooperationsmaybepersistedtothedatabase,resultinginincreasedwriteamplificationandreducedperformance.事实证明,这对我们在最初的RocksDB调优中看到的更高性能和更低写入放大起到了重要作用。随着时间的推移,各种其他RocksDB设置被调整或添加,最终在CephPacific中使用以下默认配置: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,write_buffer_number_to_merge=1,recycle_log_file_num=4,write_buffer_size=268435456,write_buffer_size=268435456,write,compaction_readahead_size=2097152,max_background_compactions=2,max_total_wal_size=1073741824附加选项总结如下:compression=kNoCompression不压缩数据库。由于担心CPU开销和延迟,在bluestore开发的早期就选择了它。*recycle_log_file_num=4该选项在BlueStore开发初期由SageWeil提交给RocksDB,用于提高WAL写入的性能。不幸的是,在2020年,RocksDB开发人员发现使用他们许多更强大的恢复模型并不安全。从RocksDBPR#6351(https://github.com/facebook/rocksdb/pull/6351)开始,RocksDB本身通常默认禁用此选项。CephPR#36579(https://github.com/ceph/ceph/pull/36579)试图通过切换到RocksDB中的不同恢复模型来重新启用日志文件的回收,但最终因不安全而关闭。到目前为止,我们还没有删除这个选项,以防RocksDB开发人员找到一种方法在幕后重新启用它,但现在看来不太可能。writable_file_max_buffer_size=0在非常老的RocksDB版本中,WritableFileWriter默认总是分配一个64K的缓冲区。Ceph不需要或使用这块内存,但在向BlueFS写入数据时必须复制它。RocksDBPR#1628(https://github.com/ceph/ceph/pull/36579)是为Ceph实现的,因此可以将初始缓冲区大小设置为小于64K。compaction_readahead_size=2097152此选项已添加到CephPR#14932(https://github.com/ceph/ceph/pull/14932)中以大大提高压缩期间的性能。在设置此选项之前,CompactionIterator将为每个Next()调用发出一个读取。因为读取是顺序的,所以2MB预读对于减少读取开销非常有效。max_background_compactions=2此选项已添加到CephPR#29027(https://github.com/ceph/ceph/pull/29027)中,并且已经过测试并证明不会损害RBD或rados写入工作负载,同时拉动繁重的OMAP写入工作负载性能提高了约50%。此选项不适用于发生在级别0中的压缩,但可能允许在其他级别进行并行压缩。RocksDB现在建议使用max_background_jobs设置来控制压缩和刷新行为。max_total_wal_size=1073741824此选项限制预写日志中数据的总大小。在RocksDB列族分片合并后,观察到RocksDBWAL消耗的空间显着增加。这几乎可以肯定是因为每个列族最多可以有4个256MiB缓冲区,而我们现在有不止1个列族。此选项已添加到CephPR#35277(https://github.com/ceph/ceph/pull/35277)中以将整体WAL大小限制为1GB,这是以前它可以增长到4256MB缓冲区大小的最大值。替代调整为了提高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这是level1中sst文件的基本大小。随后的每个级别都会将target_file_size_multiplier的附加乘数应用到此基本文件大小level0_file_num_compaction_triggerThis控制在触发压缩到级别1之前可以在级别0中累积的文件数。level0的总大小由以下公式控制:write_buffer_size*min_write_buffer_number_to_merge*level0_file_num_compaction_triggerlevel0_slowdown_writes_triggerthrottlingwrites之前level0可以累积的文件数level0_stop_writes_triggerwritestop之前level0可以累积的文件数max_bytes_for_level_basethis是其他级别的总大小和基本大小。根据RocksDB调优指南,最好将level1配置为与level0大小相同。每个后续级别都会将max_bytes_for_level_multiplier的额外乘数应用到此基本级别大小max_bytes_for_level_multiplier这是level1之后后续级别的字节乘数.如果max_bytes_for_level_base=200MB和max_bytes_for_level_multiplier=10,那么level1最多可以包含200MB,level2最多可以包含2000MB,level3最多可以包含20000MB,等等flusher_threadsRocksDB的高优先级池中用于刷新的线程数memtables到数据库。RocksDB现在建议使用max_background_jobs选项来控制压缩和刷新行为。此替代调整中的某些选项看起来有点可疑。通常CephOSD最多只使用6-10个内核,并且通常配置为使用更少的内核。这些设置允许RocksDB生成多达32个低优先级线程用于压缩和8个高优先级线程用于刷新。根据在编写BlueStore时执行的初始RocksDB测试,具有更频繁刷新的较小内存表可能更容易在数据库中产生更高的写入放大。此外,此调整缺少一些添加到RocksDBforCeph的选项以及添加列族分片后引入的全局WAL限制。