Nginx+PHP Xsendfile文件傳輸

1.簡(jiǎn)介

傳統(tǒng)的文件傳輸模式中(read/write和send/recv),需要在文件file,系統(tǒng)buffer和用戶buffer中反復(fù)I/O,造成內(nèi)存的浪費(fèi)與資源占用,大致流程如下.

  • 1.調(diào)用read(file, tmp_buf, len);,切換user modekernel mode,將文件從磁盤讀取到kernel buffer中掛起;
    關(guān)于read():
    ssize_t read (int fd, void *buf, size_t count);

成功返回讀取的字節(jié)數(shù),出錯(cuò)返回-1并設(shè)置errno啤它,如果在調(diào)read之前已到達(dá)文件末尾,則這次read返回0衰粹。
read()會(huì)把參數(shù)fd所指的文件傳送nbyte個(gè)字節(jié)到buf指針所指的內(nèi)存中铝耻。若參數(shù)nbyte為0瓢捉,則read()不會(huì)有作用并返回0。返回值為實(shí)際讀取到的字節(jié)數(shù)某弦,如果返回0而克,表示已到達(dá)文件尾或無可讀取的數(shù)據(jù)。錯(cuò)誤返回-1,并將根據(jù)不同的錯(cuò)誤原因適當(dāng)?shù)脑O(shè)置錯(cuò)誤碼碎绎。

  • 2.read()返回,切換kernel modeuser mode,把kernel buffer中緩存的數(shù)據(jù)復(fù)制到user buffer中;

  • 3.調(diào)用write(socket, tmp_buf, len);,切換user modekernel mode,把復(fù)制到user buffer中的數(shù)據(jù)再次復(fù)制到另一個(gè)與socket關(guān)聯(lián)的kernel buffer;
    關(guān)于write():

ssize_t write(int fd, const void *buf, size_t nbyte);
write函數(shù)把buf中nbyte寫入文件描述符handle所指的文檔筋帖,成功時(shí)返回寫的字節(jié)數(shù)幕随,錯(cuò)誤時(shí)返回-1.

  • 4.write()返回,切換kernel modeuser mode,將上一步緩存到kernel buffer中的數(shù)據(jù)復(fù)制到服務(wù)器協(xié)議棧中;

關(guān)于Linux User Mode和Kernel Mode

簡(jiǎn)單圖示:


圖片來源:http://laoxu.blog.51cto.com/4120547/1417294

這樣的傳輸方式固然簡(jiǎn)單可靠,但是由于一共進(jìn)行了四次跨space的I/O和四次mode切換,所以在傳輸size過大或數(shù)量過多的文件時(shí)效率堪憂.


在Linux 2.0+以后提供了一個(gè)sendfile()的文件傳送方式,
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
文檔

sendfile()是作用于數(shù)據(jù)拷貝在兩個(gè)文件描述符之間的操作函數(shù).這個(gè)拷貝操作是內(nèi)核中操作的,所以稱為"零拷貝".sendfile函數(shù)比起read和write函數(shù)高效得多,因?yàn)閞ead和write是要把數(shù)據(jù)拷貝到用戶應(yīng)用層操作.

其大致流程如下:

  • 1.調(diào)用sendfile()把磁盤中的數(shù)據(jù)復(fù)制到kernel buffer;
  • 2.把復(fù)制到kernel buffer中的數(shù)據(jù)復(fù)制到另一個(gè)socket關(guān)聯(lián)的kernel buffer中;
  • 3.將上一步緩存到socket kernel buffer中的數(shù)據(jù)復(fù)制到服務(wù)器協(xié)議棧中;

以上流程中并沒有出現(xiàn)mode的切換,并且省略了涉及user buffer的兩次I/O,所以性能會(huì)比傳統(tǒng)方式優(yōu)異許多.

簡(jiǎn)單圖示:

圖片來源:http://laoxu.blog.51cto.com/4120547/1417294

2.實(shí)現(xiàn)

強(qiáng)烈建議先閱讀官方文檔:
XSendfile-Nginx官方文檔

  • 1.首先需要確保Nginx支持sendfile:
$ sudo vi /etc/nginx/nginx.conf
>>
sendfile on;
  • 2.既然涉及PHP的文件傳輸,header不能少:
header('Content-type: application/octet-stream');
// 這里的$s_fileName指的是被下載的文件名
header('Content-Disposition: attachment; filename="' . $s_fileName . '"');
// nginx sendfile
// 這里的$p_file指的是在nginx中約定的訪問路徑
header('X-Accel-Redirect: '.$p_file);
  • 3.上一步的$p_file并不是指文件的實(shí)際路徑,而是nginx中約定的路由,所以需要配置nginx:
// 假設(shè) $p_file = "/demo/download/" . $s_fileName;
// 假設(shè)該文件的實(shí)際路徑為 /var/www/demo/_api.git/var/tmp/
location /demo/download {
    internal;
    alias   /var/www/demo/_api.git/var/tmp/;
}
  • 4.重啟一下相關(guān)服務(wù)以加載最新配置:
$ sudo service nginx reload

需要注意的是:

  • 1.聲明Xsendfile的header必須包含約定的URI;
  • 2.在配置文件中約定的解析路徑必須被聲明為內(nèi)部調(diào)用(internal),這么做是為了防止外部URI的直接訪問;
  • 3.根據(jù)實(shí)際需求選擇解析目錄使用root(實(shí)際目錄)還是alias(虛擬目錄)關(guān)鍵字;
  • 4.另外Nginx提供了幾個(gè)header控制sendfile的配置:
X-Accel-Limit-Rate: 1024
X-Accel-Buffering: yes|no
X-Accel-Charset: utf-8

3.其它:

Apache2 Xsendfile mod
DEMO

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末梢卸,一起剝皮案震驚了整個(gè)濱河市蛤高,隨后出現(xiàn)的幾起案子塞绿,更是在濱河造成了極大的恐慌异吻,老刑警劉巖喜庞,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件雷猪,死亡現(xiàn)場(chǎng)離奇詭異求摇,居然都是意外死亡月帝,警方通過查閱死者的電腦和手機(jī)幽污,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門嚷辅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人距误,你說我怎么就攤上這事簸搞。” “怎么了准潭?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵趁俊,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我刑然,道長(zhǎng)煮盼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任亡脸,我火速辦了婚禮衣厘,結(jié)果婚禮上挡逼,老公的妹妹穿的比我還像新娘嘱能。我一直安慰自己,他們只是感情好析苫,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布矛物。 她就那樣靜靜地躺著峦萎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪详幽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音宪肖,去河邊找鬼。 笑死阱持,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的镶骗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼唤衫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎可免,沒想到半個(gè)月后毡咏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體修己,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年厢岂,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筐摘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片圃酵。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡堪置,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出坎匿,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布挤巡,位于F島的核電站喉恋,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦芹彬、人聲如沸陡叠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至裁眯,卻和暖如春晌坤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工袍啡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留颖系,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓旅掂,卻偏偏與公主長(zhǎng)得像秘车,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容