trunk/ 刚获得了 Linux 原生 AIO 的支持。
我基于 libaio 实现了异步 IO,libaio 是针对 2.6.x 内核的 aio 系统调用的一个最小封装。
实现
由于 libaio 基本没有文档,所以让它工作起来有点棘手,但是嘿……这就是我们是黑客的原因 :)
异步文件 IO 支持是 Linux 2.6.9 及更高版本的一部分,应该在每个最新的 Linux 系统上都可用。一个名为 libaio 的独立库提供了非常简单的封装,并被用作新网络后端的基础。
思路是
- 在 /dev/shm 中创建一个缓冲区并 mmap() 它
- 从源文件到 mmap() 缓冲区启动异步 read()
- 等待数据就绪
- 使用 sendfile() 将数据从 /dev/shm 发送到网络套接字
对性能而言很重要的是:数据从不复制到用户空间。我们只将其从内核的一侧移动到另一侧。
技术探索
遗憾的是,我不得不将 pthread 添加到依赖项中。在一个单线程服务器中拥有线程有点奇怪,但这是必要的。
fdevent_poll() 会等待 fd 事件 1 秒。在它等待期间,服务器也在等待。异步通知的处理也是阻塞的,我们无法让它们在其中一个完成后立即返回。
如果需要,我们会启动一个 io-getevent 线程,与 fdevent_poll() 调用并行运行。首先返回的调用会通过向进程发送 SIGUSR1 来中断另一个调用。它使得等待中的调用(poll() 和 io_getevents())以 EINTR 返回,我们就可以继续处理这两个调用中的一个的结果。
基准测试
作为测试平台,我们有一个通过两块硬盘组成的 RAID1 (linux md)
- ST3160827AS (SATA, 每块 120Mb)
- nVidia Corporation CK8S 作为 SATA 控制器
- AMD Athlon™ 64 处理器 3000+
- Linux 2.6.16.21-0.25-xen (SuSE 10.1)
siege, 700Mb
我将比较 linux-sendfile 与 linux-aio-sendfile。
|并发|非 aio|aio [512k]|aio [1M]|
|1|52.38 MB/秒 [9% 空闲]|89.85 MB/秒 [70% 空闲]|107.50 MB/秒 [67% 空闲] |
|2|39.94 MB/秒 [8% 空闲]|94.52 MB/秒 [70% 空闲]| 92.74 MB/秒 [70% 空闲]
|
|5|35.45 MB/秒 [7% 空闲]|31.81 MB/秒 [86% 空闲]|72.84 MB/秒 [70% 空闲]|
|10|… |25.22 MB/秒 [82% 空闲]| 32.87 MB/秒 [90%] 空闲 |
现在,比吞吐量更重要的是可以用于其他任务的 CPU 时间。
下一步是什么?
接下来是错误修复、负载测试(更多并行连接)、随机负载等……