1. 程式人生 > >nginx故障及處理

nginx故障及處理

flag 在線 linu 反向代理 bad 今天 arc 播放 lower

原因:

502 GAT away

Php-cgi進程掛掉或者是沒有cgi進程

504 timeout

Nginx請求不到php-cgi進程,超時

解決方法:

思路:

502錯誤和php-fpm.conf配置文件有關系,網上很多教程都說了,一般就設置以下幾個選項

這個數字只是一個參考,具體多少需要自己去琢磨

技術分享圖片

504錯誤和nginx.conf配置文件有很大的關系,網上教程就是說修改緩存的時間,大小等等,其實不然,除了上面的要修改,還有一個關鍵就是fastcgi_read_timeout這個選項,此選項的意思是設置在那個時間段內,不管php-cgi請求是否完成,都要關閉,大概意思就是這樣,還有一點就是一定要註意,你的web站點的Php最大請求的時間大概為多少,如果設置少了,那麽肯定報504,下面是我的配置

技術分享圖片

由於我內部Php那面需要網上采集數據,時間設置少了就會報502或者504……..就是這個原因

故障簡述

中午在線優化一個敏感服務的Nginx配置時,發現5分鐘內Nginx errorlog裏出現了大量400錯誤,於是迅速回滾了Nginx配置。

原來的Nginx配置存在重復或者需廢棄的內容,於是在多次diff了新舊兩份配置內容後,小明認為最新配置是不影響業務的,因此在線推送更新配置後,直接reload了Nginx,出於double check原則,在線觀察了5分鐘Nginx日誌:

/etc/init.d/Nginx reload

tail -f /var/log/access.log

tail -f /var/log/error.log

發現出現大量類似下面的400錯誤:

1.1.1.1 - - [21/Feb/2017:13:53:00 +0800] "GET /x/get?id=hh2&aid=11642618&currenttime=1487656379&num=21461799&flag=1&host=23000&user=60%2E220%2E132%2E66&logintime=1487654812&username=howru%2D10 HTTP/1.1" 400 166 "-" "-" "223.252.221.10" "0.000" "-" "-"

400錯誤的產生,很可能影響服務端或客戶端的後續業務邏輯判斷,因此需要引起重視。

處理過程

當時回滾配置後,先在搜索引擎查找了Nginx 400錯誤的可能原因和解決辦法,初步確定有下面兩種可能:1是空主機頭,2是請求包頭過大

為了方便後續排查,小明參考線上環境臨時搭建了一套Nginx測試環境,重現了故障:

了解到原來客戶端不是從代碼的http庫調用, 而是按照上面的方式走TCP/telnet傳遞http參數來調用服務端http接口。但是為什麽一樣的客戶端請求方式,舊配置完全ok,新配置則會出現大量400錯誤?

懷疑自己沒有完全diff出新舊兩份配置的差別,於是他使用vimdiff再次對比新舊兩份配置。

本次排查中,小明考慮的重點是新配置裏遺漏了某些配置,於是他把location ~ (.*)的相關邏輯加上,發現問題依舊:

既然前面往缺失配置的思路走不通,下面就按照新增配置的思路排查,結果發現新配置增加了一些包頭信息,小明懷疑是請求包過大,於是優先排查了Nginx針對包頭大小的設置,其中有這麽幾個配置:

  • client_header_buffer_size:默認是1k,所以header小於1k的話是不會出現問題的。

  • large_client_header_buffers:該命令用於設置客戶端請求的Header頭緩沖區的大小,默認值為4KB。

客戶端請求行不能超過large_client_header_buffers指令設置的值,客戶端請求的Header頭信息不能大於large_client_header_buffers指令設置的緩沖區大小,否則會報“Request URL too large”(414)或者“Bad-request”(400)錯誤,如果客戶端Cookie信息較大,則須增加緩沖區大小。於是小明將client_header_buffer_size和large_client_header_buffers都設置為128k。結果問題也重現了。

原因分析

A client MUST include a Host header field in all HTTP/1.1 request messages . If the requested URI does not include an Internet host name for the service being requested, then the Host header field MUST be given with an empty value. An HTTP/1.1 proxy MUST ensure that any request message it forwards does contain an appropriate Host header field that identifies the service being requested by the proxy. All Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request) status code to any HTTP/1.1 request message which lacks a Host header field.

