Nginx圖片下載不完整的處理過程

济南小老虎發表於2024-06-09

Nginx圖片下載不完整的處理過程


背景

昨天同事進行了nginx的遷移
然後晚上發現圖片展示不全. 
自己其實之前遇到過類似的問題
但是因為熬夜比較久,腦子已經不轉了.
所以花了接近半小時才理清楚.
感覺一些事情不記錄一下, 無法加深印象.

問題現象

客戶的nginx從之前的CentOS遷移到了新機房的銀河麒麟v10SP3
基本功能可用,但是比較大的圖片就顯示不出來了. 
因為當時下午在補覺, 所以上會時間比較晚. 
上會之後看了下問題現場, 因為同期進行了網路切割
所以大家都在討論網路層的問題. 
自己也一直沒插上話.
等到網路問題討論完, 我這邊能插上話後.
讓同事幫忙看了下 error log
裡面發現了 permission denied的提示
然後很明顯就可以定位到時Nginx的許可權相關的問題 
跟同事說 可以修改使用者 從 nobody 到 root 
或者是可以 修改一下 proxy_temp 的目錄許可權
都可以解決這個問題. 

同事為了簡單, 修改了下 proxy_temp 的目錄許可權後問題解決. 

其實最初自己遇到過這個問題
也是因為安全加固之後的一些小的相容性的問題
但是自己當時忘記整理了(因為解決的太暢快了)
以至於這次出問題耗費了半個多小時. 
感覺必須記錄一下將原理搞清楚才可以. 

關於nginx的proxy_temp

語法:proxy_buffering on|off
預設值:proxy_buffering on
上下文:http,server,location

作用:該指令開啟從後端被代理伺服器的響應body緩衝。
    如果proxy_buffering開啟,nginx假定被代理的後端伺服器會以最快速度響應,
    並把內容儲存在由指令 proxy_buffer_size 和 proxy_buffers 指定的緩衝區裡邊.
    如果響應body無法放在記憶體裡邊,那麼部分內容會被寫到磁碟上。
    如果proxy_buffering被關閉了,那麼響應body會按照獲取body的多少立刻同步傳送到客戶端。
    nginx不嘗試計算被代理伺服器整個響應body的大小,nginx能從伺服器接受的最大資料,是由指令 proxy_buffer_size指定的。
    對於基於長輪詢(long-polling)的Comet 應用來說,關閉 proxy_buffering 是重要的,
    不然非同步響應將被快取導致Comet無法工作。
    但是無論proxy_buffering是否開啟,proxy_buffer_size都是生效的

語法:proxy_buffers  數量  size
預設值:proxy_buffers 256 8k
上下文:http,server,location

作用:設定儲存被代理伺服器響應的body所佔用的buffer個數和每個buffer大小。
    具體的意思是說,開闢256個長度為8k大小的read_buf用來儲存body,
    當然不是連線建立初始化時就開闢256個,而是噹噹前buf不夠存響應body時才會新申請一個,最多申請256個buf。

語法:proxy_buffer_size size
預設值:proxy_buffer_size 4k/8k
上下文:http,server,location

作用:Nginx使用該大小申請read_buf,即大小指定了 upstream header 最大長度,
如果響應頭超過了這個長度,Nginx會報upstream sent too big header錯誤,然後client收到的是502。

語法:proxy_temp_path  path [level1 level2 level3]
預設值:proxy_temp_path proxy_temp
上下文:http,server,location
作用:定義proxy的臨時檔案存在目錄以及目錄的層級。

proxy_max_temp_file_size
語法:proxy_max_temp_file_size size;
預設值:proxy_max_temp_file_size 1024m;
上下文:http, server, location

關於解決問題的方法

同事用curl的方式高的
發現會在第100KB 進行截斷
所以很明顯應該是proxy_buffer size的設定.

其實解決問題的思路應該主要有三個:
1. 擴大proxy_buffer的大小. 保證能夠在記憶體裡面放的開
優點,效能最好, 缺點不能無限大, 並且會消耗過多的記憶體. 

2. 修改proxy_temp_path 的目錄許可權.
可以修改屬主, 也可以修改目錄許可權, 保證nginx的worker程序可以有讀寫許可權.

3. 修改nginx的執行使用者.
如果不清楚具體目錄,可以修改worker的使用者給一個高一點許可權的使用者
這樣也可以解決.

關於效能

一般認為 nginx 作為 proxy 的時候 對磁碟的讀寫壓力不大.
但是在這種情況下, 一個是buffer size 一個是max_body_size
其實還是需要中轉到磁碟內的. 

改大buffer區域肯定能夠提供一定的效能. 
linux下采用 sendfile 這種COW的方式減少CPU的記憶體COPY來提高效能
還可以透過gzip 的方式進行 js,css,bmp 等檔案格式的壓縮
減少網路消耗

其實還可以增加一下記憶體檔案系統. 比如 /dev 後者是 /tmp等
將臨時檔案放到記憶體檔案系統的目錄下.
並且增加特定許可權 能夠避免磁碟的拖累, 提高nginx的速度

當然前提是記憶體需要儘量大一點.
吃飽了的馬才能使千里馬. 

相關文章