線上運(yùn)營培訓(xùn)seo每日一帖
Nginx學(xué)習(xí):FastCGI模塊(三)緩沖區(qū)與響應(yīng)頭
緩存相關(guān)的內(nèi)容占了 FastCGI 模塊將近一小半的內(nèi)容,當(dāng)然,用過的人可能不多。而今天的內(nèi)容說實(shí)話,我平常也沒怎么用過。第一個(gè)是緩沖區(qū)相關(guān)的知識(shí),其實(shí)和我們之前學(xué)習(xí)過的 client_body_buffer_size 有點(diǎn)類似,但它是針對后端動(dòng)態(tài)程序的響應(yīng)緩沖區(qū)來說的。另一個(gè)也是響應(yīng)有關(guān)的,主要是響應(yīng)頭相關(guān)的一些配置。
今天學(xué)習(xí)的內(nèi)容都是可以設(shè)置在 http、server、location 中的,有特殊情況的我會(huì)單獨(dú)說。
FastCGI緩沖區(qū)配置
就像開頭所說的,它和 client_body_buffer_size 的概念是類似的,只不過針對的是后端程序的響應(yīng)緩沖。什么意思呢?其實(shí)就是將響應(yīng)保存在內(nèi)存中,如果內(nèi)容太多,就會(huì)保存到一個(gè)臨時(shí)文件里。
fastcgi_buffering
啟用或禁用來自 FastCGI 服務(wù)器的響應(yīng)緩沖。
fastcgi_buffering?on?|?off;
啟用緩沖后,Nginx 會(huì)盡快收到來自 FastCGI 服務(wù)器的響應(yīng),并將其保存到由 fastcgi_buffer_size 和 fastcgi_buffers 指令設(shè)置的緩沖區(qū)中。如果整個(gè)響應(yīng)不適合內(nèi)存,可以將其中的一部分保存到磁盤上的臨時(shí)文件中。寫入臨時(shí)文件由 fastcgi_max_temp_file_size 和 fastcgi_temp_file_write_size 指令控制。
當(dāng)緩沖被禁用時(shí),響應(yīng)會(huì)在收到時(shí)立即同步傳遞給客戶端。 Nginx 不會(huì)嘗試從 FastCGI 服務(wù)器讀取整個(gè)響應(yīng)。 Nginx 一次可以從服務(wù)器接收的最大數(shù)據(jù)大小由 fastcgi_buffer_size 指令設(shè)置。
也可以通過在“X-Accel-Buffering”響應(yīng)頭字段中傳遞“yes”或“no”來啟用或禁用緩沖。可以使用 fastcgi_ignore_headers 指令禁用此功能。
它的默認(rèn)值就是開啟的,用于控制整個(gè) FastCGI 的緩沖區(qū)控制,上面已經(jīng)說明了關(guān)閉會(huì)發(fā)生什么情況。提到的配置指令我們馬上一一學(xué)習(xí),最后再將所有配置指令合在一起進(jìn)行一個(gè)簡單的測試。
fastcgi_buffer_size
設(shè)置用于讀取從 FastCGI 服務(wù)器接收到的響應(yīng)的第一部分的緩沖區(qū)大小。
fastcgi_buffer_size?size;
這部分通常包含一個(gè)小的響應(yīng)頭。默認(rèn)情況下,緩沖區(qū)大小等于一個(gè)內(nèi)存頁,這是 4K 或 8K,具體取決于平臺(tái)。然而,它可以做得更小。它和 client_header_buffer_size 這類的配置指令是類似的,就相當(dāng)于是 FastCGI 版本的。
fastcgi_buffers
為單個(gè)連接設(shè)置用于從 FastCGI 服務(wù)器讀取響應(yīng)的緩沖區(qū)的數(shù)量和大小。
fastcgi_buffers?8?4k|8k;
默認(rèn)情況下,緩沖區(qū)大小等于一內(nèi)存頁。這是 4K 或 8K,具體取決于平臺(tái)。這個(gè)配置項(xiàng)是創(chuàng)建幾個(gè)緩沖區(qū)用的,比如設(shè)置成 8 4k ,表示的就是 8*4=32k 的緩沖區(qū),而上面的 fastcgi_buffer_size 是第一個(gè)頭緩沖區(qū)的大小,不包含在這邊,因此,整個(gè)緩沖區(qū)的大小就是 8*4k+fastcgi_buffer_size 的結(jié)果。它和 client_header_buffer_size 類似,可以看成是主要的響應(yīng)體的大小。
fastcgi_busy_buffers_size
當(dāng)啟用來自 FastCGI 服務(wù)器的響應(yīng)緩沖時(shí),限制在響應(yīng)尚未完全讀取時(shí)可能正忙于向客戶端發(fā)送響應(yīng)的緩沖區(qū)的總大小。
fastcgi_busy_buffers_size?size;
默認(rèn)值是 8 或 16 K,其余緩沖區(qū)可用于讀取響應(yīng),并在需要時(shí)將部分響應(yīng)緩沖到臨時(shí)文件。默認(rèn)情況下,大小受 fastcgi_buffer_size 和 fastcgi_buffers 指令設(shè)置的兩個(gè)緩沖區(qū)的大小限制。
fastcgi_max_temp_file_size
該指令設(shè)置臨時(shí)文件的最大大小。
fastcgi_max_temp_file_size?size;
默認(rèn)值是 1024m ,零值表示禁用對臨時(shí)文件的響應(yīng)的緩沖。如果啟用了來自 FastCGI 服務(wù)器的響應(yīng)緩沖,并且整個(gè)響應(yīng)不適合由 fastcgi_buffer_size 和 fastcgi_buffers 指令設(shè)置的緩沖區(qū),則可以將部分響應(yīng)保存到臨時(shí)文件中。一次寫入臨時(shí)文件的數(shù)據(jù)大小由 fastcgi_temp_file_write_size 指令設(shè)置。此限制不適用于將緩存或存儲(chǔ)在磁盤上的響應(yīng)。
fastcgi_temp_file_write_size
當(dāng)啟用從 FastCGI 服務(wù)器到臨時(shí)文件的響應(yīng)緩沖時(shí),限制一次寫入臨時(shí)文件的數(shù)據(jù)大小。
fastcgi_temp_file_write_size?size;
默認(rèn)情況下,大小受 fastcgi_buffer_size 和 fastcgi_buffers 指令設(shè)置的兩個(gè)緩沖區(qū)限制。臨時(shí)文件的最大大小由 fastcgi_max_temp_file_size 指令設(shè)置。
fastcgi_temp_path
定義一個(gè)目錄,用于存儲(chǔ)帶有從 FastCGI 服務(wù)器接收到的數(shù)據(jù)的臨時(shí)文件。
fastcgi_temp_path?path?[level1?[level2?[level3]]];
默認(rèn)值是 Nginx 運(yùn)行目錄下的 fasstcgi_temp 目錄,整體和之前學(xué)過的 client_body_temp_path 是類似的,在指定目錄下最多可以使用三級(jí)子目錄層次結(jié)構(gòu)。例如,在以下配置中:
fastcgi_temp_path?/spool/nginx/fastcgi_temp?1?2;
臨時(shí)文件可能存儲(chǔ)的目錄就是:
/spool/nginx/fastcgi_temp/7/45/00000123457
前面我們學(xué)習(xí)的 FastCGI 緩存相關(guān)的配置中,緩存臨時(shí)文件配置項(xiàng) fastcgi_cache_path 有個(gè)參數(shù) use_temp_path 和這個(gè)配置項(xiàng)有關(guān)系,之前我們已經(jīng)學(xué)習(xí)過了。
綜合測試
新建一個(gè)配置,注意要用非正則針對指定目錄的配置,要不然會(huì)被我們最開始的那個(gè)?location ~ \.php
給搶走,因?yàn)樗沁呏付?php 結(jié)尾,優(yōu)先級(jí)比直接指定目錄要高,只需要加上?^~
?就好了,之前在 location 中已經(jīng)詳細(xì)講解過了。
location?^~?/fastcgi1/?{root?html;fastcgi_pass?unix:/var/sock/php-fpm/www.sock;fastcgi_index??index.php;fastcgi_param??SCRIPT_FILENAME??$document_root$fastcgi_script_name;include????????fastcgi_params;fastcgi_buffer_size?100;fastcgi_buffers?2?100;fastcgi_busy_buffers_size?100;fastcgi_temp_file_write_size?100;fastcgi_temp_path?/root/fastcgi_temp_test?1?2;
}
都設(shè)置得很小是吧,但是我們要準(zhǔn)備的 PHP 文件需要返回的響應(yīng)還是要設(shè)置的很大,否則很難看出效果。
//?1.php
<?php
$c?=?$_GET['c']????2000;
for?($i=$c;$i>0;$i--){print_r($_SERVER);
}
照理說,我們設(shè)置的都只是 100 字節(jié),但實(shí)際循環(huán) 2000 次返回的響應(yīng)有 2M 了,這時(shí)才能看到指定的 fastcgi_temp_path 文件夾產(chǎn)生了變動(dòng),里面也會(huì)生成子目錄。這一塊確實(shí)不太理解,設(shè)置成 1600 次循環(huán),達(dá)不到 2M 的響應(yīng),就不會(huì)產(chǎn)生臨時(shí)文件。去掉 fastcgi_temp_file_write_size 的配置之后,2M 的響應(yīng)也不會(huì)產(chǎn)生文件。
這一塊比較難測,而且出來的效果說實(shí)話和我們想像的也不太一樣。所以如果有大佬知道這是什么情況,歡迎評(píng)論留言哈。將來如果有學(xué)習(xí)或者接觸到類似的問題,也會(huì)再單獨(dú)寫文章說說。
另外,上面的數(shù)值大家可以亂調(diào)一下試試,這幾個(gè)配置之間有各種限制,比如:
nginx:?[emerg]?"fastcgi_temp_file_write_size"?must?be?equal?to?or?greater?than?the?maximum?of?the?value?of?"fastcgi_buffer_size"?and?one?of?the?"fastcgi_buffers"?in?/etc/nginx/nginx.conf:396nginx:?[emerg]?"fastcgi_busy_buffers_size"?must?be?less?than?the?size?of?all?"fastcgi_buffers"?minus?one?buffer?in?/etc/nginx/nginx.conf:396
這些看英文也都能猜到是啥意思了。即使通過檢查了,并且 reload 成功之后,請求時(shí)也可能會(huì)報(bào)這些錯(cuò)。
2022/08/22?22:24:52?[crit]?1811#0:?*79?open()?"/root/fastcgi_temp_test/0000000001"?failed?(13:?Permission?denied)?while?reading?upstream,?client:?192.168.56.1,?server:?core.nginx.test,?request:?"GET?/fastcgi1/1.php?HTTP/1.1",?upstream:?"fastcgi://unix:/var/sock/php-fpm/www.sock:",?host:?"192.168.56.88"2022/08/22?22:20:33?[error]?1792#0:?*71?upstream?sent?too?big?header?while?reading?response?header?from?upstream,?client:?192.168.56.1,?server:?core.nginx.test,?request:?"GET?/fastcgi1/1.php?HTTP/1.1",?upstream:?"fastcgi://unix:/var/sock/php-fpm/www.sock:",?host:?"192.168.56.88"
第一個(gè)錯(cuò)誤是指定的臨時(shí)文件夾,它的上級(jí)目錄的權(quán)限必須是 755 ,所有 Nginx 下面的文件夾目錄都有這個(gè)要求。第二個(gè)是 fastcgi_buffer_size 設(shè)置小了,我想極限測試,也就是設(shè)置成 1 ,結(jié)果就直接報(bào)錯(cuò)了。這個(gè)和響應(yīng)返回的頭的大小有關(guān),我這里測試是設(shè)置到 76 就可以了,不過為了統(tǒng)一,我就全部設(shè)置到 100 了。
響應(yīng)頭處理
在 FastCGI 的處理中,HTTP 請求標(biāo)頭字段作為參數(shù)傳遞給 FastCGI 服務(wù)器。在作為 FastCGI 服務(wù)器運(yùn)行的應(yīng)用程序和腳本中,這些參數(shù)通常作為環(huán)境變量提供。例如,“User-Agent”標(biāo)頭字段作為 HTTP_USER_AGENT 參數(shù)傳遞。除了 HTTP 請求頭字段之外,還可以使用 fastcgi_param 指令傳遞任意參數(shù)。這些參數(shù)在 PHP 中都可以在?$_SERVER
?里面看到。
對于這些響應(yīng)頭,Nginx 中也有一些字段進(jìn)行處理,這里不僅是響應(yīng)頭,請求頭部分的內(nèi)容也一起寫在這里了。
fastcgi_hide_header
默認(rèn)情況下,nginx 不會(huì)從 FastCGI 服務(wù)器的響應(yīng)中將頭字段“Status”和“X-Accel-...”傳遞給客戶端。
fastcgi_hide_header?field;
沒有默認(rèn)值,也就是除了上面那些響應(yīng)頭以外,其它響應(yīng)頭都會(huì)進(jìn)行傳遞,相反,如果需要允許傳遞字段,則可以使用 fastcgi_pass_header 指令。
我們在 PHP 文件中定義一個(gè)響應(yīng)頭?header("oopp:111");
?,然后正常查看頁面,這個(gè) oopp 會(huì)返回來,而添加了?fastcgi_hide_header oopp;
?之后,在瀏覽器上就看不到這個(gè)響應(yīng)頭的信息了。
fastcgi_pass_header
允許將其他禁用的標(biāo)頭字段從 FastCGI 服務(wù)器傳遞到客戶端。
fastcgi_pass_header?field;
可以指定在禁用列表中的響應(yīng)頭返回,比如 “X-Accel-...” 這些的。具體有哪些可以看后面的 fastcgi_ignore_headers 配置。
比如我們之前測試過的 X-Accel-Expires 響應(yīng)頭,在 PHP 中設(shè)置了,但是前端瀏覽器的響應(yīng)頭中不會(huì)顯示,就可以用這個(gè)傳遞到前端瀏覽器上。
那么如果 fastcgi_hide_header 和 fastcgi_pass_header 同時(shí)設(shè)置一個(gè)響應(yīng)頭字段呢?以先后順序?yàn)闇?zhǔn),后設(shè)置的生效。
fastcgi_ignore_headers
忽略對來自 FastCGI 服務(wù)器的某些響應(yīng)頭字段的處理。
fastcgi_ignore_headers?field?...;
以下字段可以忽略:“X-Accel-Redirect”、“X-Accel-Expires”、“X-Accel-Limit-Rate”(1.1.6)、“X-Accel-Buffering”(1.1.6) 、“X-Accel-Charset”(1.1.6)、“Expires”、“Cache-Control”、“Set-Cookie”(0.8.44)和“Vary”(1.7.7)。
如果未禁用,則處理這些標(biāo)頭字段具有以下效果:
“X-Accel-Expires”、“Expires”、“Cache-Control”、“Set-Cookie”、“Vary”設(shè)置響應(yīng)緩存的參數(shù)
“X-Accel-Redirect”執(zhí)行到指定 URI 的內(nèi)部重定向
“X-Accel-Limit-Rate”設(shè)置向客戶端傳輸響應(yīng)的速率限制
“X-Accel-Buffering”啟用或禁用響應(yīng)緩沖
“X-Accel-Charset”設(shè)置響應(yīng)的所需字符集
默認(rèn)值是空的,就是這些都會(huì)處理,假如設(shè)置一個(gè) X-Accel-Expires ,那么我們之前在 PHP 中設(shè)置的 X-Accel-Expires 響應(yīng)頭延長緩存時(shí)間的效果就不起作用了。
總結(jié)
緩沖區(qū)部分可能還是需要更深入的學(xué)習(xí)操作系統(tǒng)及網(wǎng)絡(luò)相關(guān)的知識(shí)才能夠解釋清楚,目前我的水平也就只能到這里了。測試代碼也是按自己的想法來進(jìn)行測試的。另外一塊的響應(yīng)頭部分比較簡單,大家可以自己測試一下哦。
參考文檔:
http://nginx.org/en/docs/http/ngx_http_fastcgi_module.html