上面是http1.1的rfc關於host部分的解釋,從上面我們了解到如果一個http1.1的請求沒有host域,那麽server應該給client段發送400的狀態碼,表明這個請求server不能處理。而對於Nginx server來說,也遵循這樣的方式,說明client發送了一個無效的請求,Nginx server無法處理,於是返回了400的狀態碼。

$host

This variable is equal to line Host in the header of request or name of the server processing the request if the Host header is not available.

This variable may have a different value from $http_host in such cases: 1) when the Host input header is absent or has an empty value, $host equals to the value of server_name directive; 2)when the value of Host contains port number, $host doesn‘t include that port number. $host‘s value is always lowercase since 0.8.17.

本次故障中,客戶端的調用方式沒有使用host 參數,傳遞了空的Host頭給服務端,一旦Nginx設置了proxy_set_header Host $http_host,空Host頭就傳給了後端。然而,在http 1.1的規範中,Host只要出現空,就會返回400,所以出現了這個故障。而對於需要在Host字段裏帶上端口信息的,則仍需要配置proxy_set_header Host $http_host。

最後,需要註意的是,400錯誤不一樣會影響業務,需要看具體的業務處理邏輯,比如使用nagios的check_tcp插件對Nginx server端口做檢測或者使用keepalived的tcp_check功能對後端Nginx端口的存活做檢測,這兩種情況都會在Nginx errorlog中產生400的請求。

原因也很簡單,就是一般tcp check的方式,就是建立tcp連接,但是沒有發送任何數據,當然也沒有Host頭,然後再reset或者四次揮手斷開連接

技術學習方法

本次故障的產生,很大程度上就是運維同學不理解Nginx變量的定義和區別,直接從搜索引擎上找了些配置,檢查覺得正確就推到了線上。這裏仍需要重申的是,以官方文檔為準!互聯網上很多知識或者配置有各種各樣的問題,隨時都有暗坑在裏邊,只有啃過官方文檔才能避免誤讀。

Web日誌分析

針對這裏的Nginx錯誤日誌查看,我們看到小明是用在線命令查看的,其實現在有很多web日誌分析工具或系統,比如ELK(ElacticSearch+LogStash+Kibana),只需要配置好grok正則,是可以通過可視化界面實時監控web服務質量的。

  • 403錯誤

403是很常見的錯誤代碼,一般就是未授權被禁止訪問的意思。

可能的原因有兩種:

  1. Nginx程序用戶無權限訪問web目錄文件

  2. Nginx需要訪問目錄,但是autoindex選項被關閉

修復方法:

  1. 授予Nginx程序用戶權限讀取web目錄文件

  2. 設置autoindex目錄為on

location /path/to/website/folder {

...

autoindex on;

... }

  • 413錯誤

在上傳時Nginx返回了413錯誤:“413 Request Entity Too Large”,這一般就是上傳文件大小超過Nginx配置引起。

修復方法:

  1. 在Nginx.conf增加client_max_body_size的設置,這個值默認是1M,可以增加到8M以提高文件大小限制;

  2. 如果運行的是php,那麽還要檢查php.ini,這個大小client_max_body_size要和php.ini中的如下值的最大值一致或者稍大,這樣就不會因為提交數據大小不一致出現的錯誤。

post_max_size = 8M

upload_max_filesize = 2M

  • 502錯誤

Nginx 502 Bad Gateway的含義是請求的PHP-CGI已經執行,但是由於某種原因(一般是讀取資源的問題)沒有執行完畢而導致PHP-CGI進程終止。一般來說Nginx 502 Bad Gateway和php-fpm.conf的設置有關。

修復方法:

1、查看FastCGI進程是否已經啟動

ps -aux | grep php-cgi

2、檢查系統Fastcgi進程運行情況

除了第一種情況,fastcgi進程數不夠用、php執行時間長、或者是php-cgi進程死掉也可能造成Nginx的502錯誤。

運行以下命令判斷是否接近FastCGI進程,如果fastcgi進程數接近配置文件中設置的數值,表明worker進程數設置太少。

netstat -anpo | grep "php-cgi" | wc -l

3、FastCGI執行時間過長

根據實際情況調高以下參數值

fastcgi_connect_timeout 300;

fastcgi_send_timeout 300;

fastcgi_read_timeout 300;

  • 504錯誤

