Ceph 后端IO提交异步化

前言

从15年3月接触Ceph分布式存储系统,至今已经5年了;因为工作的需要,对Ceph的主要模块进行了较深入的学习,也在Ceph代码层面做了些许改进,以满足业务需要(我们主要使用M版本)。最近得闲,将过往的一些改进以及优化思路记录下了,希望能对后来者有所帮助。

这是第二篇:Ceph 后端IO提交异步化

背景知识

Ceph的IO写入包括写Rocksdb元数据和写Block数据两部分,等各个副本写完元数据即给客户端返回应答。如果是小IO,会现将元数据和数据打包写入Rocksdb,之后通过deferred IO的形式将数据写入Block设备,如果是大IO,会将元数据写入Rocksdb,数据以aio的方式写入Block设备。在整个IO过程中,OSD拿着PG 锁,直到元数据提交到Rocksdb才释放锁,在次过程中,该PG中后续的IO,都排队等待

Ceph OSD 进行IO时,以PG为粒度加锁,来保证一致性;在PG内,通过为每个IO事务分配一个OpSeqencer来保证IO的串行执行。

每个OSD 包含一个Rocksdb实例,BlueStore通过一个独立的线程来完成元数据的提交以及Block设备的flush。

优化思路

  1. IO事务分段处理,提前是否PG锁
    既然PG是通过OpSeqencer来保证IO的串行执行,那么在BlueStore为IO事务分配好了序列号,而不需要等到IO提交到Rocksdb就可以释放PG 锁。

处理思路:OSD通过线程池和data shard队列来提供并行性,使得不同data shard中的IO可以并发的执行;我们可以在BlueStore中同样启动一个线程池和队列,当IO事务分配好OpSeqencer后,将事务提交到队列,并释放PG锁;通过将IO事务的提交分为两个阶段,OSD可以继续处理后续的IO,而IO提交的工作交给BlueStore来处理。

  1. 关闭Rocksdb WAL,自维护WAL
    BlueStore准备好IO事务后,将事务投递到kv_queue中,通过一个线程来完成IO元数据的提交以及Block设备的flush:调用rocksdb的sync操作持久化WAL,调用block的flush操作刷新buffer cache。BlueStore只能通过一个线程来完成IO元数据的提交,是因为一个rocksdb实例,因为要写WAL,需要串行执行。如果我们关闭rocksdb的WAL,而自己维护WAL(WAL使用来做故障恢复的,所以关闭rocksdb的wal后,需要自维护WAL来保证数据一致性),那么通过多线程提交元数据应该会有更好的性能。

处理思路:配置rocksdb属性,关闭WAL;使用独立的SSD设备承载自维护WAL,将WAL磁盘划分为多个分区,每个WAL分区大小配置为2*(write_buffer_size * max_write_buffer_number)。根据配置的OSD io线程数,配置WAL线程数。这样调整后,不同线程处理的PG 可以同时提交,可以提高并发度。

Tips:上述修改有一定复杂度的,需要修改open_db中wal的处理逻辑,故障恢复下replay的逻辑,添加bluestore threadpool以及io队列,另外,io中需要先写wal,再写db,才能返回。

通过上述修改后,写IO性能有15%以上的提升。

本文只提供可行的实现思路,不提供具体的实现代码及细节,如有不清楚的地方,欢迎留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章