《從400錯(cuò)誤引發(fā)的故障入手,談?wù)勅绾畏治龊托迯?fù)常見(jiàn)的Nginx異常》要點(diǎn):
本文介紹了從400錯(cuò)誤引發(fā)的故障入手,談?wù)勅绾畏治龊托迯?fù)常見(jiàn)的Nginx異常,希望對(duì)您有用。如果有疑問(wèn),可以聯(lián)系我們。
作者介紹
林偉壕,網(wǎng)絡(luò)安全DevOps新司機(jī),先后在中國(guó)電信和網(wǎng)易游戲從事數(shù)據(jù)網(wǎng)絡(luò)、網(wǎng)絡(luò)安全和游戲運(yùn)維工作.對(duì)Linux運(yùn)維、虛擬化和網(wǎng)絡(luò)安全防護(hù)等研究頗多,目前專(zhuān)注于網(wǎng)絡(luò)安全自動(dòng)化檢測(cè)、防御系統(tǒng)構(gòu)建.
眾所周知,Nginx是目前最流行的Web Server之一,也廣泛應(yīng)用于負(fù)載均衡、反向代理等服務(wù),使用過(guò)程中可能因?yàn)閷?duì)Nginx工作原理、變量含義、參數(shù)大小等問(wèn)題的理解錯(cuò)誤,導(dǎo)致Nginx工作異常.
因此,本文將從一個(gè)Nginx錯(cuò)誤代碼400引發(fā)的故障入手,談?wù)勅绾畏治龊托迯?fù)常見(jiàn)的Nginx異常.
小明某天中午在線優(yōu)化一個(gè)敏感服務(wù)的Nginx配置時(shí),發(fā)現(xiàn)5分鐘內(nèi)Nginx errorlog里出現(xiàn)了大量400錯(cuò)誤,于是迅速回滾了Nginx配置.
原來(lái)的Nginx配置存在重復(fù)或者需廢棄的內(nèi)容,于是在多次diff了新舊兩份配置內(nèi)容后,小明認(rèn)為最新配置是不影響業(yè)務(wù)的,因此在線推送更新配置后,直接reload了Nginx,出于double check原則,在線觀察了5分鐘Nginx日志:
發(fā)現(xiàn)出現(xiàn)大量類(lèi)似下面的400錯(cuò)誤:
400錯(cuò)誤的產(chǎn)生,很可能影響服務(wù)端或客戶端的后續(xù)業(yè)務(wù)邏輯判斷,因此需要引起重視.
節(jié)點(diǎn)1
當(dāng)時(shí)回滾配置后,小明先在搜索引擎查找了Nginx 400錯(cuò)誤的可能原因和解決辦法,初步確定有下面兩種可能:1是空主機(jī)頭,2是請(qǐng)求包頭過(guò)大.
小明跟客戶端同學(xué)確認(rèn)了客戶端請(qǐng)求方式,發(fā)現(xiàn)他們使用的是類(lèi)似telnet的方式發(fā)起的http請(qǐng)求,類(lèi)似下面的:
為了方便后續(xù)排查,小明參考線上環(huán)境臨時(shí)搭建了一套Nginx測(cè)試環(huán)境,重現(xiàn)了故障:
后來(lái)小明了解到原來(lái)客戶端不是從代碼的http庫(kù)調(diào)用, 而是按照上面的方式走TCP/telnet傳遞http參數(shù)來(lái)調(diào)用服務(wù)端http接口.但是為什么一樣的客戶端請(qǐng)求方式,舊配置完全ok,新配置則會(huì)出現(xiàn)大量400錯(cuò)誤?
節(jié)點(diǎn)2
至此,小明懷疑自己沒(méi)有完全diff出新舊兩份配置的差別,于是他使用vimdiff再次對(duì)比新舊兩份配置.下面僅貼出關(guān)鍵配置:
舊配置:
新配置:
本次排查中,小明考慮的重點(diǎn)是新配置里遺漏了某些配置,于是他把location ~ (.*)的相關(guān)邏輯加上,發(fā)現(xiàn)問(wèn)題依舊:
節(jié)點(diǎn)3
既然前面往缺失配置的思路走不通,下面就按照新增配置的思路排查,結(jié)果發(fā)現(xiàn)新配置增加了一些包頭信息,小明懷疑是請(qǐng)求包過(guò)大,于是優(yōu)先排查了Nginx針對(duì)包頭大小的設(shè)置,其中有這么幾個(gè)配置:
client_header_buffer_size:默認(rèn)是1k,所以header小于1k的話是不會(huì)出現(xiàn)問(wèn)題的.
large_client_header_buffers:該命令用于設(shè)置客戶端請(qǐng)求的Header頭緩沖區(qū)的大小,默認(rèn)值為4KB.
客戶端請(qǐng)求行不能超過(guò)large_client_header_buffers指令設(shè)置的值,客戶端請(qǐng)求的Header頭信息不能大于large_client_header_buffers指令設(shè)置的緩沖區(qū)大小,否則會(huì)報(bào)“Request URL too large”(414)或者“Bad-request”(400)錯(cuò)誤,如果客戶端Cookie信息較大,則須增加緩沖區(qū)大小.于是小明將client_header_buffer_size和large_client_header_buffers都設(shè)置為128k.結(jié)果問(wèn)題也重現(xiàn)了.
接下來(lái),小明發(fā)現(xiàn)新配置中多了“proxy_set_header Host $http_host;”查找了Nginx官方文檔發(fā)現(xiàn)跟$http_host類(lèi)似功能的還有$server_name和$host等變量,在他將$http_host更換成$host后,問(wèn)題修復(fù)了.
根據(jù)Nginx官方文檔介紹,400狀態(tài)碼含義如下:
上面是http1.1的rfc關(guān)于host部分的解釋,從上面我們了解到如果一個(gè)http1.1的請(qǐng)求沒(méi)有host域,那么server應(yīng)該給client段發(fā)送400的狀態(tài)碼,表明這個(gè)請(qǐng)求server不能處理.而對(duì)于Nginx server來(lái)說(shuō),也遵循這樣的方式,說(shuō)明client發(fā)送了一個(gè)無(wú)效的請(qǐng)求,Nginx server無(wú)法處理,于是返回了400的狀態(tài)碼.
另外,關(guān)于$host和$http_host這兩個(gè)變量的區(qū)別如下:
本次故障中,客戶端的調(diào)用方式?jīng)]有使用host 參數(shù),傳遞了空的Host頭給服務(wù)端,一旦Nginx設(shè)置了proxy_set_header Host $http_host,空Host頭就傳給了后端.然而,在http 1.1的規(guī)范中,Host只要出現(xiàn)空,就會(huì)返回400,所以出現(xiàn)了這個(gè)故障.而對(duì)于需要在Host字段里帶上端口信息的,則仍需要配置proxy_set_header Host $http_host.
最后,需要注意的是,400錯(cuò)誤不一樣會(huì)影響業(yè)務(wù),需要看具體的業(yè)務(wù)處理邏輯,比如使用nagios的check_tcp插件對(duì)Nginx server端口做檢測(cè)或者使用keepalived的tcp_check功能對(duì)后端Nginx端口的存活做檢測(cè),這兩種情況都會(huì)在Nginx errorlog中產(chǎn)生400的請(qǐng)求.
原因也很簡(jiǎn)單,就是一般tcp check的方式,就是建立tcp連接,但是沒(méi)有發(fā)送任何數(shù)據(jù),當(dāng)然也沒(méi)有Host頭,然后再reset或者四次揮手?jǐn)嚅_(kāi)連接.
運(yùn)維規(guī)范
細(xì)心的同學(xué)會(huì)發(fā)現(xiàn)本次配置更新是在大中午操作,而且也沒(méi)有在測(cè)試環(huán)境測(cè)試通過(guò),這在流程上是不嚴(yán)謹(jǐn)?shù)?雖然Nginx等web服務(wù)的配置更新基本上通過(guò)熱更就可以了,但沒(méi)有灰度測(cè)試或者在測(cè)試環(huán)境測(cè)試,一是無(wú)法提前發(fā)現(xiàn)問(wèn)題,二是無(wú)法控制業(yè)務(wù)影響.所以,在運(yùn)維規(guī)范上看,即使是熱更也應(yīng)當(dāng)在測(cè)試環(huán)境測(cè)試正常后再同步到線上,其他的更新則應(yīng)在業(yè)務(wù)低谷時(shí)操作.
技術(shù)學(xué)習(xí)方法
本次故障的產(chǎn)生,很大程度上就是運(yùn)維同學(xué)不理解Nginx變量的定義和區(qū)別,直接從搜索引擎上找了些配置,檢查覺(jué)得正確就推到了線上.這里仍需要重申的是,以官方文檔為準(zhǔn)!互聯(lián)網(wǎng)上很多知識(shí)或者配置有各種各樣的問(wèn)題,隨時(shí)都有暗坑在里邊,只有啃過(guò)官方文檔才能避免誤讀.
Web日志分析
針對(duì)這里的Nginx錯(cuò)誤日志查看,我們看到小明是用在線命令查看的,其實(shí)現(xiàn)在有很多web日志分析工具或系統(tǒng),比如ELK(ElacticSearch+LogStash+Kibana),只需要配置好grok正則,是可以通過(guò)可視化界面實(shí)時(shí)監(jiān)控web服務(wù)質(zhì)量的.
引申
上面介紹了Nginx 400錯(cuò)誤的可能原因和解決辦法,但實(shí)際工作中,我們遇到的可不止這么一點(diǎn).于是,由此引申出去的是,針對(duì)那些Nginx常見(jiàn)錯(cuò)誤如何去排查和解決.
403錯(cuò)誤
403是很常見(jiàn)的錯(cuò)誤代碼,一般就是未授權(quán)被禁止訪問(wèn)的意思.
可能的原因有兩種:
Nginx程序用戶無(wú)權(quán)限訪問(wèn)web目錄文件
Nginx需要訪問(wèn)目錄,但是autoindex選項(xiàng)被關(guān)閉
修復(fù)方法:
授予Nginx程序用戶權(quán)限讀取web目錄文件
設(shè)置autoindex目錄為on
413錯(cuò)誤
在上傳時(shí)Nginx返回了413錯(cuò)誤:“413 Request Entity Too Large”,這一般就是上傳文件大小超過(guò)Nginx配置引起.
修復(fù)方法:
在Nginx.conf增加client_max_body_size的設(shè)置,這個(gè)值默認(rèn)是1M,可以增加到8M以提高文件大小限制;
如果運(yùn)行的是php,那么還要檢查php.ini,這個(gè)大小client_max_body_size要和php.ini中的如下值的最大值一致或者稍大,這樣就不會(huì)因?yàn)樘峤粩?shù)據(jù)大小不一致出現(xiàn)的錯(cuò)誤.
post_max_size = 8M
upload_max_filesize = 2M
502錯(cuò)誤
Nginx 502 Bad Gateway的含義是請(qǐng)求的PHP-CGI已經(jīng)執(zhí)行,但是由于某種原因(一般是讀取資源的問(wèn)題)沒(méi)有執(zhí)行完畢而導(dǎo)致PHP-CGI進(jìn)程終止.一般來(lái)說(shuō)Nginx 502 Bad Gateway和php-fpm.conf的設(shè)置有關(guān).
修復(fù)方法:
1、查看FastCGI進(jìn)程是否已經(jīng)啟動(dòng)
ps -aux | grep php-cgi
2、檢查系統(tǒng)Fastcgi進(jìn)程運(yùn)行情況
除了第一種情況,fastcgi進(jìn)程數(shù)不夠用、php執(zhí)行時(shí)間長(zhǎng)、或者是php-cgi進(jìn)程死掉也可能造成Nginx的502錯(cuò)誤.
運(yùn)行以下命令判斷是否接近FastCGI進(jìn)程,如果fastcgi進(jìn)程數(shù)接近配置文件中設(shè)置的數(shù)值,表明worker進(jìn)程數(shù)設(shè)置太少.
netstat -anpo | grep “php-cgi” | wc -l
3、FastCGI執(zhí)行時(shí)間過(guò)長(zhǎng)
根據(jù)實(shí)際情況調(diào)高以下參數(shù)值
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
504錯(cuò)誤
Nginx 504 Gateway Time-out的含義是所請(qǐng)求的網(wǎng)關(guān)沒(méi)有請(qǐng)求到,簡(jiǎn)單來(lái)說(shuō)就是沒(méi)有請(qǐng)求到可以執(zhí)行的PHP-CGI.
Nginx 504 Gateway Time-out一般與Nginx.conf的設(shè)置有關(guān).
頭部太大這種情況可能是由于Nginx默認(rèn)的fastcgi進(jìn)程響應(yīng)的緩沖區(qū)太小造成的, 這將導(dǎo)致fastcgi進(jìn)程被掛起,如果你的fastcgi服務(wù)對(duì)這個(gè)掛起處理的不好,那么最后就極有可能導(dǎo)致504 Gateway Time-out.
默認(rèn)的fastcgi進(jìn)程響應(yīng)的緩沖區(qū)是8K,可以調(diào)大以下參數(shù):
fastcgi_buffer_size 128k;
fastcgi_buffers 8 128k;
fastcgi_busy_buffers_size 由 128K 改為 256K;
fastcgi_temp_file_write_size 由 128K 改為 256K.
此外,也可能是php-cgi的問(wèn)題,需要修改php.ini的配置:
將max_children由之前的10改為30,這樣操作是為了保證有充足的php-cgi進(jìn)程可以被使用.
將request_terminate_timeout由之前的0秒改成60秒,這樣使php-cgi進(jìn)程處理腳本的超時(shí)時(shí)間提高到60秒,可以防止進(jìn)程被掛起以提高利用效率.
原文出處:http://dbaplus.cn/news-21-1129-1.html
Nginx 400狀態(tài)碼排查
http://www.68idc.cn/help/jiabenmake/qita/20140707115201.html
Nginx變量大全
https://openresty.org/download/agentzh-Nginx-tutorials-en.html
Nginx報(bào)502、504、400、413錯(cuò)誤
http://blog.csdn.net/miltonzhong/article/details/9195855
轉(zhuǎn)載請(qǐng)注明本頁(yè)網(wǎng)址:
http://www.snjht.com/jiaocheng/4306.html