Nginx 504 Gateway Time-out的含義是所請求的網關沒有請求到,簡單來說就是沒有請求到可以執行的PHP-CGI。

Nginx 504 Gateway Time-out一般與Nginx.conf的設置有關。

頭部太大這種情況可能是由於Nginx默認的fastcgi進程響應的緩沖區太小造成的, 這將導致fastcgi進程被掛起,如果你的fastcgi服務對這個掛起處理的不好,那麽最後就極有可能導致504 Gateway Time-out。

默認的fastcgi進程響應的緩沖區是8K,可以調大以下參數:

  • fastcgi_buffer_size 128k;

    fastcgi_buffers 8 128k;

  • fastcgi_busy_buffers_size 由 128K 改為 256K;

    fastcgi_temp_file_write_size 由 128K 改為 256K。

此外,也可能是php-cgi的問題,需要修改php.ini的配置:

  1. 將max_children由之前的10改為30,這樣操作是為了保證有充足的php-cgi進程可以被使用。

  2. 將request_terminate_timeout由之前的0秒改成60秒,這樣使php-cgi進程處理腳本的超時時間提高到60秒,可以防止進程被掛起以提高利用效率。

nginx緩存權限問題

故障說明:

官網放了一段flv的視頻,之前還可以播放,今天突然發現播放不了了。程序都一樣,測試環境沒問題,線上卻播放不了。

下面說下產生問題的原因和解決辦法。

  1. nginx打開網頁,點擊視頻播放,打不來,首先從nginx的error log下手,看下能否找出一些蛛絲馬跡。

2015/04/09 18:33:20 [crit] 8063#0: *15970093 open() "/data/nginx/proxy_temp/7/41/0000006417" failed (13: Permission denied) while reading upstream, (nginx部分error日誌)

通過查詢nginx的eror日誌,表面上是打不來緩存目錄,沒法緩存數據,google搜索了下,找到了答案。

nginx原本運行的賬戶是root,後來基於安全考慮,我修改成了你nginx,但是緩存目錄的屬主和屬組還是root,所以視頻的緩存數據寫不到緩存目錄。

2.找到了原因,下面說下解決方法:查看下,運行nginx的用戶。

ps -ef | grep nginx

root 4850 1 0 Jan22 ? 00:00:00 nginx: master process /data/nginx/sbin/nginx

nginx 8862 4850 0 Apr14 ? 00:00:34 nginx: worker process

root 20476 20395 0 10:49 pts/1 00:00:00 grep nginx

3.可以看到運行nginx服務的用戶是nginx用戶,修改緩存目錄的屬主和屬組為nginx。

chown -R nginx.nginx proxy_temp

ls -ld proxy_temp

drwx------ 12 nginx nginx 4096 Jan 8 18:02 proxy_temp

或者是把proxy_temp刪除,就可以了

nginx 加tomcat負載在業務高峰期出現問題

nginx 反向代理Tomcat 高峰時報 connect() failed (110: Connection timed out) while connecting to upstream,

平峰一切OK 反應很快, 一到高峰期就很多connect() failed (110: Connection timed out) while connecting to upstream,

導致後端tomcat卡死 ,一開始以為是tomcat內存設置不夠 gc的問題,後來更改過了還是不行 不能解決問題! 然後就奇葩的是 我直接幹掉nginx 直接采用一個tomcat處理業務在高峰期居然可以抗的下來 但是加上nginx+tomcat的模式就會報錯在高峰期

技術分享圖片

解決:

nginx配置中,"proxy_connect_timeout 6000"代表nginx與後端(即upstream)建連的超時時間為6秒。即是說,當nginx嘗試與tomcat建連時間超過6秒後就會放棄並報錯。高峰期時,如果nginx與tomcat建連頻繁超時,就會出現你描述的情況。

你所謂的"tomcat卡死",我估計應該是tomcat在應對高峰流量時展現出的請求嚴重積壓狀態,此時tomcat還在工作,只不過排隊的請求太多,響應非常非常慢。

至於為啥拿掉nginx之後就"沒問題"了,是因為拿掉nginx之後就是用戶直接與tomcat建連,此時請求處理效率並沒有提高(如果按照6秒超時來計算的話,建連失敗和先前是一樣多甚至更多的),只不過建連失敗、請求超時等問題都不會體現在tomcat的日誌中罷了

nginx故障及處理