IO解惑:cephfs、libaio与io瓶颈
最近笔者在对kernel cephfs客户端进行fio direct随机大io读测试时发现,在numjobs不变的情况下,使用libaio作为ioengine,无论怎么调节iodepth,测试结果都变化不大,咦,这是为什么呢?

一、撇开fio,单看libaio的使用
......
rc = io_setup(maxevents, &ctx);
for (j = 0; j < IO_COUNT; j++) {
......
io_prep_pread(iocb, fd, (void *)buf_, io_size, offset);
}
rc = io_submit(ctx, IO_COUNT, &iocbray[count]);
......
rc = io_getevents(ctx, IO_COUNT, IO_COUNT, events, &timeout);
......
}
代码中,io_setup函数创建一个异步io的上下文,io_prep_pread函数准备了IO_COUNT个读请求,通过io_submit函数批量提交IO_COUNT个读请求,最后通过io_getevents函数等待请求的返回。
笔者通过该代码来对kernel cephfs客户端进行direct随机读测试,发现io_submit函数非常耗时,这完全不符合笔者对libaio的预期(io_submit提交请求应该非常快,时间应该耗费在io_getevents等待io结束上)。
笔者决定一探究竟...
二、探索libaio源码
SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr,struct iocb __user * __user *, iocbpp){
return do_io_submit(ctx_id, nr, iocbpp, 0);
}
long do_io_submit(aio_context_t ctx_id, long nr,struct iocb __user *__user *iocbpp, bool compat){
...
for (i=0; i<nr; i++) {
ret = io_submit_one(ctx, user_iocb, &tmp, compat);
}
...
}
static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,struct iocb *iocb, bool compat){
...
ret = aio_run_iocb(req, compat);
...
}
static ssize_t aio_run_iocb(struct kiocb *req, bool compat){
...
case IOCB_CMD_PREADV:
rw_op = file->f_op->aio_read;
...
}
// 后面的代码不再赘述
这段是3.10.107内核的io_submit系统调用的源码,并不复杂,总结下就是,对于批量的读请求,io_submit会逐个通过io_submit_one函数进行提交,而io_submit_one最终是调用底层文件系统的aio_read函数进行请求提交。
这里说的底层文件系统当然是cephfs文件系统,不妨来看下它的aio_read函数。
三、探索kernel cephfs源码
const struct file_operations ceph_file_fops = {
...
.read = do_sync_read,
.write = do_sync_write,
.aio_read = ceph_aio_read,
.aio_write = ceph_aio_write,
.mmap = ceph_mmap,
...
};
通过上述代码可以看出,kernel cephfs的aio_read上注册的是ceph_aio_read函数,让我们看看该函数。
static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos){
...
if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
(iocb->ki_filp->f_flags & O_DIRECT) ||
(inode->i_sb->s_flags & MS_SYNCHRONOUS) ||
(fi->flags & CEPH_F_SYNC))
/* hmm, this isn't really async... */
ret = ceph_sync_read(filp, base, len, ppos, &checkeof);
else
ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
...
}
相信你已经注意到了这条注释 /* hmm, this isn't really async... */,在direct读模式下,当上层的io_submit调用到这里时,并没有进行async的调用,而是sync调用,即请求发送后需等待结果返回。
在3.10.107内核下,由于kernel cephfs没有实现真正的aio,导致批量提交的请求,io_submit会逐一处理提交,然后等待请求结果,再处理下一请求,而非批量提交请求,批量等待请求结果,这便是io_submit耗时的原因。
四、回到fio
理解了io_submit为什么费时,也就能理解fio下以libaio作为ioengine,无论怎么调节iodepth,测试结果都变化不大的原因。所以,当底层文件系统不支持aio时,fio测试时,libaio跟sync是几乎没有差别的。
五、聊聊cephfs、libaio、fio
4.14内核上,kernel cephfs在实现上支持了libaio,笔者分别做了以sync和libaio为ioengine的fio direct随机大io读测试。
对于sync:
在numjobs数达到一定的值后,fio的带宽已经到达了瓶颈(远小于客户机的万兆网卡带宽、集群有36个sata osd),再提高numjobs数已经不再起作用,这一点笔者非常费解,原因不得而知,知晓原因的朋友可以评论中告知笔者,万分感谢。
对于libaio:
在numjobs设置成较小值(4、8)时,通过增大iodepth就可以打满kernel cephfs客户机的万兆网卡(测试文件较小,集群osd足以将其缓存)。因此,通过libaio,我们可以向ceph集群提交大量的io,这样便可以测出集群的io极限。
六、关注笔者
专注笔者公众号,阅读更多干货文章:)

