502,504在超時(shí)的場(chǎng)景下會(huì)比較像,經(jīng)常有人不能區(qū)分它們。499產(chǎn)生的原因也常常會(huì)和504會(huì)有內(nèi)在的關(guān)聯(lián),你都了解嗎?本文不光復(fù)現(xiàn)它們,而且會(huì)循序漸進(jìn),在對(duì)比之中復(fù)現(xiàn)它們。
下面所有復(fù)現(xiàn)的場(chǎng)景,修改nginx或者php-fpm的配置后,記得要重新啟動(dòng)。
環(huán)境介紹
- 系統(tǒng)環(huán)境和軟件環(huán)境為:Linux,Nginx,php-fpm
- nginx 配置
fastcgi_connect_timeout 5; # nginx連接fastcgi的超時(shí)時(shí)間 fastcgi_send_timeout 10; #nginx往fastcgi發(fā)送參數(shù)的超時(shí)時(shí)間 fastcgi_read_timeout 10; #nginx從fastcig獲取數(shù)據(jù)的超時(shí)時(shí)間- php-fpm配置
所有復(fù)現(xiàn)場(chǎng)景都是在nginx根目錄下創(chuàng)建一個(gè)hello.php文件,然后通過(guò)訪問(wèn)http://127.0.0.1/hello.php 來(lái)查看http響應(yīng)code,hello.php代碼如下:; 一次請(qǐng)求的最長(zhǎng)執(zhí)行時(shí)間 request_terminate_timeout = 30s<?php sleep(7); // 通過(guò)調(diào)整sleep秒數(shù),來(lái)達(dá)成不同的復(fù)現(xiàn) echo 'hello world'; ?>
499
499, Client Closed Request, 客戶(hù)端主動(dòng)斷開(kāi)連接。
是指一次http請(qǐng)求在客戶(hù)端指定的時(shí)間內(nèi)沒(méi)有返回響應(yīng),此時(shí),客戶(hù)端會(huì)主動(dòng)斷開(kāi)連接,此時(shí)表象為客戶(hù)端無(wú)響應(yīng)返回,而nginx的日志中會(huì)status code 為499。
此狀態(tài)碼在瀏覽器請(qǐng)求時(shí)幾乎不可見(jiàn),因?yàn)闉g覽器默認(rèn)的超時(shí)時(shí)間會(huì)很長(zhǎng)。多見(jiàn)于服務(wù)之間的調(diào)用,在業(yè)務(wù)架構(gòu)中常常會(huì)分層設(shè)計(jì),拆分為不同的子系統(tǒng)或者微服務(wù),這樣系統(tǒng)之間就會(huì)常常通過(guò)http方式來(lái)請(qǐng)求,并且會(huì)設(shè)置每次請(qǐng)求的超時(shí)時(shí)間,當(dāng)請(qǐng)求在請(qǐng)求時(shí)間內(nèi)所調(diào)用的上游服務(wù)無(wú)返回,則會(huì)主動(dòng)關(guān)閉連接,上游服務(wù)日志中會(huì)記錄一條499。
- 復(fù)現(xiàn)路徑
- php-fpm.conf
request_terminate_timeout=30 - nginx
fastcgi_read_timeout 5; - php
我們?cè)趌inux終端使用curl命令來(lái)請(qǐng)求,-m 表示超時(shí)時(shí)間,單位為秒<?php sleep(7); echo 'hello world'; error_log("hello", 3, "/tmp/hello.log"); ?>
curl -i -m 3 http://127.0.0.1/hello.php
返回:
curl: (28) Operation timed out after 3004 milliseconds with 0 bytes received
nginx的access日志的code為499,如下:
"HEAD /hello.php HTTP/1.1" 499 0 - php-fpm.conf
500
500, Internal Server Error , 服務(wù)器內(nèi)部錯(cuò)誤,服務(wù)器遇到了一個(gè)未曾預(yù)料的狀況,導(dǎo)致了它無(wú)法完成對(duì)請(qǐng)求的處理。
日常開(kāi)發(fā)中500錯(cuò)誤幾乎都是由于php腳本語(yǔ)法出現(xiàn)錯(cuò)誤導(dǎo)致php-fpm無(wú)法正常執(zhí)行。
-
復(fù)現(xiàn)路徑
- php
<?php echo 'hello world' ?>由于php代碼語(yǔ)法錯(cuò)誤,php-fpm執(zhí)行失敗,然后告訴nginx這一結(jié)果,nginx則返回500。
php錯(cuò)誤日志:
PHP Parse error: syntax error, unexpected 'echo' (T_ECHO), expecting ',' or ';' in hello.php on line 2
502
502,Bad Gateway,網(wǎng)關(guān)錯(cuò)誤,它往往表示網(wǎng)關(guān)從上游服務(wù)器中接收到的響應(yīng)是無(wú)效的。
先來(lái)了解一下網(wǎng)關(guān)是什么含義,從宏觀定義上來(lái)說(shuō)只要連接兩個(gè)不同的網(wǎng)絡(luò)的設(shè)備都可以叫網(wǎng)關(guān),其實(shí)具體到應(yīng)用層Http請(qǐng)求這一領(lǐng)域,網(wǎng)關(guān)就是指是轉(zhuǎn)發(fā)其他服務(wù)器通信數(shù)據(jù)的服務(wù)器,對(duì)于本文的復(fù)現(xiàn)環(huán)境而言,當(dāng)客戶(hù)端請(qǐng)求數(shù)據(jù)到達(dá)nginx,nginx負(fù)責(zé)把請(qǐng)求轉(zhuǎn)交給fastcgi(即php-fpm)進(jìn)行處理,那么在這個(gè)場(chǎng)景中Nginx就是網(wǎng)關(guān)。
502并不是指網(wǎng)關(guān)本身出了問(wèn)題,而是從上游接收響應(yīng)出了問(wèn)題,比如由于上游服務(wù)自身超時(shí)導(dǎo)致不能產(chǎn)生響應(yīng)數(shù)據(jù),或者上游不按照協(xié)議約定來(lái)返回?cái)?shù)據(jù)導(dǎo)致網(wǎng)關(guān)不能正常解析。
-
復(fù)現(xiàn)路徑1
關(guān)閉php-fpm進(jìn)程,返回502。
這個(gè)比較容易理解,參照上面的定義,因?yàn)閜hp-fpm進(jìn)程關(guān)閉,nginx連接不上php-fpm,即nginx不能收從上層接收到響應(yīng)數(shù)據(jù)。nginx 錯(cuò)誤日志如下:
connect() to unix:/tmp/php-cgi.sock failed (2: No such file or directory) while connecting to upstream -
復(fù)現(xiàn)路徑2
啟動(dòng)php-fpm進(jìn)程,修改php-fpm.conf的request_terminate_timeout和php代碼的sleep時(shí)間來(lái)復(fù)現(xiàn)。php
<?php sleep(7); echo 'hello world'; ?>php-fpm.conf
request_terminate_timeout=5
nginx
fastcgi_read_timeout 10;
php-fpm.conf設(shè)置的最大執(zhí)行時(shí)間是5s,但是php腳本需要的執(zhí)行時(shí)間大于7s,所以php-fpm進(jìn)程執(zhí)行5s時(shí)就回退出,此時(shí)php腳本沒(méi)有正常執(zhí)行完成,所以返回給網(wǎng)關(guān)Nginx的數(shù)據(jù)異常,于是導(dǎo)致502。php-fpm錯(cuò)誤日志如下:
script '/webroot/hello.php' (request: "GET /hello.php") execution timed out (5.161544 sec), terminating
nginx錯(cuò)誤日志
recv() failed (104: Connection reset by peer) while reading response header from upstream
504
504,Gateway Timeout,網(wǎng)關(guān)超時(shí)。
它表示網(wǎng)關(guān)沒(méi)有從上游及時(shí)獲取響應(yīng)數(shù)據(jù)。注意它和502在超時(shí)場(chǎng)景下的區(qū)別,502是指上游php-fpm因?yàn)槌^(guò)自身允許的執(zhí)行時(shí)間而不能正常生成響應(yīng)數(shù)據(jù),而504是指在php-fpm還未執(zhí)行完成的某一時(shí)刻,由于超過(guò)了nginx自身的超時(shí)時(shí)間,nginx則以為上游php-fpm沒(méi)有按照設(shè)置時(shí)間返回響應(yīng)數(shù)據(jù)就會(huì)返回504, 此時(shí)對(duì)于php-fpm而言還會(huì)繼續(xù)執(zhí)行下去,直到執(zhí)行完成。
-
復(fù)現(xiàn)路徑
php<?php sleep(7); echo 'hello world'; error_log("hello", 3, "/tmp/hello.log"); ?>php-fpm.conf
request_terminate_timeout=30
nginx
fastcgi_read_timeout 5;
hello.php腳本執(zhí)行時(shí)間需要7s,遠(yuǎn)小于php-fpm的一次請(qǐng)求的最大請(qǐng)求時(shí)間30s,所以php腳本可以正常完成執(zhí)行,這個(gè)可以查看/tmp/hello.log文件內(nèi)容來(lái)得到證明。由于nginx從php-fpm讀取數(shù)據(jù)的超時(shí)時(shí)間為5s,所以在5s的時(shí)科,nginx還未從php-fpm獲取到響應(yīng)數(shù)據(jù),于是返回504。
nginx錯(cuò)誤日志
upstream timed out (110: Connection timed out) while reading response header from upstream
總結(jié)
499是由于超過(guò)客戶(hù)端設(shè)置的請(qǐng)求超時(shí)時(shí)間,客戶(hù)端主動(dòng)關(guān)閉連接,服務(wù)器code為499。
500多是由于代碼語(yǔ)法錯(cuò)誤,導(dǎo)致CGI執(zhí)行錯(cuò)誤并且會(huì)把錯(cuò)誤結(jié)果通知服務(wù)器,服務(wù)器則報(bào)500。
502是由于CGI由于在自身的執(zhí)行時(shí)間要求內(nèi)無(wú)法按時(shí)完成,則無(wú)法返回給服務(wù)器正常響應(yīng),此時(shí)服務(wù)器會(huì)返回502。
504是CGI在服務(wù)器設(shè)置的超時(shí)時(shí)間內(nèi)無(wú)法按時(shí)返回響應(yīng),服務(wù)器則返回504。
499,502,504都會(huì)因?yàn)槌瑫r(shí)而產(chǎn)生,區(qū)別是超時(shí)超了誰(shuí)的時(shí),499是超了客戶(hù)端本身的連接時(shí)間,502是超了CGI的執(zhí)行時(shí)間,504是超了服務(wù)器本身的最大允許讀取時(shí)間。