Nginx使用Linux-native aio提高文件读取性能

Nginx性能优异在于善于利用操作系统内核的各种特性,比如aio/epoll/sendfile(Linux)/kqueue(FreeBSD)等。对于使用VPS做图片站的站长来说,使用nginx的aio特性会大大提高性能,图片站的特点是大量的读io操作,nginx aio不用等待每次io的结果,有助于并发处理大量io和提高nginx处理效率。

如果包里的nginx没有包含Linux-native aio(asynchronous I/O)的支持,那么需要下载nginx源代码并带上参数--with-file-aio编译。除了要带参数外,Linux内核还必须有支持这一特性的api-eventfd(),否则在nginx错误日志(/var/log/nginx/error.log)里会看到类似的报错:

eventfd() failed (38: Function not implemented) 
worker process 1858 exited with fatal code 2 and can not be respawn

解决方法很简单,升级内核就可以了。

要让nginx使用aio特性还需要修改nginx配置文件:

# vim /usr/local/nginx/conf/nginx.conf 
... 
location / { 
  aio on; 
  directio 1; 
  output_buffers 1 128k; 
} 
...

Linux-native aio比传统的POSIX aio功能更丰富一些,重要的一点是能通过内核加速提供高性能。直接用Linux-native aio API比较晦涩,为了方便使用和开发Linux-native aio应用程序,我们可以用libaio/libaio-devel库。不过nginx的作者没有用这些库,因为nginx需要eventfd(),而libaio库里只有0.3.107版本起才支持eventfd,nginx也没有用glibc,因为glibc要到2.8版本才支持eventfd(),为了减少对库的依赖性,nginx干脆直接用Linux-native aio API。

$ vim nginx/src/event/modules/ngx_epoll_module.c 
... 
#if (NGX_HAVE_FILE_AIO) 

/* 
 * We call io_setup(), io_destroy() io_submit(), and io_getevents() directly 
 * as syscalls instead of libaio usage, because the library header file 
 * supports eventfd() since 0.3.107 version only. 
 * 
 * Also we do not use eventfd() in glibc, because glibc supports it 
 * since 2.8 version and glibc maps two syscalls eventfd() and eventfd2() 
 * into single eventfd() function with different number of parameters. 
 */ 
...

这里说到了eventfd(),eventfd是Linux-native aio其中的一个API,用来生成file descriptors,这些file descriptors可为应用程序提供更高效“等待/通知”的事件机制。和pipe作用相似,但比pipe更好,一方面它只用到一个file descriptor(pipe要用两个),节省了内核资源,另一方面,eventfd的缓冲区管理要简单得多,pipe需要不定长的缓冲区,而eventfd全部缓冲只有定长8 bytes。

相关推荐