大型 tmp 檔案傳輸在 nginx php-fpm 代理程式中掛起

大型 tmp 檔案傳輸在 nginx php-fpm 代理程式中掛起

我們有一台在 Ubuntu 20 LTS 上執行 WordPress 網站的伺服器,並在 Ubuntu 20 LTS 上安裝了 serverpilot 安裝的 nginx 堆疊。

非常大的上傳似乎陷入了nginx 代理和PHP 之間的切換,我已經完成了我所知道的如何排除故障,而不僅僅是戳它看看會發生什麼(這很少是一個很好的時間利用或前進的方式)。據我所知,我已經增加了必要的超時並提高了所有磁碟限制,但我顯然仍然缺少一些東西。

對於我們的用例,我們需要允許上傳高達 50GB 的文件,我們在運行標準 LAMP 堆疊的臨時環境中可以正常運作。我們對~2GB以下的檔案沒有任何問題,但根據我無法追蹤的一些標準,超過2GB的檔案可能會失敗,也可能不會失敗。在早些時候對問題進行故障排除時,檔案複製停止的時間似乎是任意的(成功達到 10GB),但使用當前配置(見下文),當 PHP 檔案tmp達到 2GB 時,檔案複製始終會停止。

當我們上傳非常大的檔案時,我們可以看到傳入的臨時檔案消耗磁碟空間,直到整個檔案存在/mnt/tmp/[nginx_tmp_path](是的,有足夠的可用磁碟空間)。之後,我們可以看到檔案被複製到 phptmp路徑,但幾秒鐘後,phptmp檔案大小停止成長,複製過程掛起。最終,達到了 600 秒超時之一,並且記錄了錯誤(見下文)。在此螢幕截圖中,我們有一個已完成(從瀏覽器/最終用戶角度來看)的 14.8GB 上傳,該上傳掛在大約 2GB 的 tmp 檔案傳輸上。 PHP tmp 檔案停止成長

在 600 秒週期結束時,Apache 錯誤日誌中顯示以下內容:

(70008)Partial results are valid but processing is incomplete: [client <MY_IP>] AH01075: Error dispatching request to : (reading input brigade), referer: https://<THE_URL>/wp-admin/media-new.php

nginx 錯誤日誌是這樣說的:

2512066#0: *9 upstream timed out (110: Connection timed out) while sending request to upstream, client: <MY_IP>, server: <INTERNAL_IP>, request: "POST /wp-admin/async-upload.php HTTP/2.0", upstream: "http://127.0.0.1:81/wp-admin/async-upload.php", host: "<THE_URL>", referrer: "https://<THE_URL>/wp-admin/media-new.php"

請務必注意,這些訊息直到上傳完全到達伺服器後 10 分鐘才會出現在日誌檔案中,即檔案副本似乎暫停/掛起後 9 分鐘或更長時間。我確信某些東西導致文件副本卡住,然後最終達到超時 - 我不認為問題在於超時本身。在檔案複製停止和日誌檔案中出現逾時錯誤之間的過渡期間,伺服器上沒有增加或異常的活動,並且所有服務均按預期運行和回應。

在當前配置下,PHPtmp檔案總是成長到 2097152 KB(根據du -a),這讓我相信我已經達到了我尚未發現的內建檔案大小限制。

相關的 nginx 伺服器設定選項是: 在server上下文中:

    proxy_connect_timeout 600;
    proxy_read_timeout 600;
    proxy_send_timeout 600;
    proxy_max_temp_file_size 51200m;

    fastcgi_connect_timeout 600;
    fastcgi_read_timeout 600;
    fastcgi_send_timeout 600;
    fastcgi_request_buffering off;

    keepalive_timeout 600;
    send_timeout 600;

    client_max_body_size 0;
    client_body_temp_path /mnt/tmp;
    client_body_in_file_only clean;

Apache的虛擬主機設定:

    RequestReadTimeout header=0 body=0
    Timeout 3600
    ProxyTimeout 3600

最後是 PHP 配置:

memory_limit = -1
max_execution_time = 0
max_input_time = -1
post_max_size = 50G
upload_max_filesize = 50G
default_socket_timeout = -1

我不知道是什麼原因導致了我所看到的症狀。任何指示表示讚賞!

附加說明:症狀讓我覺得不相關,但萬一…網站透過 WP Rocket 運行,但沒有像 CloudFlare 這樣的外部代理服務。

更新:我將這些行加入到 nginx 設定中:

    proxy_http_version 1.1;
    proxy_set_header Connection "";

這稍微改變了症狀,但沒有解決問題。透過此更改,行為已恢復為我之前解釋的內容,並且檔案傳輸在不可預測的位置停止。下面的第一個範例停在 3823176 KB,第二個範例停在 3264364 KB。行為差異的原因對我來說沒有意義,但值得報告。 在此輸入影像描述 在此輸入影像描述

更新2:我已經能夠明確地確定這是tmpnginx 和 php 之間文件切換的問題,但我似乎無法確定導致進程掛起的具體原因。

tmp我們可以透過將這些行新增至 nginx 設定來跳過 nginx 代理程式並僅使用 PHP :

    proxy_buffering off;
    proxy_request_buffering off;

透過此配置,檔案直接進入/mnt/tmp/php<RND_STR>,上傳完成後,我們的應用程式會正確地取出檔案tmp並完成其任​​務。

但是,這會將上傳速度減慢到可用頻寬的大約 1/3,因此這不是一個好的解決方案。然而,它確實證明這不是應用程式問題。

所以這就是正在發生的事情:

  1. 用戶上傳一個大檔案(50GB 是我們的用例最大值)
  2. 檔案tmp完整到達nginx位置
  3. 嘗試將檔案從 nginx 複製tmp到 PHP tmp- 複製過程將在幾秒鐘內在不可預測的地方停止,但在 3GB 到 10GB 之間。 [3b] 此時,我們可以看到兩個tmp文件,並且 PHPtmp文件包含的位元組數應該會不斷增長,直到等於 nginxtmp文件的大小,但事實並非如此。這兩個檔案將完全保持原樣,直到達到 600 秒逾時之一(見上文),然後日誌檔案中會出現錯誤,並且這兩個tmp檔案都會消失。 [3c] 如果檔案小於 3GB,則每次都可以工作。如果檔案超過 3GB,有時可以工作,但其他時候則不行 - 檔案越小,工作的可能性就越大。
  4. 繞過 nginx 的tmp工作完全符合預期,只是上傳速度很慢。

當檔案非常大時,在 nginx 和 PHP 之間的檔案切換過程中肯定會出現一些問題tmp,我很想弄清楚它是什麼。

相關內容