Connection reset by peer 全解
-
瘋狂創客圈 經典圖書 : 《Netty Zookeeper Redis 高併發實戰》 面試必備 + 面試必備 + 面試必備 【部落格園總入口 】
-
瘋狂創客圈 經典圖書 : 《SpringCloud、Nginx高併發核心程式設計》 大廠必備 + 大廠必備 + 大廠必備 【部落格園總入口 】
-
入大廠+漲工資必備: 高併發【 億級流量IM實戰】 實戰系列 【 SpringCloud Nginx秒殺】 實戰系列 【部落格園總入口 】
知識鋪墊
瘋狂創客圈 《SpringCloud Nginx 高併發核心程式設計》Java 工程師/ 架構師 必備【連結 】
1錯誤資訊
Connection reset by peer
nginx的錯誤日誌中會出現
Connection reset by peer) while reading response header from upstream, client: 1.1.1.1, server: 102.local, request: "GET / HTTP/1.1", upstream: "fastcgi://127.0.0.1:9000
日誌檢視方法
這個錯誤是在nginx的錯誤日誌中發現的,為了更全面的掌握nginx執行的異常,強烈建議在nginx的全域性配置中增加
error_log logs/error.log notice;
這樣,就可以記錄nginx的詳細異常資訊。
2 原因一:連線已經被上游close。
服務端確實已經關閉了連線: upstream傳送了RST,將連線重置。
errno = 104 錯誤表明你在對一個對端socket已經關閉的的連線呼叫write或send方法,在這種情況下,呼叫write或send方法後,對端socket便會向本端socket傳送一個RESET訊號,在此之後如果繼續執行write或send操作,就會得到errno為104,錯誤描述為connection reset by peer。
如果對方socket已經執行了close的操作,本端socket還繼續在這個連線上收發資料,就會觸發對端socket傳送RST報文。按照TCP的四次握手原理,這時候本端socket應該也要開始執行close的操作流程了,而不是接著收發資料。
- 比如,當後端為php程式時,如果php執行較慢,並超出php-fpm.conf的request_terminate_timeout設定的秒數。request_terminate_timeout用於設定當某個php指令碼執行最長時間,若超出php-fpm程序管理器強行中止當前程式,並關閉fastcgi和nginx的網路連線,然後nginx中就會出現Connection reset by peer的錯誤了。
也就是說,產生這個錯誤的原因是:php 程式的執行時間超出request_terminate_timeout設定的值。
在php-fpm環境下,在php的安裝目錄的etc/php-fpm.conf中有此值的設定項,可將其設定為0或更大的值。這樣將php的request_terminate_timeout設定為較大的值或0,可減少因php指令碼執行時行過長導致nginx產生Connection reset by peer錯誤。
- 比如,當後端為java 程式時,
java 的也類似,不能Java端主動關閉連線。 如果上游的tomcat 或者 netty 已經關閉連線, 那麼nginx 肯定就是 Connection reset by peer
3 原因二:資料長度不一致
傳送端和接收端事先約定好的資料長度不一致導致的,接收端被通知要收的資料長度小於傳送端實際要傳送的資料長度。
4 原因三: FastCGI 快取小,timeout太小。
nginx的buffer太小,timeout太小。主要指php的環境,nginx如果要解析php指令碼語言,就必須通過配置fastcgi模組來提供對php支援。
問題概述:圖片bit 64生成資料流太大,導致小程式分享彈窗的二維碼圖片生成失敗
nginx http模組新增以下引數配置:
fastcgi_buffer_size 128k;
fastcgi_buffers 4 128k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 128k;
後臺報錯:
排查:
Client------>nginx------->h5------>nginx---------->client
客戶端通過h5的nginx頁面點選,nginx反向代理到h5 [無異常]
h5通過客戶端請求調取相應介面 [無異常]
介面返回資料通過nginx展示給客戶端 [異常]
Ps: 圖片通過bit 64解析生成返回給客戶端,由於資料長度太長導致
解決方法:
調整nginx配置檔案引數,修改後引數:
fastcgi_buffer_size 256k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
先簡單的說一下 Nginx 的 buffer 機制,對於來自 FastCGI Server 的 Response,Nginx 將其緩衝到記憶體中,然後依次傳送到客戶端瀏覽器。緩衝區的大小由 fastcgi_buffers 和 fastcgi_buffer_size 兩個值控制。
比如如下配置:
fastcgi_buffers 8 4K;
fastcgi_buffer_size 4K;
fastcgi_buffers 控制 nginx 最多建立 8 個大小為 4K 的緩衝區,而 fastcgi_buffer_size 則是處理 Response 時第一個緩衝區的大小,不包含在前者中。所以總計能建立的最大記憶體緩衝區大小是 84K+4K = 36k。而這些緩衝區是根據實際的 Response 大小動態生成的,並不是一次性建立的。比如一個 8K 的頁面,Nginx 會建立 24K 共 2 個 buffers。
當 Response 小於等於 36k 時,所有資料當然全部在記憶體中處理。如果 Response 大於 36k 呢?fastcgi_temp 的作用就在於此。多出來的資料會被臨時寫入到檔案中,放在這個目錄下面。同時你會在 error.log 中看到一條類似 warning。
顯然,緩衝區設定的太小的話,Nginx 會頻繁讀寫硬碟,對效能有很大的影響,但也不是越大越好,沒意義,呵呵!
FastCGI緩衝設定主要引數
fastcgi_buffers 4 64k
這個引數指定了從FastCGI程序到來的應答,本地將用多少和多大的緩衝區讀取,假設一個PHP或JAVA指令碼所產生頁面大小為256kb,那麼會為其分配4個64kb的緩衝來快取;若頁面大於256kb,那麼大於256kb的部分會快取到fastcgi_temp指定路徑中,這並非是個好辦法,記憶體資料處理快於硬碟,一般該值應該為站點中PHP或JAVA指令碼所產生頁面大小中間值,如果站點大部分指令碼所產生的頁面大小為256kb,那麼可把值設定為16 16k,4 64k等。
fastcgi_buffer_size=64k
讀取fastcgi應答第一部分需要多大緩衝區,該值表示使用1個64kb的緩衝區讀取應答第一部分(應答頭),可以設定為fastcgi_buffers選項緩衝區大小。
fastcgi_connect_timeout=300
連線到後端fastcgi超時時間,單位秒,下同。
fastcgi_send_timeout=300
向fastcgi請求超時時間(這個指定值已經完成兩次握手後向fastcgi傳送請求的超時時間)
fastcgi_reAd_timeout=300
接收fastcgi應答超時時間,同理也是2次握手後。
5 原因四: proxy_buffer快取小
原因就是請求的標頭檔案過大導致502錯誤
解決方法就是提高頭部的快取
http{
client_header_buffer_size 5m;
location / {
proxy_buffer_size 128k;
proxy_busy_buffers_size 192k;
proxy_buffers 4 192k;
}
}
原因五:沒有設定keepalive
ngx_http_upstream_check_module這個模組,在使用tcp檢測後端狀態時,只進行了TCP的三次握手,沒有主動斷開這個連線,而是等待服務端來斷開。當後端是nginx或者tomcat時(linux上),超時後後端會發fin包關閉這個連線。這個錯誤日誌recv() failed (104: Connection reset by peer)是在後端為IIS的情況下丟擲的,抓包發現IIS並不會發fin包來斷開連結,而是在超時後發RST包重置連線,所以導致了這個問題。
從這個問題也反應出ngx_http_upstream_check_module這個模組還是需要完善下檢測機制的,如果是在檢測後端狀態後主動關閉這個連線,應該就不會出現connect reset這個問題
通過修改原始碼已經解決了該問題
static ngx_check_conf_t ngx_check_types[] = {
{ NGX_HTTP_CHECK_TCP,
ngx_string("tcp"),
ngx_null_string,
0,
ngx_http_upstream_check_peek_handler,
ngx_http_upstream_check_peek_handler,
NULL,
NULL,
NULL,
0,
1 },
將最後一行的1改為0即可,根據資料結構分析可得知,這個1代表啟用keepalived,所以客戶端才不會主動斷開連線,因為這是tcp的埠連通性檢查,不需要keepalived,將其改為0禁止keepalived即可。
修改之後的程式碼如下:
static ngx_check_conf_t ngx_check_types[] = {
{ NGX_HTTP_CHECK_TCP,
ngx_string("tcp"),
ngx_null_string,
0,
ngx_http_upstream_check_peek_handler,
ngx_http_upstream_check_peek_handler,
NULL,
NULL,
NULL,
0,
0 },
原因六:設定lingering_close
即使你禁用了 http keepalive,nginx 仍然會嘗試處理 HTTP 1.1 pipeline 的請求。你可以配置
lingering_close off 禁用此行為,但這不是推薦的做法,因為會違反 HTTP 協議。見
http://nginx.org/en/docs/http/ngx_http_core_module.html#lingering_close
nginx快速定位異常
錯誤資訊 | 錯誤說明 |
---|---|
"upstream prematurely(過早的) closed connection" | 請求uri的時候出現的異常,是由於upstream還未返回應答給使用者時使用者斷掉連線造成的,對系統沒有影響,可以忽略 |
"recv() failed (104: Connection reset by peer)" | (1)伺服器的併發連線數超過了其承載量,伺服器會將其中一些連線Down掉; (2)客戶關掉了瀏覽器,而伺服器還在給客戶端傳送資料; (3)瀏覽器端按了Stop |
"(111: Connection refused) while connecting to upstream" | 使用者在連線時,若遇到後端upstream掛掉或者不通,會收到該錯誤 |
"(111: Connection refused) while reading response header from upstream" | 使用者在連線成功後讀取資料時,若遇到後端upstream掛掉或者不通,會收到該錯誤 |
"(111: Connection refused) while sending request to upstream" | Nginx和upstream連線成功後傳送資料時,若遇到後端upstream掛掉或者不通,會收到該錯誤 |
"(110: Connection timed out) while connecting to upstream" | nginx連線後面的upstream時超時 |
"(110: Connection timed out) while reading upstream" | nginx讀取來自upstream的響應時超時 |
"(110: Connection timed out) while reading response header from upstream" | nginx讀取來自upstream的響應頭時超時 |
"(110: Connection timed out) while reading upstream" | nginx讀取來自upstream的響應時超時 |
"(104: Connection reset by peer) while connecting to upstream" | upstream傳送了RST,將連線重置 |
"upstream sent invalid header while reading response header from upstream" | upstream傳送的響應頭無效 |
"upstream sent no valid HTTP/1.0 header while reading response header from upstream" | upstream傳送的響應頭無效 |
"client intended to send too large body" | 用於設定允許接受的客戶端請求內容的最大值,預設值是1M,client傳送的body超過了設定值 |
"reopening logs" | 使用者傳送kill -USR1命令 |
"gracefully shutting down", | 使用者傳送kill -WINCH命令 |
"no servers are inside upstream" | upstream下未配置server |
"no live upstreams while connecting to upstream" | upstream下的server全都掛了 |
"SSL_do_handshake() failed" | SSL握手失敗 |
"ngx_slab_alloc() failed: no memory in SSL session shared cache" | ssl_session_cache大小不夠等原因造成 |
"could not add new SSL session to the session cache while SSL handshaking" | ssl_session_cache大小不夠等原因造成 |
參考:
https://github.com/alibaba/tengine/issues/901
https://my.oschina.net/u/1024107/blog/1838968
https://blog.csdn.net/zjk2752/article/details/21236725
http://nginx.org/en/docs/http/ngx_http_core_module.html#lingering_close
https://blog.csdn.net/crj121624/article/details/79956283t/u/1024107/blog/1838968
https://blog.csdn.net/zjk2752/article/details/21236725
http://nginx.org/en/docs/http/ngx_http_core_module.html#lingering_close
https://blog.csdn.net/crj121624/article/details/79956283
回到◀瘋狂創客圈▶
瘋狂創客圈 - Java高併發研習社群,為大家開啟大廠之門