這些 Nginx 常見異常,幫你快速定位故障
提示:文章前面部分是關于 nginx 下 https 連接 curl 請求被 reset 的處理經歷,不想看可以直接跳到最后看nginx快速定位異常,建議收藏!
問題描述
網(wǎng)站上線后,添加了https證書,瀏覽器訪問正常,通過curl請求,請求被reset,如上圖。
一路艱難
先 curl 請求同域名下http的url,返回正常,說明兩邊起碼80端口網(wǎng)絡正常
接著curl請求網(wǎng)站同服務器下其他https域名,返回正常,說明兩邊443端口網(wǎng)絡正常
難道是證書問題?查看證書未到期,通過myssl.com查詢證書詳情,沒有問題。
懷疑加密套件配置文件,添加兼容性更高的加密套件后嘗試,依然無果
附兼容性加密套件:
- "ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4"
仍然無果后,決定tcpdump兩邊抓包,用wireshark分析
從發(fā)起請求到 reset,總過16個包,看到是兩端握手完成,發(fā)起數(shù)據(jù)傳輸之后,開始傳輸數(shù)據(jù)的第一個確認包就被 reset 了,百思不得其解
難道是客戶端發(fā)送的數(shù)據(jù)太大,nginx 的 buffer 不夠?
修改了nginx關于client的相關設置如下:
- client_header_buffer_size 64k;
- large_client_header_buffers 4 64k;
- client_body_buffer_size 20m;
- keepalive_timeout 120;
因為從抓包看,還沒到fastcgi部分,所以不修改關于fastcgi的buffer部分配置
修改后結果仍然一樣,有點方了
雖然知道應該和證書關系不大,但是還是決定更換一個證書看看,因為之前是RSA的證書,那我換個ECC的證書試試(推薦七牛云SSL證書申請,可以選擇ECC證書)
換過之后有新的發(fā)現(xiàn)
- curl: (35) Cannot communicate securely with peer: no common encryption algorithm(s).
無法與對等體安全通信:無通用加密算法
問題沒解決,還出來新問題了,猜測ECC算法兼容性問題,通過一番google之后,了解到如下信息:
原來Redhat/CentOS服務器上curl默認是使用NSS庫的,而在這兩個系統(tǒng)上curl默認是禁用ECC加密的,雖然服務端加密套件支持ECC,但是客戶端不支持,所以請求失敗,需要客戶端curl通過指定加密套件來請求
- curl --ciphers ecdhe_rsa_aes_128_gcm_sha_256 ...
指定加密套件后,又回到起點,仍然是原來的錯誤,看來和證書沒有關系
柳暗花明
沒辦法,仔細對比了其他網(wǎng)站的nginx配置,沒什么不一樣,只是沒有配ssl_session_cache,以我對該參數(shù)的了解,該參數(shù)只是作為ssl優(yōu)化的一個配置,起到緩存的作用,減少握手次數(shù),但是現(xiàn)在已經“窮途末路”了,先配上再說
萬萬沒想到,好了
抑制著想要吃涮羊肉的心情,又去nginx官網(wǎng)查了下ssl_session_cache參數(shù)的解釋
總結如下:
ssl_session_cache有4個可選參數(shù)
- off
嚴禁使用session緩存:nginx明確告訴客戶端session可能不會被重用
- none
session緩存的使用被禁止:nginx告訴客戶端session可能會被重用,但實際上并不會將session參數(shù)存儲在緩存中
- builtin
在OpenSSL中構建的緩存;僅由一個工作進程使用。緩存大小在session中指定。如果沒有給出大小,則等于20480個會話。使用內置高速緩存可能導致內存碎片
- shared
所有工作進程之間共享緩存。緩存大小以字節(jié)為單位指定;一兆字節(jié)可以存儲大約4000個session。每個共享緩存都應該有一個任意名稱。具有相同名稱的緩存可以用于多個虛擬服務器
反正就是,你要做緩存的話,就兩個參數(shù),builtin和shared,而且這兩個參數(shù)可以同時開啟,但是建議只使用shared,性能要更高一些
但是看完我仍然理解不了,為什么加了這個參數(shù),curl就不報reset了,于是我再次抓包對比并和之前的做對比
在數(shù)據(jù)傳輸之前,除了沒有做Server Key Exchange外,其他沒有任何不同
(reset的連接過程中,多了Server Key Exchange),通過google查詢,拜讀了大神的文章《Winreshark抓包理解HTTPS請求流程》了解到,密鑰交換階段,這個步驟是可選步驟,對 Certificate 階段的補充,只有在這幾個場景存在:
- 協(xié)商采用了RSA加密,但是服務端證書沒有提供RSA公鑰
- 協(xié)商采用了DH(EC Diffie-Hellman)加密,但是服務端證書沒有提供DH參數(shù)
- 協(xié)商采用了fortezza_kea加密,但是服務端證書沒有提供參數(shù)
可以從包里看到,是協(xié)商使用Diffie-Hellman算法
下面整理了nginx日志中常見的 error 日志
1.”upstream prematurely(過早的) closed connection”
請求uri的時候出現(xiàn)的異常,是由于upstream還未返回應答給用戶時用戶斷掉連接造成的,對系統(tǒng)沒有影響,可以忽略
2.”recv() failed (104: Connection reset by peer)”
(1)服務器的并發(fā)連接數(shù)超過了其承載量,服務器會將其中一些連接Down掉;
(2)客戶關掉了瀏覽器,而服務器還在給客戶端發(fā)送數(shù)據(jù);
(3)瀏覽器端按了Stop
3.”(111: Connection refused) while connecting to upstream”
用戶在連接時,若遇到后端upstream掛掉或者不通,會收到該錯誤
4.”(111: Connection refused) while reading response header from upstream”
用戶在連接成功后讀取數(shù)據(jù)時,若遇到后端upstream掛掉或者不通,會收到該錯誤
5.”(111: Connection refused) while sending request to upstream”
Nginx和upstream連接成功后發(fā)送數(shù)據(jù)時,若遇到后端upstream掛掉或者不通,會收到該錯誤
6.”(110: Connection timed out) while connecting to upstream”
nginx連接后面的upstream時超時
7.”(110: Connection timed out) while reading upstream”
nginx讀取來自upstream的響應時超時
8.”(110: Connection timed out) while reading response header from upstream”
nginx讀取來自upstream的響應頭時超時
9.”(110: Connection timed out) while reading upstream”
nginx讀取來自upstream的響應時超時
10.”(104: Connection reset by peer) while connecting to upstream”
upstream發(fā)送了RST,將連接重置
11.”upstream sent invalid header while reading response header from upstream”
upstream發(fā)送的響應頭無效
12.”upstream sent no valid HTTP/1.0 header while reading response header from upstream”
upstream發(fā)送的響應頭無效
13.”client intended to send too large body”
用于設置允許接受的客戶端請求內容的最大值,默認值是1M,client發(fā)送的body超過了設置值
14.”reopening logs”
用戶發(fā)送kill -USR1命令
15.”gracefully shutting down”
用戶發(fā)送kill -WINCH命令
16.”no servers are inside upstream”
upstream下未配置server
17.”no live upstreams while connecting to upstream”
upstream下的server全都掛了
18.”SSL_do_handshake() failed”
SSL握手失敗
19.”ngx_slab_alloc() failed: no memory in SSL session shared cache”
ssl_session_cache大小不夠等原因造成
20.”could not add new SSL session to the session cache while SSL handshaking”
ssl_session_cache大小不夠等原因造成