发布网友 发布时间:2024-12-29 07:30
共1个回答
热心网友 时间:5分钟前
优化分布式存储性能的重点在于提升日志落盘操作效率。经过多次尝试,最终实施了“预写+单线程direct io同步写”的策略,成功达成了性能目标。接下来,我们将按照时间顺序回顾在优化过程中所采用的多种方案。
初始方案中,我们采用了一个专有写线程和一个专有fsync线程。fsync操作将用户数据从操作系统页面缓存刷入磁盘,而写操作则将用户数据复制到缓存。然而,我们发现fsync操作不能指定刷盘的数据范围,导致在IO抖动时,大量待fsync的写请求积压,使得时延过高,影响SQL层WAL buffer的释放。
为了寻找解决方法,我们引入了mmap写加msync策略,msync可以指定下刷数据的范围。单独测试时,mmap & msync的时延表现优于write & fsync,满足了性能要求。但在正式版本测试中,时延出现了急剧上升,原因可能是受其他高CPU消耗线程的影响。增加空转线程后,时延显著增加,且vmstat监控发现中断数明显增加,都是由于内核相关因素造成的。
随后,我们引入了预写机制,并配合sync_file_range api来指定数据范围。然而,在使用此策略后,我们发现write操作在某些周期耗时突增,平均达到100~200us,观察发现write时延增大时对应的日志盘有磁盘读IO增加的现象。初步怀疑是预写导致的,因为使用预写文件后,写日志需要先将老页面从磁盘加载到page cache,再进行修改。在运行初期或系统内存紧张时,write操作可能会导致磁盘读操作。
经过系统tap抓取submit_bio内核函数堆栈和内核源码的分析,我们验证了上述推测。为了确保write时延的稳定性,我们需要保证有足够的内存容纳所有的预写日志文件页面且不被淘汰。但在与xxxDB共部署的场景下,系统整体内存非常紧张,基本无法保证固定预留内存空间给page cache。考虑到业务模型,日志只会写不会读,大量占用page cache内存是不经济的。因此,我们寻求了绕过page cache的方案,即direct IO。
最终,我们选择了预写文件 & 单线程direct IO同步写方案。预写文件与直接IO同步写单独测试时,write时延受其他线程和内存影响较小,较为稳定。此方案的副作用主要在于IO放大,但我们通过确保一次下刷的日志块较大,有效控制了存储空间的使用和IO放大问题。在实际TPCC大压力场景下,日志块大小约为50K,4K对齐后的IO放大比例不到10%。根据实际测试数据,在X86平台下一次50K数据内存拷贝平均约4us,在ARM平台下平均为10us。此外,由于日志文件是循环使用的,放大的一点存储空间对系统影响可以忽略不计。综合测试结果,该方案在性能优化方面效果显著。
在优化过程中,我们还注意到了一个坑点:在使用O_SYNC标记进行同步写时,虽然单独测试程序时延表现良好,但在TPCC大压力下时延增加了10多us。通过改用O_DSYNC标记,TPCC大压力下的时延下降了10多us,与单独测试程序的数据基本一致。
以上步骤展示了一个优化分布式存储日志落盘操作性能的完整流程,从初始方案的尝试到最终选择预写文件 & 单线程direct IO同步写方案,每一步都基于对性能瓶颈的深入分析和优化策略的精心设计。通过这些优化措施,我们成功提升了分布式存储的性能,为系统稳定运行提供了坚实的基础。