記一次下載大文件存在數據異常問題排查

最近遇到了一個很詭異的問題,有用戶反饋從文件下載服務測試環境下載一個視頻文件,每次MD5都不一樣。。。

對於文件下載服務來說,下載文件內容錯亂是個很嚴重的問題了,但是之前一直也沒遇到過文件內容錯亂的問題。看了一下問題文件,是一個視頻文件,大小爲1.08GB。第一個反應就是可能是一個大文件下載纔會觸發的問題。接着問用戶如何發現這個問題的,答曰因爲這個視頻文件播放到最後很卡,第二個反應是下載到最後存在數據錯亂。

自己測試了一下,測試環境是100%復現,每次的MD5都是不一樣的。改用另外的大於1G的文件,一樣能復現,排除了特定文件的可能。接着測試500MB的文件和900MB,發現沒問題,推測問題是出在大於1GB的文件上。但是,生產環境卻沒有這個問題。。。

本地起Tomcat測試,竟然發現沒有復現,結合該應用穩定運行多年,線上也沒有人反饋文件異常問題,推測應用本身的邏輯應該是正常的。懷疑的焦點轉移到了Nginx上。直接訪問測試環境的Tomcat,發現也是正常的,確定是Nginx問題。

查看Nginx日誌,發現有很重要的信息:

2019/06/28 11:28:27 [error] 15032#15032: *5973942305 upstream prematurely closed connection while reading upstream, client: 192.168.237.155, server: debug.web.com, request: "GET /v0.1/static/test_mzb/bigtest-d072bc5950f767009175668f781faaf2.rar HTTP/1.1", upstream: "http://172.xx.xx.xx:8092/v0.1/static/test_mzb/bigtest-d072bc5950f767009175668f781faaf2.rar", host: "debug.web.com"

upstream prematurely closed connection while reading upstream這個錯誤信息的意思是Nginx讀取Tomcat請求時,後端服務關閉了連接。網上找到了對應錯誤的討論:Upstream prematurely closed connection while reading upstream · Issue #5706 · owncloud/client,這篇issue中,有人說通過設置proxy_request_buffering off;proxy_buffering off;可以解決這個問題。通過這個線索,懷疑是Nginx的緩存功能導致的問題。

查看Nginx文檔,Module ngx_http_proxy_module,其中描述了在作爲代理服務器時,是否緩存響應的相關配置。總的開關配置是proxy_buffering,表示是否開啓反向代理服務對Response的緩存,默認開啓。開始緩存時,Nginx會以最快的速度從後端服務讀取Response內容,緩存到緩衝區中,緩衝區的大小由proxy_buffer_sizeproxy_buffers配置項指定。如果緩衝區無法裝下所有的響應,則響應的內容會寫入到緩存文件中,緩存文件的最大大小由proxy_max_temp_file_size配置項指定,默認爲1G。Nginx這個緩存行爲會進行到Response讀取完畢,或者是緩存文件寫滿。

這個緩存文件大小爲1G,與出問題的文件是大於1G相吻合。所以可以推論問題的原因是因爲用戶下載文件,Nginx會以最快速度從Tomcat獲取文件流,因爲Nginx與Tomcat處於一個內網,帶寬很高,很快就會把1G的緩存文件寫滿,然後用戶慢慢下載,當用戶下載完這緩存的內容後,Nginx繼續從Tomcat獲取剩餘的內容,但是這會兒連接因爲長時間沒有讀寫過期關閉了,導致Nginx提示upstream prematurely closed connection while reading upstream錯誤。至於爲什麼用戶會繼續下載到後續的錯誤字節數據,這個要看Nginx的具體代碼才能清楚了。

通過將proxy_max_temp_file_size配置爲2G,發現問題解決了,可以確定是這個問題。

參考資料

本文獨立博客地址:記一次下載大文件存在數據異常問題排查 | 木杉的博客

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章