
在 Nginx 文件中,有關於三種不同網路逾時的指令,可以為「後端」伺服器配置這些逾時,如下所示:
proxy_connect_timeout
定義與代理伺服器建立連線的逾時。要注意的是,這個超時時間通常不能超過75秒。
這很容易理解——Nginx 即將連接到上游“後端”伺服器,如果在 X 時間內無法連接,它將放棄並返回錯誤。伺服器無法存取、連接過多等。
proxy_read_timeout
定義從代理伺服器讀取回應的逾時。僅在兩個連續的讀取操作之間設定逾時,而不是為整個回應的傳輸設定逾時。如果代理伺服器在此時間內未傳輸任何內容,則連線將關閉。
這也是有道理的——Nginx 已經與“後端”伺服器建立了 TCP 連接,現在即將實際發送請求,但是伺服器需要很長時間來處理,如果需要超過 X 時間,則關閉連接並返回給用戶。
事實上,我很驚訝 Nginx 關閉了連接,我以為它會保留連接,但會向用戶返回錯誤。每次發生逾時時重新建立這些「後端」TCP 連線聽起來成本很高。
proxy_send_timeout
設定將請求傳輸到代理伺服器的逾時。僅在兩個連續的寫入操作之間設定逾時,而不是為整個請求的傳輸設定逾時。如果代理伺服器在此時間內未收到任何內容,則連線將關閉。
這個我不太明白。我確實有一個理論,但我希望有人證實它。我能想到的這個超時的唯一值是請求負載是否很大(例如,帶有 JSON 的大型 POST 請求,或用戶想要保存的文檔)。將請求傳輸到「後端」需要將請求分解為更小的 MTU TCP 段,並將它們作為原始請求的「區塊」發送。因此從技術上講,直到我們成功地將所有區塊傳輸到伺服器之前,我們實際上並沒有發送請求。 Nginx 是否測量每個請求區塊之間的時間?這就是文檔中「寫」的意思嗎?一旦請求實際發送,Nginx 將開始測量proxy_read_timeout
?
答案1
TCP/IP 是所謂的「串流」資料傳輸協定。它旨在讓透過 TCP/IP 連線讀取資料的一方不必關心「段」甚至資料包的大小。在實踐中,這轉化為一種情況,即對等點調用一些傳統的「讀取」操作來獲取遠端對等點發送的資料(例如read
對於 Linux),一次讀取的資料量不一定與遠端提供給單一「寫入」操作的資料量完全相同。 TCP/IP 協定實作總是會根據一次傳遞給「寫入」操作的內容產生適當大小的 IP 封包,而另一端的實作將從這些封包中組裝回資料;但它不會必須將它們交給一些具有相同資料邊界的“讀取”客戶端應用程式!
範例:A 有 50Kb 的資料要為每個外部系統事件發送,如此之多以至於他們無法同時將其全部放入 RAM,因此他們以 16Kb 的區塊發送數據,這是其發送緩衝區的大小。因此,他們首先發送 16Kb,然後再發送 16Kb,然後再發送 16Kb,最後發送 2Kb。 TCP/IP 實作可能會傳送這些 50Kb,在內部緩衝在 128Kb 緩衝區(例如核心緩衝區)中,然後才透過網路傳送,這也有其自身的條件。其中一些資料以發送應用程式甚至不知道的方式分段,由於網路條件而首先到達另一端,並由那裡的 TCP/IP 實作進行組裝並放入內核緩衝區中再次。核心喚醒想要讀取資料的進程-讀取全部 30Kb。接收者必須決定他們是否期望更多以及如何理解期望的程度——格式TCP/IP 不關心「訊息」或資料的內容。
read
這意味著 Nginx 無法知道在基於 Linux 的系統上每次呼叫時它會立即讀取多少客戶端請求。
不過,文檔proxy_send_timeout
稍微暗示了它的用途(強調我的):
設定將請求傳輸到代理伺服器的逾時。僅在兩個連續的寫入操作之間設定逾時,而不是為整個請求的傳輸設定逾時。如果代理伺服器在這段時間內沒有收到任何內容,連線關閉。
事情是,自從 Nginx代理商請求——意味著請求不起源有了它——它等待“下游”客戶端(將請求發送到 Nginx 的連接的遠端,後者作為“代理”的角色現在期望轉發上游)在它之前傳輸請求的資料通過上游連接轉發(寫入)它。
我的理解是,如果[在逾時期間]沒有從下游接收到任何內容,那麼代理伺服器也不會接收到任何內容-然後連線就會關閉。
換句話說,如果下游在 指定的時間內沒有發送任何內容proxy_send_timeout
,Nginx 將關閉與上游的連線。
例如,考慮一個向 Nginx 發送請求的 Web 瀏覽器。第一部分由 Nginx 在時間 A 讀取。然後,它只是等待從瀏覽器讀取更多的請求資料——如果在相對於時間 A 的某個超時 X 後下一個資料還沒有到達,它將關閉與上游的連線。
請注意,這並不一定意味著它將關閉與 Web 瀏覽器的連接——它肯定會為請求返回一些 HTTP 錯誤狀態代碼,但 Web 瀏覽器連接生命週期由一組不同的條件控制proxy_send_timeout
——後者僅涉及Nginx 與上游的連接。