最近笔者在对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瓶颈的更多相关文章

  1. python全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)

    昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...

  2. JAVASE02-Unit07: 基本IO操作 、 文本数据IO操作

    基本IO操作 . 文本数据IO操作 java标准IO(input/output)操作 package day07; import java.io.FileOutputStream; import ja ...

  3. java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException

    问题描述: 严重: IOException while loading persisted sessions: java.io.WriteAbortedException: writing abort ...

  4. 并发式IO的解决方案:多路非阻塞式IO、多路复用、异步IO

    在Linux应用编程中的并发式IO的三种解决方案是: (1) 多路非阻塞式IO (2) 多路复用 (3) 异步IO 以下代码将以操作鼠标和键盘为实例来演示. 1. 多路非阻塞式IO 多路非阻塞式IO访 ...

  5. socket.io问题,io.sockets.manager.rooms和io.sockets.clients('particular room')这两个函数怎么用?

    为什么我用nodejs用这个两个函数获取都会出错呢?是不是socket的api改了?请问现在获取房间数和当前房间的客户怎么获取?什么函数?谢谢!!急求!     网友采纳 版本问题.io.socket ...

  6. 详解C#中System.IO.File类和System.IO.FileInfo类的用法

    System.IO.File类和System.IO.FileInfo类主要提供有关文件的各种操作,在使用时需要引用System.IO命名空间.下面通过程序实例来介绍其主要属性和方法. (1) 文件打开 ...

  7. 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 ...

  8. System.IO.Pipelines: .NET上高性能IO

    System.IO.Pipelines是一个新的库,旨在简化在.NET中执行高性能IO的过程.它是一个依赖.NET Standard的库,适用于所有.NET实现. Pipelines诞生于.NET C ...

  9. Perl IO:简介和常用IO模块

    三篇Perl IO基础类文章: Perl的IO操作(1):文件句柄 Perl的IO操作(2):更多文件句柄的模式 Perl文件句柄相关的常见变量 IO对象和IO::Module家族模块 无论是哪种高级 ...

  10. 《Linux/UNIX系统编程手册》第63章 IO多路复用、信号驱动IO以及epoll

    关键词:fasync_helper.kill_async.sigsuspend.sigaction.fcntl.F_SETOWN_EX.F_SETSIG.select().poll().poll_wa ...

随机推荐

  1. Kitto2 now with free opensource Kide2 since September 2017(提供Web解决方案,大概是觉得Mobile开发快差不多了)

    Kitto2 is a tool for data-driven web application Development. It allows to create Rich Internet Appl ...

  2. Bootstrap Edit 使用方法

    Getting Started <!-- rounded edit text --> <com.beardedhen.androidbootstrap.BootstrapEditTe ...

  3. .net reactor 学习系列(三)---.net reactor代码自动操作相关保护功能

    原文:.net reactor 学习系列(三)---.net reactor代码自动操作相关保护功能         接上篇,上篇已经学习了界面的各种功能以及各种配置,这篇准备学习下代码控制许可证. ...

  4. 关于 IIS 上运行 ASP.NET Core 站点的“HTTP 错误 500.19”错误

    昨天回答了博问中的一个问题 —— “HTTP 错误 500.19 - Internal Server Error dotnetcore”,今天在这篇随笔中时候事后诸葛亮地小结一下. 服务器是 Wind ...

  5. jquery 表格练习

    <!DOCTYPE html><html lang="en" xmlns="http://www.w3.org/1999/xhtml"> ...

  6. 创建hexo风格的markdown页面

    最近在用 nodejs 搭建一个个人博客,博客当然要有编辑文章的功能啦.个人比较偏爱 hexo 风格的 markdown 格式,所以想自己的博客也是这样的风格.尝试了几个库,发现 marked 的转换 ...

  7. svn文件合并

     cd 目标目录svn merge -r 开始版本号:结束版本号 源目录或单个文件URL或svn merge 源目录或单个文件URL

  8. InnoSetup提升系统管理员权限(通过破解方式修改?)

    PrivilegesRequired=admin 1 2 3 4 5   找到```INNO```安装目录下的```SetupLdr.e32```文件(其实就是一个exe程序),将程序中的```Man ...

  9. WPF 添加外部ResourceDirectory

    如果Resource资源文件在程序集中,可直接如下将资源文件添加当当前运行时 Application.Current.Resources.MergedDictionaries.Add(new Reso ...

  10. C#高性能大容量SOCKET并发(三):接收、发送

    原文:C#高性能大容量SOCKET并发(三):接收.发送 异步数据接收有可能收到的数据不是一个完整包,或者接收到的数据超过一个包的大小,因此我们需要把接收的数据进行缓存.异步发送我们也需要把每个发送的 ...