【背景】
ceph后端支持多种存储引擎,以插件的方式进行管理和使用,默认使用filestore,如ext4、btrfs,xfs。理论上每个文件系统都实现了POSIX协议,但是每个文件系统都会有那么一些不标准的地方。主要存在以下几个方面:
1. Ceph的实现非常注重可靠性,因而需要为每种文件系统引入不同的Walkaround或者Hack;例如Rename不幂等性,等等。这些工作为Ceph的不断开发带来了很大负担。
2. FileStore构建与Linux文件系统之上。POSIX提供了非常强大的功能,但大部分并不是Ceph真正需要的;这些功能成了性能的累赘。另一方面,文件系统的某些功能实现对Ceph并不友好,例如对目录遍历顺序的要求等等。
3. 日志双写问题。为了保证覆写中途断电能够恢复,以及为了实现单OSD内的事务支持,在FileStore的写路径中,Ceph首先把数据和元数据修改写入日志,日志完后后,再把数据写入实际落盘位置。这种日志方法(WAL)是数据库和文件系统标准的保证ACID的方法。但用在Ceph这里,带来了问题:
数据被写入两遍,即日志双写问题,这意味着Ceph牺牲了一半的磁盘吞吐量。
(1) Ceph的FileStore做了一遍日志,而Linux文件系统自身也有日志机制,实际上日志被多做了一遍。
(2) 对于新型的LSM-Tree类存储,如RocksDB、LevelDB,由于数据本身就按照日志形式组织,实际上没有再另加一个单独的WAL的必要。
(3) 更好地发挥SSD/NVM存储介质的性能。与磁盘不同,基于Flash的存储有更高的并行能力,需要加以利用。CPU处理速度逐渐更不上存储,因而需要更好地利用多核并行。存储中大量使用的队列等,容易引发并发竞争耗时,也需要优化。另一方面,RocksDB对SSD等有良好支持,它为BlueStore所采用。
另外,社区曾经为了FileStore的问题,提出用LevelDB作存储后端;对象存储转换为KeyValue存储,而不是转换问文件。后来,LevelDB存储没有被推广开,主流还是使用FileStore。但KeyValue的思路被沿用下来,BlueStore就是使用RocksDB来存储元数据的。
【BlueStore架构】
bluestore诞生的初衷就是为了解决filestore journal of journal 造成的写放大问题,并对ssd做了优化,因此bluestore相对于filestore主要做了两方面的核心工作:
1. 去掉journal,直接管理裸设备;
2. 针对SSD进行单独优化。
bluestore的整体架构如下图:
其中Allocator实现对裸设备的管理,直接将数据保存到设备上;metadata元数据使用RocksDB进行保存,底层自行封装了一个BlueFS用来对接RocksDB与裸设备。
Allocator 模块:
管理object数据的存放,即指派具体的实际存储空间用来存储当前的object数据,是采用bitmap的方式来实现allocator,同时采用层级索引来存储多种状态,这种方式对内存的消耗相对较小,平均1TB磁盘需要大概35MB左右的ram空间。
核心模块:
- RocksDB:存储预先写式日志,数据对象元数据,ceph的omap数据信息,以及分配器的元数据;
- BlueRocksEnv:与RocksDB进行交互的接口;
- BlueFS:解决元数据,文件空间及磁盘空间的分配和管理,并实现rocksdb:Env接口(存储RocksDB日志和sst文件)。因为rocksdb常规来说是运行在文件系统的顶层,下面是BlueFS。 它是数据存储后端层,RocksDB的数据和BlueStore中的真正数据被存储在同一个块物理设备
- BlockDevice:HDD/SSD,物理块设备,存放实际数据。
BlueStore模块:
在filestore中,对象的表现形式是对应到文件系统里的文件,默认是4MB,但是在bluestore中,已经没有传统意义上的文件系统,而是自己管理裸盘,因此需要有元数据来管理对象,对应的就是Onode,Onode是常驻内存的数据结构,持久化的时候会以kv的形式存放到rocksdb中。
BlueStore的设计特点如下:
- ceph并不需要POSIX文件系统。抛弃它实现一个尽量简单的文件系统,专门给rocksDB使用,这个文件系统叫BlueFS;
- 元数据存储在RocksDB中,用KeyValue方式存放,而数据不需要文件系统,直接存放在裸块设备上即可。那么我们在块设备上需要一个空间分配器(Allocator)
Blustore中的不同组件可以使用不同的设备。例如给RocksDB的WAL文件配置NVRAM,给SST文件配置SSD,将数据文件分配在HDD上,方案特别灵活。
【BlueStore的元数据管理】
对象是如何映射到磁盘数据结构上?Onode代表对象,名字大概是从Linux VFS的Inode沿袭过来的。Onode常驻内存,在RocksDB中以KeyValue形式持久化;Onode包含多个lextent,即逻辑extent。Blob通过映射pextent、即物理extent,映射到磁盘上的物理区域。Blob通常包括来自同一个对象的多段数据,但是也可能被其它对象引用。Bnode是对象快照后,被用于多个对象共享数据的。
上面仅是关于对象映射的。更进一步,RocksDB中存储有许多类型的元数据,包括块分配、对象集合、快照、延迟写(Deferred Writes)、对象属性(Omap,即一个对象上可以附加一些KeyValue对作为属性,例如给图片加上地点、日期等),等等。
【BlueStore写处理】
ceph的事务只工作于单个OSD内,能够保证多个对象操作被ACID地执行,主要用于实现自身的高级功能。每个pg内有一个OpSequencer,通过它来保证PG的操作按序执行。事务处理的写分三种:
1. 写到新区域。考虑ACID,因为此中写入不覆盖原来的数据,即使中途掉电,因为RocksDB中的元数据没有更新,不用担心ACID语义被破坏,RocksDB的元数据更新是在数据写之后做的。因此,日志是不需要的。在数据写完之后,元数据更新写入RocksDB,RocksDB本身支持事务,元数据更新作为RocksDB的事务提交即可。