导读:如何打开、读写块设备。如何知道块设备大小以及设备属性?
单机存储引擎负责高效的组织数据、索引数据、保存数据,为上层应用提供易用的接口。有一类存储引擎为了得到更高的性能,会跨过文件系统这一层调用,直接操作裸盘。那么如何实现这类存储引擎呢?本文希望以 Ceph BlueStore 为例子,介绍一下其中的实现方法。
裸盘对于操作系统来说,就是一个类型为block的文件,也称之为块设备。在 BlueStore 的实现中,对于块设备作了一个抽象,声明了一个基类 BlockDevice,并实现了两个子类 KernelDevice 和 NVMEDevice,来分别对应普通的块设备以及 NVMe 块设备。
在 KernrlDevice::open 方法中,包含了打开块设备以供读写的实现。
open(path.c_str(), O_RDWR | O_DIRECT);
通过阅读代码可以知道,BlueStore 使用 DirectIO 加上 libaio 的方式来进行读写操作。使用 O_DIRECT 是为了跨过 page cache 的影响,所有的存储与缓存逻辑都由我们自己实现。使用 aio 是因为用了 O_DIRECT 直接操作块设备,操作肯定会被这些IO操作阻塞。通过 libaio 来避免数据IO阻塞前台操作。
O_DIRECT (since Linux 2.4.10)
Try to minimize cache effects of the I/O to and from this
file. In general this will degrade performance, but it is
useful in special situations, such as when applications do
their own caching. File I/O is done directly to/from user-
space buffers. The O_DIRECT flag on its own makes an effort
to transfer data synchronously, but does not give the
guarantees of the O_SYNC flag that data and necessary metadata
are transferred. To guarantee synchronous I/O, O_SYNC must be
used in addition to O_DIRECT. See NOTES below for further
discussion.
aio 简单介绍
说到 aio,会有三个东西:
作为一个存储引擎,应当为上层调用方提供当前存储空间利用率接口。那么如何获取一个块设备有多大呢?
可以使用 ioctl 函数的 BLKGETSIZE/BLKGETSIZE64 来获取。BLKGETSIZE 返回的是有多少块(每块是512字节)。所以最多获取 2TB 块设备的大小(2*32 512 byte = 2TB)。为了支持更大的设备,在较新的内核上支持了 BLKGETSIZE64,返回一个 int64 类型的数字,表示块设备有多少字节。
#include <fcntl.h>
#include <linux/fs.h>
main(int argc, char **argv)
{
int fd;
unsigned long numblocks=0;
fd = open(argv[1], O_RDONLY);
ioctl(fd, BLKGETSIZE, &numblocks);
close(fd);
printf("Number of blocks: %lu, this makes %.3f GB\n", numblocks,
(double)numblocks * 512.0 / (1024 * 1024 * 1024));
}
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。
➜ ~ ll /sys/block/sda/queue/
total 0
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 add_random
-r--r--r-- 1 root root 4.0K 8月 28 19:41 chunk_sectors
-r--r--r-- 1 root root 4.0K 8月 28 19:41 dax
-r--r--r-- 1 root root 4.0K 8月 28 19:41 discard_granularity
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 discard_max_bytes
-r--r--r-- 1 root root 4.0K 8月 28 19:41 discard_max_hw_bytes
-r--r--r-- 1 root root 4.0K 8月 28 19:41 discard_zeroes_data
-r--r--r-- 1 root root 4.0K 8月 28 19:41 hw_sector_size
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 io_poll
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 io_poll_delay
drwxr-xr-x 2 root root 0 8月 28 19:41 iosched
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 iostats
-r--r--r-- 1 root root 4.0K 8月 28 19:41 logical_block_size
-r--r--r-- 1 root root 4.0K 8月 28 19:41 max_discard_segments
-r--r--r-- 1 root root 4.0K 8月 28 19:41 max_hw_sectors_kb
-r--r--r-- 1 root root 4.0K 8月 28 19:41 max_integrity_segments
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 max_sectors_kb
-r--r--r-- 1 root root 4.0K 8月 28 19:41 max_segments
-r--r--r-- 1 root root 4.0K 8月 28 19:41 max_segment_size
-r--r--r-- 1 root root 4.0K 8月 28 19:41 minimum_io_size
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 nomerges
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 nr_requests
-r--r--r-- 1 root root 4.0K 8月 28 19:41 optimal_io_size
-r--r--r-- 1 root root 4.0K 8月 28 19:41 physical_block_size
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 read_ahead_kb
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 rotational
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 rq_affinity
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 scheduler
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 wbt_lat_usec
-rw-r--r-- 1 root root 4.0K 8月 28 19:41 write_cache
-r--r--r-- 1 root root 4.0K 8月 28 19:41 write_same_max_bytes
-r--r--r-- 1 root root 4.0K 8月 28 19:41 write_zeroes_max_bytes
-r--r--r-- 1 root root 4.0K 8月 28 19:41 zoned
➜ ~ cat /sys/block/sda/queue/rotational
1
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。