续:异步IO一定更好吗?
发布于 4年前 作者 pengchun 4318 次浏览 最后一次编辑是 3年前

我之前的一篇文章《异步IO一定更好吗?》中举了一个很变态的例子,用以说明在单碟机械式硬盘上异步IO反而可能降低性能的问题,大家的讨论很热烈。前天的NodeParty杭州站分享会上,来自上海的@老赵 随口带出了这个问题,大概说是多个异步IO请求会使得性能提高,因为磁头走到哪里就处理到哪里,很多请求在“路上”就可以被处理掉了。

乍一看,我和老赵的结论是相反的。所以从nodeparty回来后查了查资料,并且做了一些实验,发现这两种情况在各自特定的场景里都可能是正确的,在别的场景又都可能是错误的。为什么呢?

我之前的结论没有认真考虑操作系统对IO调度的优化,对此一知半解就拿出来大放厥词,实在不应该!

Linux2.6内核对IO调度提供了四种算法:Completely Fair Queuing(CFQ)、Deadline、NOOP和Anticipatory(as),详细情况请点击这里阅读。在2.6内核中,系统默认的IO调度算法是CFQ,也就是OS会对请求的偏移量首先进行排序,按照这个排序顺序进行磁头的移动和请求响应,这正是老赵的观点的出处。而假如某个磁盘采用了NOOP的IO调度算法,也就是说内核不会对IO调度做任何优化,容易理解,正是我在《异步IO一定更好吗?》一问中的观点。除此之外,用户还可以为不同磁盘指定不同的IO调度算法。查看某个磁盘的IO调度算法的命令如下:

$[pengchun]$ cat /sys/block/sda/queue/scheduler
noop anticipatory deadline [cfq]

原文这里的测试方法不对,已删掉

总结我的几点经验:

1. 异步IO不一定是性能最好的;

2. 操作系统对磁盘IO的各种调度算法中,没有哪一个是绝对更好的;随着应用场景的不同,很可能某一个算法的性能远远好于其他几个;而在另外的场景中则相反。例如,某个磁盘专门用来写日志的,那么你用NOOP就最好了;而如果要作为数据库的磁盘来使用,deadline可能是最好的算法了;

3. 尽管操作系统会做这样那样的优化,但不要懒惰地依赖操作系统;对机械式磁盘的访问,尽可能把随机访问变成顺序访问。

4 回复

对这个测试有点疑问:lseek和fread都是系统调用,磁盘调度应该在此之下,不同的调度算法不应该改变lseek和fread的调用顺序。而且程序是同步调用,调用未完成前不会继续执行后边的调用,操作系统无法聪明的将还没有被执行的调用进行调度。

因此怀疑是php自己做的优化,查阅了一下php的源代码,发现在php-5.3.6\main\streams\streams.c 中的_php_stream_read函数实现中确实有buffer,而php的fread是通过调用_php_stream_read来实现的。

建议换成C语言再实现一下同样的逻辑,看看结果是否有所不同。

看到ls的回复,期待一篇"操作系统与编译器/解释器中的IO调度算法分析"

是的,我的测试方法搞错了,先删掉。IO调度应该是lseek里的实现,怎么去验证这个谁能支点招?

异步IO请求会使得性能提高,因为磁头走到哪里就处理到哪里,很多请求在“路上”就可以被处理掉了。看来异步还能保护硬盘哦。

回到顶部