1.5.0 版本将是所有用户的一大胜利。它在处理上将更灵活,并且由于异步 I/O,将对静态文件有巨大改进。
以下基准测试显示,新的 linux-aio-sendfile 后端相比经典的 linux-sendfile 后端,性能提升了 80%。
测试环境是
- 客户端: Mac Mini 1.2Ghz, MacOS X 10.4.8, 1Gb 内存, 100Mbit
- 服务器: AMD64 3000+, 1Gb 内存, Linux 2.6.16.21-xen, 160Gb RAID1 (软 RAID)
服务器运行的是 lighttpd 1.4.13 和 lighttpd 1.5.0-svn,配置纯净 [未加载模块],客户端将使用 http_load。
客户端将运行
$ ./http_load -verbose -parallel 100 -fetches 10000 urls
我用这个小程序生成了 1000 个文件夹,每个文件夹包含 100 个 100KB 大小的文件。
for i in `seq 1 1000`; do mkdir -p files-$i; for j in `seq 1 100`; do dd if=/dev/zero of=files-$i/$j bs=100k count=1 2> /dev/null; done; done
这就是 10GB 的数据,是服务器内存大小的 10 倍,因为我们希望在磁盘上达到寻道瓶颈。
限制
两块希捷 Barracuda 160GB 硬盘 (ST3160827AS) 通过 linux-md 驱动构建 RAID1。7200 转/分钟将给我们带来最高 480 次寻道/秒 (7200 转/分钟 = 120 转/秒,每次寻道平均 0.5 转,2 块硬盘)。
每块硬盘可以进行 30MB/秒的顺序读取,合计 60MB。
网络是 100Mbit/秒,我们预计其上限为 10MB/秒。
lighttpd 1.4.13, sendfile
对 lighttpd 1.4.13 使用 linux-sendfile 的首次测试运行结果是
$ iostat 5 avg-cpu: %user %nice %system %iowait %steal %idle 0.99 0.00 4.77 86.68 0.20 7.36 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 35.19 3503.78 438.97 17624 2208 sdb 33.40 4052.49 438.97 20384 2208 md0 119.48 7518.09 429.42 37816 2160 avg-cpu: %user %nice %system %iowait %steal %idle 0.60 0.00 4.61 78.36 0.00 16.43 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 31.46 3408.42 365.53 17008 1824 sdb 30.06 3313.83 365.53 16536 1824 md0 104.21 6760.72 357.52 33736 1784
http_load 返回
./http_loadverbose -parallel 100 -fetches 10000 urls- 60.006 secs, 1744 fetches started, 1644 completed, 100 current
-
-120 secs, 3722 fetches started, 3622 completed, 100 current
-180 secs, 5966 fetches started, 5866 completed, 100 current
-240 secs, 8687 fetches started, 8587 completed, 100 current
10000 fetches, 100 max parallel, 1.024e+09 bytes, in 274.323 seconds
102400 mean bytes/connection
36.4534 fetches/sec, 3.73283e+06 bytes/sec
msecs/connect: 51.7815 mean, 147.412 max, 0.181 min
msecs/first-response: 360.689 mean, 6178.2 max, 1.08 min
HTTP response codes:
code 200 — 10000
lighttpd 1.5.0, sendfile
使用 lighttpd 1.5.0 和相同的网络后端:linux-sendfile 进行相同的测试。
avg-cpu: %user %nice %system %iowait %steal %idle 0.40 0.00 3.60 85.60 0.00 10.40 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 33.80 4606.40 564.80 23032 2824 sdb 37.00 4723.20 564.80 23616 2824 md0 136.00 9368.00 553.60 46840 2768 avg-cpu: %user %nice %system %iowait %steal %idle 0.80 0.00 4.80 81.80 0.00 12.60 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 33.40 4198.40 504.00 20992 2520 sdb 30.60 4564.80 504.00 22824 2520 md0 123.60 8763.20 496.00 43816 2480 avg-cpu: %user %nice %system %iowait %steal %idle 0.80 0.00 5.19 81.24 0.00 12.77 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 36.53 4490.22 493.41 22496 2472 sdb 32.34 4784.03 493.41 23968 2472 md0 126.75 9274.25 483.83 46464 2424
客户端显示
-60 secs, 2444 fetches started, 2344 completed, 100 current
-120.003 secs, 4957 fetches started, 4857 completed, 100 current
-180 secs, 7359 fetches started, 7259 completed, 100 current
-240 secs, 9726 fetches started, 9626 completed, 100 current
10000 fetches, 100 max parallel, 1.024e+09 bytes, in 246.803 seconds
102400 mean bytes/connection
40.5181 fetches/sec, 4.14906e+06 bytes/sec
msecs/connect: 55.5808 mean, 186.153 max, 0.24 min
msecs/first-response: 398.639 mean, 6101.44 max, 9.313 min
HTTP response codes:
code 200 — 10000
这只是稍微好一点,但仍然存在相同的问题。我们被磁盘而非网络限制了性能。
lighttpd 1.5.0, linux-aio-sendfile
我们只是将网络后端切换到异步 I/O 后端
server.network-backend = "linux-aio-sendfile"
……然后再次运行我们的基准测试
avg-cpu: %user %nice %system %iowait %steal %idle 8.38 0.00 10.18 38.52 0.00 42.91 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 42.91 7190.42 526.95 36024 2640 sdb 36.93 6144.51 526.95 30784 2640 md0 205.99 13213.57 517.37 66200 2592 avg-cpu: %user %nice %system %iowait %steal %idle 0.80 0.00 9.84 48.39 0.20 40.76 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 50.40 8369.48 573.49 41680 2856 sdb 44.18 7318.88 573.49 36448 2856 md0 241.77 15890.76 563.86 79136 2808 avg-cpu: %user %nice %system %iowait %steal %idle 0.60 0.00 8.38 44.91 0.00 46.11 Device: tps Blk_read/s Blk_wrtn/s Blk_read Blk_wrtn sda 50.10 7580.04 720.16 37976 3608 sdb 47.50 7179.24 720.16 35968 3608 md0 242.12 14558.08 710.58 72936 3560
客户端显示
--- 60.0001 secs, 3792 fetches started, 3692 completed, 100 current --- 120 secs, 8778 fetches started, 8678 completed, 100 current 10000 fetches, 100 max parallel, 1.024e+09 bytes, in 137.551 seconds 102400 mean bytes/connection 72.7004 fetches/sec, 7.44452e+06 bytes/sec msecs/connect: 66.9088 mean, 197.157 max, 0.223 min msecs/first-response: 226.181 mean, 6066.96 max, 2.098 min HTTP response codes: code 200 -- 10000
总结
使用异步 I/O 允许 lighttpd 重叠文件操作。我们发送一个文件的 I/O 请求,并在文件准备好时收到通知。这样就无需等待文件 (像正常的 sendfile() 那样) 并阻塞服务器,我们可以转而处理其他请求。
另一方面,我们允许内核根据需要重新排序文件请求。
结合这两项改进,我们可以将吞吐量提高 80%。
另一方面,lighty 本身不会花费任何时间在等待上。64 个内核线程在后台为我们处理 read() 调用,这将空闲时间从 12% 增加到 40%,提升了 230%。