Fio压测工具和io队列深度理解和误区
随着块设备的发展,特别是SSD盘的出现,设备的并行度越来越高。利用好这些设备,有个诀窍就是提高设备的iodepth, 一把喂给设备更多的IO请求,让电梯算法和设备有机会来安排合并以及内部并行处理,提高总体效率。
应用使用IO通常有二种方式:同步和异步。 同步的IO一次只能发出一个IO请求,等待内核完成才返回,这样对于单个线程iodepth总是小于1,但是可以透过多个线程并发执行来解决,通常我们会用16-32根线程同时工作把iodepth塞满。 异步的话就是用类似libaio这样的linux native aio一次提交一批,然后等待一批的完成,减少交互的次数,会更有效率。
io队列深度通常对不同的设备很敏感,那么如何用fio来探测出合理的值呢?
让我们先来看下和iodepth相关的参数:
iodepth=int
Number of I/O units to keep in flight against the file. Note that increasing iodepth beyond 1 will not affect synchronous ioengines
(except for small degress when verify_async is in use). Even async engines my impose OS restrictions causing the desired depth not to be
achieved. This may happen on Linux when using libaio and not setting direct=1, since buffered IO is not async on that OS. Keep an eye on
the IO depth distribution in the fio output to verify that the achieved depth is as expected. Default:
1.
iodepth_batch=int
Number of I/Os to submit at once. Default: iodepth.
iodepth_batch_complete=int
This defines how many pieces of IO to retrieve at once. It defaults to 1 which
means that we’ll ask for a minimum of 1 IO in the retrieval process from the kernel. The IO retrieval will go on until we hit the limit
set by iodepth_low. If this variable is set to 0, then fio will always check for completed events before queuing more IO. This helps
reduce IO latency, at the cost of more retrieval system calls.
iodepth_low=int
Low watermark indicating when to start filling the queue again. Default: iodepth.
direct=bool
If true, use non-buffered I/O (usually O_DIRECT). Default: false.
fsync=int
How many I/Os to perform before issuing an fsync(2) of dirty data. If 0, don’t sync. Default: 0.
这几个参数在libaio的引擎下的作用,文档写的挺明白,但容我再罗嗦下IO请求的流程:
libaio引擎会用这个iodepth值来调用io_setup准备个可以一次提交iodepth个IO的上下文,同时申请个io请求队列用于保持IO。 在压测进行的时候,系统会生成特定的IO请求,往io请求队列里面扔,当队列里面的IO个数达到iodepth_batch值的时候,就调用io_submit批次提交请求,然后开始调用io_getevents开始收割已经完成的IO。 每次收割多少呢?由于收割的时候,超时时间设置为0,所以有多少已完成就算多少,最多可以收割iodepth_batch_complete值个。随着收割,IO队列里面的IO数就少了,那么需要补充新的IO。 什么时候补充呢?当IO数目降到iodepth_low值的时候,就重新填充,保证OS可以看到至少iodepth_low数目的io在电梯口排队着。
注意:这些参数在文档里面描述的有点小问题,比如说默认值什么的是不太对的,所以我的建议是这些参数要去显示的写。
如何确认fio安装我们的配置在工作呢? fio提高了诊断办法 --debug=io ,我们来演示下:
# cat nvdisk-test [global] bs=512 ioengine=libaio userspace_reap rw=randrw rwmixwrite=20 time_based runtime=180 direct=1 group_reporting randrepeat=0 norandommap ramp_time=6 iodepth=16 iodepth_batch=8 iodepth_low=8 iodepth_batch_complete=8 exitall [test] filename=/dev/nvdisk0 numjobs=1
fio任务配置里面有几个点需要非常注意:
1. libaio工作的时候需要文件direct方式打开。
2. 块大小必须是扇区的倍数。
3. userspace_reap提高异步IO收割的速度。
4. ramp_time的作用是减少日志对高速IO的影响。
5. 只要开了direct,fsync就不会发生。
# fio nvdisk-test --debug=io fio: set debug option io io 22441 load ioengine libaio io 22441 load ioengine libaio test: (g=0): rw=randrw, bs=512-512/512-512, ioengine=libaio, iodepth=16 fio 2.0.5 Starting 1 process io 22444 invalidate cache /dev/nvdisk0: 0/8589926400 io 22444 fill_io_u: io_u 0x6d3210: off=3694285312/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d3210: off=3694285312/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d3210)=0 io 22444 queue: io_u 0x6d3210: off=3694285312/len=512/ddir=0//dev/nvdisk0 io 22444 fill_io_u: io_u 0x6d2f80: off=4595993600/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d2f80: off=4595993600/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d2f80)=0 io 22444 queue: io_u 0x6d2f80: off=4595993600/len=512/ddir=0//dev/nvdisk0 io 22444 fill_io_u: io_u 0x6d2cb0: off=3825244160/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d2cb0: off=3825244160/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d2cb0)=0 io 22444 queue: io_u 0x6d2cb0: off=3825244160/len=512/ddir=0//dev/nvdisk0 io 22444 fill_io_u: io_u 0x6d29a0: off=6994864640/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d29a0: off=6994864640/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d29a0)=0 io 22444 queue: io_u 0x6d29a0: off=6994864640/len=512/ddir=0//dev/nvdisk0 io 22444 fill_io_u: io_u 0x6d2710: off=2572593664/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d2710: off=2572593664/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d2710)=0 io 22444 queue: io_u 0x6d2710: off=2572593664/len=512/ddir=0//dev/nvdisk0 io 22444 fill_io_u: io_u 0x6d2400: off=3267822080/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d2400: off=3267822080/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d2400)=0 io 22444 queue: io_u 0x6d2400: off=3267822080/len=512/ddir=0//dev/nvdisk0 io 22444 fill_io_u: io_u 0x6d2130: off=7099489280/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d2130: off=7099489280/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d2130)=0 io 22444 queue: io_u 0x6d2130: off=7099489280/len=512/ddir=0//dev/nvdisk0 io 22444 fill_io_u: io_u 0x6d1ea0: off=7682447872/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d1ea0: off=7682447872/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d1ea0)=0 io 22444 queue: io_u 0x6d1ea0: off=7682447872/len=512/ddir=0//dev/nvdisk0 io 22444 calling ->commit(), depth 8 io 22444 fill_io_u: io_u 0x6d1b90: off=5983331840/len=512/ddir=0//dev/nvdisk0 io 22444 prep: io_u 0x6d1b90: off=5983331840/len=512/ddir=0//dev/nvdisk0 io 22444 ->prep(0x6d1b90)=0 io 22444 queue: io_u 0x6d1b90: off=5983331840/len=512/ddir=0//dev/nvdisk0 io 22444 fill_io_u: io_u 0x6cdfa0: off=6449852928/len=512/ddir=0//dev/nvdisk0 ...
我们可以看到详细的IO工作过程,这个方法不需要对OS非常的熟悉,比较实用。
还有个方法就是透过strace来跟踪系统调用的情况, 更直观点。
# pstree -p init(1)─┬─agent_eagleye(22296) ├─screen(13490)─┬─bash(18324)─┬─emacs(19429) │ │ ├─emacs(20365) │ │ ├─emacs(21268) │ │ ├─fio(22452)─┬─fio(22454) │ │ │ └─{fio}(22453) │ │ └─man(20385)───sh(20386)───sh(20387)───less(20391) ├─sshd(1834)───sshd(13115)───bash(13117)───screen(13662) └─udevd(705)─┬─udevd(1438) └─udevd(1745 # strace -p 22454 ... io_submit(140534061244416, 8, {{(nil), 0, 1, 0, 3}, {(nil), 0, 0, 0, 3}, {(nil), 0, 0, 0, 3}, {(nil), 0, 0, 0, 3}, {(nil), 0, 0, 0, 3}, {(nil), 0, 1, 0, 3}, {(nil), 0, 1, 0, 3}, {(nil), 0, 0, 0, 3}}) = 8 io_getevents(140534061244416, 8, 8, {{(nil), 0x6d3210, 512, 0}, {(nil), 0x6d2f80, 512, 0}, {(nil), 0x6d2cb0, 512, 0}, {(nil), 0x6d29a0, 512, 0}, {(nil), 0x6d2710, 512, 0}, {(nil), 0x6d2400, 512, 0}, {(nil), 0x6d2130, 512, 0}, {(nil), 0x6d1ea0, 512, 0}}, NULL) = 8 ...
最后有效的一招就是用iostat -dx 1来确认你的iodepth是符合设备特性的。
通过这些方法确认你的配置是对的,之后分析出来的数据才会有意义。
建议继续学习:
- 关于IO的同步,异步,阻塞,非阻塞 (阅读:14482)
- Linux服务器性能评估 (阅读:8189)
- 提升磁盘IO性能的几个技巧 (阅读:7606)
- redis在大数据量下的压测表现 (阅读:7383)
- I/O模型-读书笔记 (阅读:6918)
- Innodb IO优化-配置优化 (阅读:6658)
- 查看 CPU, Memory, I/O and NetFlow (阅读:6442)
- blktrace 深度了解linux系统的IO运作 (阅读:6012)
- Linux操作系统内核3.3版本I/O Stack的流图 (阅读:5780)
- Linux IO协议栈框图 (阅读:5338)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:Yu Feng 来源: Erlang非业余研究
- 标签: Fio IO 压测
- 发布时间:2012-03-11 22:18:53
- [54] IOS安全–浅谈关于IOS加固的几种方法
- [54] android 开发入门
- [52] Oracle MTS模式下 进程地址与会话信
- [52] 图书馆的世界纪录
- [51] Go Reflect 性能
- [50] 如何拿下简短的域名
- [48] 【社会化设计】自我(self)部分――欢迎区
- [48] 读书笔记-壹百度:百度十年千倍的29条法则
- [38] 程序员技术练级攻略
- [31] 视觉调整-设计师 vs. 逻辑