日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Nginx >内容正文

Nginx

invalid signature 错误原因验签失败_Nginx 失败重试机制

發布時間:2025/3/13 Nginx 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 invalid signature 错误原因验签失败_Nginx 失败重试机制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

可直接點擊上方藍字

(網易游戲運維平臺)

關注我們,獲一手游戲運維方案

src

網易游戲 SRE,喜歡鉆研與分享。

背景

Nginx 作為目前應用較廣的反向代理服務,原生提供了一套失敗重試機制,來保證服務的可用性。本文主要是通過一些簡單例子來剖析 Nginx 失敗重試機制,讓讀者能對該機制有一個基礎的了解,避免在使用過程中踩坑。

本文中的結論在以下環境進行驗證:

  • 版本詳情:nginx/1.16.0

  • 安裝方式:使用 apt 從 nginx 官方源安裝

如何定義 fails

在了解 Nginx 的失敗重試機制之前,需要先了解 Nginx 如何定義失敗。

Nginx 通過 proxy_next_upstream 參數來定義什么情況下會被認為是 fails,從而觸發失敗重試機制。

fails 可以分成兩類:

  • 默認錯誤,包括 error、timeout

  • 選擇定義錯誤,包含 invalid_header 以及各種異常 http 狀態碼錯誤等

  • 默認錯誤

    關于默認錯誤,我們再詳細解析一下這兩種錯誤。關于這兩種錯誤的定義,官網文檔已經描述的非常清楚了:

    error: an error occurred while establishing a connection with the server, passing a request to it, or reading the response headertimeout: a timeout has occurred while establishing a connection with the server, passing a request to it, or reading the response header

    出現 error 的場景,常見的是上游服務器的服務重啟、停止,或者異常崩潰導致的無法提供正常服務。而 timeout 的情況,就是代理請求過程中達到對應的超時配置,主要包括了:

    • proxy_connect_timeout,建立三次握手的時間

    • proxy_read_timeout,建立連接后,等待上游服務器響應以及處理請求的時間

    • proxy_send_timeout,數據回傳的間隔時間(注意不是數據發送耗時)

    選擇定義錯誤

    關于選擇定義錯誤,異常狀態碼部分(也就是 4xx、5xx 錯誤)應該是比較好理解,這里主要說一下 invalid_header

    invalid_header: a server returned an empty or invalid response;

    這個場景就是上游服務器返回空響應或者非法響應頭,包括且不僅限于:

    • 上游服務器的業務使用了非標準的 HTTP 協議,nginx 校驗不通過

    • 因服務異常導致響應請求處理返回了異常 header(或者空 header)

    NOTE
    默認只有 error、timeout 會被認為是 fails,統計到健康檢測的 max_fails 計數,如果通過 proxy_next_upstream 定義了其他類型的 fails,那這部分 fails 也會被算到計數器。

    在選擇自定義錯誤的配置上,一定要十分慎重,必須要結合業務實際情況來調整配置,而不是直接復制網上或者其他站點的配置,否則可能踩坑:

    • 配置了不合理的錯誤類型,可能導致一些非預期的所有節點被踢掉的情況

    • 缺少對關鍵錯誤類型的定義,導致出問題的節點一直沒有被踢掉,影響客戶端訪問

    重試機制解析

    Nginx 的失敗重試,就是為了實現對客戶端透明的服務器高可用。然而這部分失敗重試機制比較復雜且官方文檔沒詳細介紹,本文將對其解析,并配合實際場景例子使之更容易被理解。

    基礎失敗重試

    這部分介紹最常見、最基礎的失敗重試場景。

    為了方便理解,使用了以下配置進行分析(proxy_next_upstream 沒有特殊配置):

    upstream?test?{
    ????server?127.0.0.1:8001?fail_timeout=60s?max_fails=2;?#?Server?A
    ????server?127.0.0.1:8002?fail_timeout=60s?max_fails=2;?#?Server?B
    }?

    模擬后端異常的方式是直接將對應服務關閉,造成 connect refused 的情況,對應 error 錯誤。

    在最初始階段,所有服務器都正常,請求會按照輪詢方式依次轉發給 AB 兩個 Server 處理。假設這時 A 節點服務崩潰,端口不通,則會出現這種情況:

  • 請求 1 轉到 A 異常,再重試到 B 正常處理,A fails +1

  • 請求 2 轉到 B 正常處理

  • 請求 3 轉到 A 異常,再重試到 B 正常處理,A fails +1 達到 max_fails 將被屏蔽 60s

  • 屏蔽 A 的期間請求都只轉給 B 處理,直到屏蔽到期后將 A 恢復重新加入存活列表,再按照這個邏輯執行

  • 如果在 A 的屏蔽期還沒結束時,B 節點的服務也崩潰,端口不通,則會出現:

  • 請求 1 轉到 B 異常,此時所有線上節點異常,會出現:

    • AB 節點一次性恢復,都重新加入存活列表

    • 請求轉到 A 處理異常,再轉到 B 處理異常

    • 觸發?no live upstreams 報錯,返回 502 錯誤

    • 所有節點再次一次性恢復,加入存活列表

    請求 2 依次經過 AB 均無法正常處理, 觸發 no live upstreams 報錯,返回 502 錯誤

    重試限制方式

    默認配置是沒有做重試機制進行限制的,也就是會盡可能去重試直至失敗。

    Nginx 提供了以下兩個參數來控制重試次數以及重試超時時間:

    • proxy_next_upstream_tries:設置重試次數,默認 0 表示無限制,該參數包含所有請求 upstream server 的次數,包括第一次后之后所有重試之和;

    • proxy_next_upstream_timeout:設置重試最大超時時間,默認 0 表示不限制,該參數指的是第一次連接時間加上后續重試連接時間,不包含連接上節點之后的處理時間

    為了方便理解,使用以下配置進行說明(只列出關鍵配置):

    proxy_connect_timeout?3s;
    proxy_next_upstream_timeout?6s;
    proxy_next_upstream_tries?3;

    upstream?test?{
    ????server?127.0.0.1:8001?fail_timeout=60s?max_fails=2;?#?Server?A
    ????server?127.0.0.1:8002?fail_timeout=60s?max_fails=2;?#?Server?B
    ????server?127.0.0.1:8003?fail_timeout=60s?max_fails=2;?#?Server?C
    }

    第 2~3 行表示在 6 秒內允許重試 3 次,只要超過其中任意一個設置,Nginx 會結束重試并返回客戶端響應(可能是錯誤碼)。我們通過 iptables DROP 掉對 8001、8002 端口的請求來模擬 connect timeout 的情況:

    iptables?-I?INPUT??-p?tcp?-m?tcp?--dport?8001?-j?DROP
    iptables?-I?INPUT??-p?tcp?-m?tcp?--dport?8002?-j?DROP

    則具體的請求處理情況如下:

  • 請求 1 到達 Nginx,按照以下邏輯處理

    • 先轉到 A 處理,3s 后連接超時,A fails +1

    • 重試到 B 處理,3s 后連接超時,B fails +1

    • 到達設置的 6s 重試超時,直接返回 `504 Gateway Time-out` 到客戶端,不會重試到 C

    請求 2 轉到 C 正常處理

    請求 3 到達 Nginx

    • 先轉到 B 處理,3s 后連接超時,B 達到 max_fails 將被屏蔽 60s

    • 轉到 C 正常處理

    請求 4 達到 Nginx:

    • 先轉到 A 處理,3s 后連接超時,A 達到 max_fails 將被屏蔽 60s

    • 轉到 C 正常處理

    后續的請求將全部轉到 C 處理直到 AB 屏蔽到期后重新加入服務器存活列表

    從上面的例子,可以看出 proxy_next_upstream_timeout 配置項對重試機制的限制,
    重試次數的情況也是類似,這里就不展開細講了。

    關于 backup 服務器

    Nginx 支持設置備用節點,當所有線上節點都異常時啟用備用節點,同時備用節點也會影響到失敗重試的邏輯,因此單獨列出來介紹。

    upstream 的配置中,可以通過 backup 指令來定義備用服務器,其含義如下:

  • 正常情況下,請求不會轉到到 backup 服務器,包括失敗重試的場景

  • 當所有正常節點全部不可用時,backup 服務器生效,開始處理請求

  • 一旦有正常節點恢復,就使用已經恢復的正常節點

  • backup 服務器生效期間,不會存在所有正常節點一次性恢復的邏輯

  • 如果全部 backup 服務器也異常,則會將所有節點一次性恢復,加入存活列表

  • 如果全部節點(包括 backup)都異常了,則 Nginx 返回 502 錯誤

  • 為了方便理解,使用了以下配置進行說明:

    upstream?test?{
    ????server?127.0.0.1:8001?fail_timeout=60s?max_fails=2;?#?Server?A
    ????server?127.0.0.1:8002?fail_timeout=60s?max_fails=2;?#?Server?B
    ????server?127.0.0.1:8003?backup;?#?Server?C
    }?

    在最初始階段,所有服務器都正常,請求會按照輪詢方式依次轉發給 AB 兩個節點處理。當只有 A 異常的情況下,與上文沒有 backup 服務器場景處理方式一致,這里就不重復介紹了。

    假設在 A 的屏蔽期還沒結束時,B 節點的服務也崩潰,端口不通,則會出現:

  • 請求 1 轉到 B 處理,異常,此時所有線上節點異常,會出現:

    • AB 節點一次性恢復,都重新加入存活列表

    • 請求轉到 A 處理異常,再重試到 B 處理異常,兩者 fails 都 +1

    • 因 AB 都異常,啟用 backup 節點正常處理,并且 AB 節點一次性恢復,加入存活列表

    請求 2 再依次經過 A、B 節點異常,轉到 backup 處理,兩者 fails 都達到 max_fails:

    • AB 節點都將會被屏蔽 60s,并且不會一次性恢復

    • backup 節點正式生效,接下來所有請求直接轉到 backup 處理

    • 直到 AB 節點的屏蔽到期后,重新加入存活列表

    假設 AB 的屏蔽期都還沒結束時,C 節點的服務也崩潰,端口不通,則會出現

  • 請求 1 轉到 C 異常,此時所有節點(包括 backup)都異常,會出現:

    • ABC 三個節點一次性恢復,加入存活列表

    • 請求轉到 A 處理異常,重試到 B 處理異常,最后重試到 C 處理異常

    • 觸發 `no live upstreams` 報錯,返回 502 錯誤

    • 所有節點再次一次性恢復,加入存活列表

    請求 2 依次經過 AB 節點異常,重試到 C 異常,最終結果如上個步驟,返回 502 錯誤

    踩坑集錦

    如果不熟悉 HTTP 協議,以及 Nginx 的重試機制,很可能在使用過程中踩了各種各樣的坑:

    • 部分上游服務器出現異常卻沒有重試

    • 一些訂單創建接口,客戶端只發了一次請求,后臺卻創建了多個訂單,等等…

    以下整理了一些常見的坑,以及應對策略。

    需要重試卻沒有生效

    接口的 POST 請求允許重試,但實際使用中卻沒有出現重試,直接報錯。

    從 1.9.13 版本,Nginx 不再會對一個非冪等的請求進行重試。如有需要,必須在 proxy_next_upstream 配置項中顯式指定 non_idempotent 配置。參考 RFC-2616 的定義:

    • 冪等 HTTP 方法:GET、HEAD、PUT、DELETE、OPTIONS、TRACE

    • 非冪等 HTTP 方法:POST、LOCK、PATCH

    如需要允許非冪等請求重試,配置參考如下(追加 non_idemponent 參數項):

    proxy_next_upstream?error?timeout?non_idemponent;

    該配置需要注意的點:

  • 添加非冪等請求重試是追加參數值,不要把原來默認的 error/timeout 參數值去掉

  • 必須明確自己的業務允許非冪等請求重試以避免業務異常

  • 禁止重試的場景

    一些場景不希望請求在多個上游進行重試,即使上游服務器完全掛掉。

    正常情況下,Nginx 會對 error、timeout 的失敗進行重試,對應默認配置如下:

    proxy_next_upstream?error?timeout;

    如希望完全禁止重試,需要顯式指定配置來關閉重試機制,配置如下:

    proxy_next_upstream?off;

    重試導致性能問題

    錯誤配置了重試參數導致 Nginx 代理性能出現異常

    默認的 error/timeout 是不會出現這種問題的。在定義重試場景時,需要結合業務情況來確定是否啟用自定義錯誤重試,而不是單純去復制其他服務的配置。比如對于某個業務,沒有明確自己業務情況,去網上復制了 Nginx 配置,其中包括了:

    proxy_next_upstream?error?timeout?invalid_header?http_500?http_503?http_404;

    那么只需要隨便定義一個不存在的 URI 去訪問該服務頻繁去請求該服務,就可以重復觸發 Nginx no live upstreams 報錯,這在業務高峰情況下,性能將受到極大影響。同樣,如果使用的代碼框架存在不標準 HTTP 處理響應情況,惡意構造的請求同樣也會造成類似效果。

    因此在配置重試機制時,必須先對業務的實際情況進行分析,嚴謹選擇重試場景。

    異常的響應超時重試

    某冪等接口處理請求耗時較長,出現非預期的重試導致一個請求被多次響應處理。

    假設該接口處理請求平均需要 30s,而對應的代理超時為:

    proxy_read_timeout?30s;

    默認的重試包含了 timeout 場景,在這個場景下,可能會有不到一半的請求出現超時情況,同時又因為是冪等請求,所有會進行重試,最終導致一個的超時請求會被發到所有節點處理的請求放大情況。

    因此在進行超時設置時,也必須要跟進業務實際情況來調整。可以適當調大超時設置,并收集請求相關耗時情況進行統計分析來確定合理的超時時間。

    異常的連接超時重試

    因上游服務器異常導致連接問題,客戶端無超時機制,導致請求耗時非常久之后才失敗。

    已知所有上游服務器異常,無法連接或需要非常久(超過 10s)才能連接上,假設配置了連接超時為:

    proxy_connect_timeout?10;

    在這種情況下,因客戶端無超時設置,冪等請求將卡住 10*n 秒后超時(n 為上游服務器數量)。
    因此建議:

  • 客戶端設置請求超時時間

  • 配置合理的 proxy_connect_timeout

  • 配合 proxy_next_upstream_timeout、proxy_next_upstream_tries 來避免重試導致更長超時

  • 往期精彩

    MongoDB 最佳實踐:為什么升級之后負載升高了

    Linux網絡數據包的揭秘以及常見的調優方式總結

    Python:requests超時機制實現

    斷點原理與實現

    疑難雜癥篇之 ulimit

    總結

    以上是生活随笔為你收集整理的invalid signature 错误原因验签失败_Nginx 失败重试机制的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。