导读:如何打开、读写块设备。如何知道块设备大小以及设备属性?
什么是裸盘存储引擎
单机存储引擎负责高效的组织数据、索引数据、保存数据,为上层应用提供易用的接口。有一类存储引擎为了得到更高的性能,会跨过文件系统这一层调用,直接操作裸盘。那么如何实现这类存储引擎呢?本文希望以 Ceph BlueStore 为例子,介绍一下其中的实现方法。
怎么实现一个裸盘存储引擎
读写块设备
裸盘对于操作系统来说,就是一个类型为block的文件,也称之为块设备。在 BlueStore 的实现中,对于块设备作了一个抽象,声明了一个基类 BlockDevice,并实现了两个子类 KernelDevice 和 NVMEDevice,来分别对应普通的块设备以及 NVMe 块设备。
在 KernrlDevice::open 方法中,包含了打开块设备以供读写的实现。
1 | open(path.c_str(), O_RDWR | O_DIRECT); |
通过阅读代码可以知道,BlueStore 使用 DirectIO 加上 libaio 的方式来进行读写操作。使用 O_DIRECT 是为了跨过 page cache 的影响,所有的存储与缓存逻辑都由我们自己实现。使用 aio 是因为用了 O_DIRECT 直接操作块设备,操作肯定会被这些IO操作阻塞。通过 libaio 来避免数据IO阻塞前台操作。
1 | O_DIRECT (since Linux 2.4.10) |
aio 简单介绍
说到 aio,会有三个东西:
- posix aio,在用户态使用 glic 实现,维护一个线程池来模拟异步IO。接口为 aio_read/aio_write/aio_xxxx。性能较差。
- linux aio,linux 特有的 aio 实现,接口为 aio_submit/aio_cancel 等5个函数。
- libaio,oracle 对 linux aio 的包装。
取块设备大小
作为一个存储引擎,应当为上层调用方提供当前存储空间利用率接口。那么如何获取一个块设备有多大呢?
可以使用 ioctl 函数的 BLKGETSIZE/BLKGETSIZE64 来获取。BLKGETSIZE 返回的是有多少块(每块是512字节)。所以最多获取 2TB 块设备的大小(2*32 512 byte = 2TB)。为了支持更大的设备,在较新的内核上支持了 BLKGETSIZE64,返回一个 int64 类型的数字,表示块设备有多少字节。
1 |
|
microHOWTO: Get the size of a Linux block special device in C
如何获取设备的属性
属性包括块设备是否是SSD?是否支持 discard?在 linux 环境下提供了 procfs 的方式来获取这些信息。设备的属性在 /sys/block/{device name}/queue/
目录下,例如我们可以通过 /sys/block/sda/queue/rotational
文件来获取块设备是不是SSD。
1 | ➜ ~ ll /sys/block/sda/queue/ |