最近笔者在对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. C++ string的那些坑,C++ string功能补充(类型互转,分割,合并,瘦身) ,c++ string的内存本质(简单明了的一个测试)

    1. size_type find_first_of( const basic_string &str, size_type index = 0 ); 查找在字符串中第一个与str中的某个字符 ...

  2. XP双网卡不能上网的问题

    转载. 现在很多本本都是双网卡配置,让两个网卡分别负责连接内外网能够加快上网速度和连接稳定,但不少网友照做后会出现无法上网的情况,这是由于默认网关冲突所导致的.那么该如何处理让双网卡各行其是,互不干扰 ...

  3. DOS符号转义(转 http://www.robvanderwoude.com/escapechars.php)

    Escape Characters Character to be escaped Escape Sequence Remark % %% May not always be required in ...

  4. WCF SOAP用法

    基本思路 1.新建一个WCF服务库2.在客户端引用处右键,添加服务引用   点击发现,选择目标服务设置好命名空间   可以在高级一栏里面,设置详细信息   点击确认,添加服务引用 3.在客户端自动生成 ...

  5. mysql数据库编码、字段编码、表编码 专题

    CREATE DATABASE `mybatis-subject` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin */ 其中的 ...

  6. 最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保留一块内存

    申请效率的比较 栈:由系统自动分配,速度较快.但程序员是无法控制的. 堆:是由new分配的内存,最好的方式是用VirtualAlloc分配虚拟内存,它既不是在堆也不是在栈,而是直接在进程的地址空间中保 ...

  7. 使用NEWSEQUENTIALID解决GUID聚集索引问题

    原文:使用NEWSEQUENTIALID解决GUID聚集索引问题 UNIQUEIDENTIFIER做主键(Primary Key)是一件很方便的事情,在数据合并等操作中有不可替代的优势 但是由于普通的 ...

  8. C#匿名方法返回值赋值给变量

    The problem here is that you've defined an anonymous method which returns a string but are trying to ...

  9. android 录屏

    录屏,google了一下,记录下来,以免FQ android 4.4 录屏可通过adb:adb shell screenrecord /sdcard/video.mp4 (未测试) android 5 ...

  10. 漫步Facebook开源C++库Folly之string类设计(散列、字符串、向量、内存分配、位处理等,小部分是对现有标准库和Boost库功能上的补充,大部分都是基于性能的需求而“重新制造轮子”)

    就在近日,Facebook宣布开源了内部使用的C++底层库,总称folly,包括散列.字符串.向量.内存分配.位处理等,以满足大规模高性能的需求. 这里是folly的github地址:https:// ...