天天看點

linux aio socket,nginx AIO機制與sendfile機制

nginx AIO機制與sendfile機制

從0.8.11版本開始, nginx 開始支援Linux native aio,如何在nginx裡配置使用這套機制是本文介紹的重點。在下面的示例配置中,幾個重要相關選項的具體含義如下: aio:

Syntax: aio on | off | sendfile

Default: off

在linux下aio可以設定為on或off(在freebsd還可以設定為sendfile),但需要2.6.22及以後版本的核心,原因在前面文章已經提到過,nginx使用的eventfd有這個 要求 。

directio:

Syntax: directio size | off

Default: off

directio選項可以設定為off或一個大小值,表示當檔案大小大于等于這個值時啟用directio。

sendfile:

Syntax: sendfile on | off

Default: off

是否啟用sendfile()。

[[email protected] nginx-1.2.0]# uname -a

Linux www.t1.com 2.6.38.8 #2 SMP Wed Nov 2 07:52:53 CST 2011 x86_64 x86_64 x86_64 GNU/Linux

[[email protected] nginx-1.2.0]# cat /etc/issue

CentOS Linux release 6.0 (Final)

Kernel \r on an \m

[[email protected] nginx-1.2.0]# ./configure --with-file-aio

[[email protected] nginx-1.2.0]# make

[[email protected] nginx-1.2.0]# make install

[[email protected] nginx-1.2.0]# cat /usr/local/nginx/conf/nginx.conf

...

http {

...

server {

...

location / {

aio on;

directio 512k;

sendfile on;

output_buffers 1 128k;

...

要使aio生效需把directio設定為打開狀況,并且如果aio生效,那麼将自動不使用sendfile(),這在linux下這是顯然的,要麼利用aio讀到緩存區,要麼利用sendfile()直接發送出去,兩者不可兼用,而對于freebsd系統下aio和sendfile并用的情況,我并不了解,是以也就不妄加評論;

可以看到directio是針對每個請求的檔案大小而決定是否開啟directio的,是以對于上面的整個示例配置,也就會針對每個請求的不同而不同: 如果某處請求的檔案大于等于512k,那麼将啟用directio,進而aio生效,進而sendfile不生效; 如果某處請求的檔案小于512k,那麼将禁用directio,進而aio也就不生效,轉而使用sendfile(),即sendfile生效;

這種設計貌似剛好把linux下aio和sendfile兩種機制的優點很好的結合起來使用。對于大檔案采用aio,節省cpu,而對于小檔案,采用sendfile,減少拷貝;并且對于大檔案aio采用directio,避免擠占檔案系統緩存,讓檔案系統緩存更多的小檔案。 從理論上來看,這種配置比較适合系統記憶體有限、小檔案請求比較多、間隔有幾個大檔案請求的Web環境;如果記憶體足夠大,那麼應該充分利用檔案系統緩存,而directio使得aio無法使用緩存是衡量最終是否需要采用aio的一個需要仔細考慮的因素;網上有人總結說nginx+aio很好,也有人說其很差,其實根據特定的系統環境和應用場景來做配置調節,才能達到性能的最優,nginx提供的 AIO 隻是一套工具,沒有固定的好與差之分,就看你能否恰當的用好它,但據nginx官網論壇來看,在linux系統的大部分場景下,目前因使用aio功能附加的限制而帶來的實際效果估計并不太理想:

nginx supports file AIO only in 0.8.11+, but the file AIO is functional

on FreeBSD only. On Linux AIO is supported by nginx only on kerenl

2.6.22+ (although, CentOS 5.5 has backported the required AIO features).

Anyway, on Linux AIO works only if file offset and size are aligned

to a disk block size (usually 512 bytes) and this data can not be cached

in OS VM cache (Linux AIO requires DIRECTIO that bypass OS VM cache).

I believe a cause of so strange AIO implementaion is that AIO in Linux

was developed mainly for databases by Oracle and IBM.

示例:

location /video/ {

sendfile on;

sendfile_max_chunk 256k;

aio threads;

directio 512k;

output_buffers 1 128k;

}

啟用aio時會自動啟用directio,小于directio定義的大小的檔案則采用sendfile進行發送,超過或等于directio定義的大小的檔案,将采用aio線程池進行發送,也就是說aio和directio适合大檔案下載下傳.因為大檔案不适合進入作業系統的buffers/cache,這樣會浪費記憶體,而且Linux AIO(異步磁盤IO)也要求使用directio的形式.

sendfilemaxchunk可以減少阻塞調用sendfile()所花費的最長時間.因為Nginx不會嘗試一次将整個檔案發送出去,而是每次發送大小為256KB的塊資料.

注意,Nginx從1.7.11開始為AIO引入了線程池支援,能夠使用多線程讀取和發送檔案,以免勞工程序被阻塞.要啟用多線程支援,configure時需要顯式加入–with-threads選項.

sendfile機制:

在apache,nginx,lighttpd等web伺服器當中,都有一項sendfile相關的配置,在一些網上的資料都有談到sendfile會提升檔案傳輸性能,那sendfile到底是什麼呢?它的原理又是如何呢?

在傳統的檔案傳輸裡面(read/write方式),在實作上其實是比較複雜的,需要經過多次上下文的切換,我們看一下如下兩行代碼: Java代碼 收藏代碼

read(file, tmp_buf, len);

write(socket, tmp_buf, len);

以上兩行代碼是傳統的read/write方式進行檔案到socket的傳輸。

當需要對一個檔案進行傳輸的時候,其具體流程細節如下: 1、調用read函數,檔案資料被copy到核心緩沖區 2、read函數傳回,檔案資料從核心緩沖區copy到使用者緩沖區 3、write函數調用,将檔案資料從使用者緩沖區copy到核心與socket相關的緩沖區。 4、資料從socket緩沖區copy到相關協定引擎。

以上細節是傳統read/write方式進行網絡檔案傳輸的方式,我們可以看到,在這個過程當中,檔案資料實際上是經過了四次copy操作:

硬碟—>核心buf—>使用者buf—>socket相關緩沖區—>協定引擎

而sendfile系統調用則提供了一種減少以上多次copy,提升檔案傳輸性能的方法。Sendfile系統調用是在2.1版本核心時引進的: Java代碼 收藏代碼

sendfile(socket, file, len);

運作流程如下: 1、sendfile系統調用,檔案資料被copy至核心緩沖區 2、再從核心緩沖區copy至核心中socket相關的緩沖區 3、最後再socket相關的緩沖區copy到協定引擎

相較傳統read/write方式,2.1版本核心引進的sendfile已經減少了核心緩沖區到user緩沖區,再由user緩沖區到socket相關緩沖區的檔案copy,而在核心版本2.4之後,檔案描述符結果被改變,sendfile實作了更簡單的方式,系統調用方式仍然一樣,細節與2.1版本的不同之處在于,當檔案資料被複制到核心緩沖區時,不再将所有資料copy到socket相關的緩沖區,而是僅僅将記錄資料位置和長度相關的資料儲存到socket相關的緩存,而實際資料将由DMA子產品直接發送到協定引擎,再次減少了一次copy操作。

原創文章,作者:YOUNG,如若轉載,請注明出處:http://www.178linux.com/54790