IO解惑:cephfs、libaio与io瓶颈的更多相关文章
- python全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)
昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...
- JAVASE02-Unit07: 基本IO操作 、 文本数据IO操作
基本IO操作 . 文本数据IO操作 java标准IO(input/output)操作 package day07; import java.io.FileOutputStream; import ja ...
- java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException
问题描述: 严重: IOException while loading persisted sessions: java.io.WriteAbortedException: writing abort ...
- 并发式IO的解决方案:多路非阻塞式IO、多路复用、异步IO
在Linux应用编程中的并发式IO的三种解决方案是: (1) 多路非阻塞式IO (2) 多路复用 (3) 异步IO 以下代码将以操作鼠标和键盘为实例来演示. 1. 多路非阻塞式IO 多路非阻塞式IO访 ...
- socket.io问题,io.sockets.manager.rooms和io.sockets.clients('particular room')这两个函数怎么用?
为什么我用nodejs用这个两个函数获取都会出错呢?是不是socket的api改了?请问现在获取房间数和当前房间的客户怎么获取?什么函数?谢谢!!急求! 网友采纳 版本问题.io.socket ...
- 详解C#中System.IO.File类和System.IO.FileInfo类的用法
System.IO.File类和System.IO.FileInfo类主要提供有关文件的各种操作,在使用时需要引用System.IO命名空间.下面通过程序实例来介绍其主要属性和方法. (1) 文件打开 ...
- 14.4.7 Configuring the Number of Background InnoDB IO Threads 配置 后台InnoDB IO Threads的数量
14.4.7 Configuring the Number of Background InnoDB IO Threads 配置 后台InnoDB IO Threads的数量 InnoDB 使用bac ...
- System.IO.Pipelines: .NET上高性能IO
System.IO.Pipelines是一个新的库,旨在简化在.NET中执行高性能IO的过程.它是一个依赖.NET Standard的库,适用于所有.NET实现. Pipelines诞生于.NET C ...
- Perl IO:简介和常用IO模块
三篇Perl IO基础类文章: Perl的IO操作(1):文件句柄 Perl的IO操作(2):更多文件句柄的模式 Perl文件句柄相关的常见变量 IO对象和IO::Module家族模块 无论是哪种高级 ...
- 《Linux/UNIX系统编程手册》第63章 IO多路复用、信号驱动IO以及epoll
关键词:fasync_helper.kill_async.sigsuspend.sigaction.fcntl.F_SETOWN_EX.F_SETSIG.select().poll().poll_wa ...
随机推荐
- WPF教程002 - 实现Step步骤条控件
原文:WPF教程002 - 实现Step步骤条控件 在网上看到这么一个效果,刚好在用WPF做控件,就想着用WPF来实现一下 1.实现原理 1.1.该控件分为2个模块,类似ComboBox控件分为Ste ...
- 【iOS发展-49】的插件-插件该文档的凝视VVDocumenter安装与使用
文件凝视是/** */.快捷键///. 但是,这需要安装插件.VVDocumenter. 下载链接:https://github.com/onevcat/VVDocumenter-Xcode (1 ...
- 用MVVM模式开发中遇到的零散问题总结(4)——自制摄像头拍摄大头贴控件
原文:用MVVM模式开发中遇到的零散问题总结(4)--自制摄像头拍摄大头贴控件 一直有个疑问,为什么silverlight对摄像头支持这么好,WPF却一个库都没有....于是我各种苦恼啊,各种Code ...
- delphi备份恢复剪切板(使用了GlobalLock API函数和CopyMemory)
看了季世平老兄的C++代码后翻译过来的 unit clipbak; interface uses SysUtils, Classes, Clipbrd, Windows, Contnrs; type ...
- C# 读取大文件 (可以读取3GB大小的txt文件)
原文:C# 读取大文件 (可以读取3GB大小的txt文件) 在处理大数据时,有可能 会碰到 超过3GB大小的文件,如果通过 记事本 或 NotePad++去打开它,会报错,读不到任何文件. 如果你只是 ...
- delphi 操作xml示例(DelphiBBS)
自:http://www.delphibbs.com/keylife/iblog_show.asp?xid=20713 ======================================== ...
- 【Gerrit】Performance Cheat Sheet
首先说下做这件事情的主因,组内有人说Project repo sync有点慢,废话不多说,直接上图. 相关官方文档参考链接: 我的数据: ~/review_site/logs# fgrep " ...
- C# 生成txt日志文件
/// <summary> /// 创建日志文件,每天一个 /// </summary> /// <param name="logContent"&g ...
- C# 如何使用 Sql Server Compact 数据库
Sql Server Compact Edition(简称SqlCE)是一个轻量级的数据库,对于放在客户机上的程序而有需要存储数据这样的环境,使用SqlCE再合适不过了.SqlCE可以通过在VS(Vi ...
- C#图片旋转
这里以Bitmap为例说明问题. 可以看到,旋转方法需要传入一个参数,而这个参数是一个枚举类型,RotateFlipType. 系统提供了两大类型的旋转, 1.旋转后不翻转. 2.旋转后接着翻转.翻转 ...