摘要:,在后續測試時遇到一個詭異,當文件過大時,任務腳本上傳到七牛云失敗。當我遇到大文件無法上傳到七牛云時,斷點調試到這里,發現返回的是。后來還真被我找到了,七牛云官方提供一個腳本工具。
業務場景 需求
我們項目有一個文件上傳需求,需要從客戶端上傳到七牛云的對象存儲和自己的應用服務器上。這里使用七牛云主要是實現下載分發。應用服務器需要留一份是因為后續需要做文件分析(并且是上傳后需要立馬分析出結果展現給客戶端)。另外,由于是初期項目,暫時沒考慮用獨立服務器來分析。
所用技術棧服務器:Centos7
開發語言:PHP
框架:Laravel
前端上傳組件:百度的WebUploader
準確的說我經過了三個階段才真正完美的實現了需求(主要解決上傳速度)。
一期解決方案及細節初期面對需求很容易想到的思路是:客戶端先上傳文件到應用服務器(因為上傳完成可以及時做分析),然后再上傳到七牛云上。
所以我的解決方案是:前端用webuploader,后端的七牛云文件處理方面使用了Laravel的一個插件:overtrue/flysystem-qiniu (https://github.com/overtrue/f...,該插件的接口很簡潔好用(但是有坑,后面會說到)。
然后為了解決性能問題,我還做了以下工作:
1,使用分片上傳
2,后續上傳七牛云使用異步的方式(因為文件上傳到其他應用來下載這個文件,中間有許多時間來讓上傳任務的完成)
這里講下分片上傳的實現思路,客戶端主要是把大文件按一定size進行分片,然后上傳到服務器,所以會有多個請求,并且每個請求還需帶上關鍵的信息:當前chunk(從0開始)和chunks(總分片數)。由于我用的是WebUploader組件,所以客戶端不用自己做什么,只需配置下簡單信息(是否分片及分片大小)。
服務端處理邏輯為:
客戶端一個請求過來,分兩種情況:
1,文件總size小于要分片的size,這時候直接處理文件。
2,處理分片情況。
具體邏輯是判斷chunk和chunks,如果相等說明為第一種情況,直接處理上傳,其他走處理分片邏輯。
處理分片的邏輯為:保存當前分片到臨時目錄(按分片命名),然后判斷當所有分片完成時,就合并文件。具體邏輯是判斷 chunk + 1 是否等于chunks。 合并邏輯就是循環讀取臨時文件,然后寫入到一個新的文件(合并后的),這里可以順便刪除臨時文件。
所遇的坑:
這里處理碎片文件時,當初圖方便使用了Laravel的文件處理接口Storage::append,但是這個接口有個坑就是它自作主張的文件結尾加入換行符。導致合并后的文件還原不成原始文件。解決辦法是老老實實使用php的fopen、fwrite、fclose這一套。
關于PHP的異步實現可以參考鳥哥寫的文章:http://www.laruence.com/2008/...
主要方法為:客戶端AJAX、popen函數、curl、fsocketopen等
不過這篇文章比較老了,局限性也大,現在有了協程等處理方案(現在Swoole也提供協程方案了,并且client-server task分發這種也可以用swoole的),而且往架構方面考慮可以使用隊列等(感覺靠譜的還是隊列)。
PS: 我這里前期用的是簡單粗暴的popen,后來使用的是Laravel提供的隊列。
一期方案的問題通過上述所說的方案,很容易就實現了一個版本。但是沒高興多久。。,在后續測試時遇到一個詭異bug,當文件過大時,任務腳本上傳到七牛云失敗。
這里腳本是寫在Laravel的artisan中的,當我把腳本命令直接在終端調試時也是沒有任何異常(準確講是看不了任何異常)
。前面我說過七牛這塊SDK用的是overtrue/flysystem-qiniu ,并且為了考慮性能問題用的是他的writeStream接口。
$disk = Storage::disk("qiniu"); $stream = fopen($localFileName, "r"); $disk->writeStream($fileName, $stream); if (is_resource($stream)) { fclose($stream); }
代碼表面上看起來很理想,用的是文件流上傳(怕吃內存)。但結果證明一切只是表面上的。。
當我遇到大文件無法上傳到七牛云時,斷點調試到$disk->writeStream這里,發現返回的是false。 繼而調試到overtrue/flysystem-qiniu這個擴展的源代碼。然后發現了一個大坑。。
主要是兩個問題:
1,writeStream只是個假的流寫入
具體源碼在擴展的QiniuAdapter.php文件中,這里貼段代碼:
public function writeStream($path, $resource, Config $config) { $contents = ""; while (!feof($resource)) { $contents .= fread($resource, 1024); } $response = $this->write($path, $contents, $config); if (false === $response) { return $response; } return compact("path"); }
注意這里的$contents變量,最終還是等價于一個大文件內容的大小(服務器為此變量開辟的內存)。并且后續還要在方法間傳遞。所以這里是假的流!
2,接口對調試不友好
還有在write方法中,屏蔽了$error,只返回false,這樣不便于我們查問題,最終我是斷點打印這個$error才知道報的錯誤是:“invalid multipart format: multipart: message too large”,這個應該是七牛那邊真正返回的,但這么重要的信息被這個擴展屏蔽了。
二期解決方案知道了一期方案的具體問題所在,我就一直在思考(那個擴展就不提了。。我現在懷疑它的存在意義。。),甚至在想也許一開始整個思路就錯了(通過SDK上傳文件的方案)。后來還真被我找到了,七牛云官方提供一個腳本工具:Qshell(https://github.com/qiniu/qshell)。這個是命令行運行腳本,具體操作看文檔就可以了。放到我的項目也是集成到七牛的任務腳本中。
后來測試可以了,整個流程可以跑通。
但是無意中發現二期的重要問題,這個上傳走的是服務器的上行帶寬!而我們平常付費買的帶寬就是買的上行帶寬!(下行是一般是免費的)。這還怎么搞!由于我們上傳業務是商戶端使用的,平時使用頻次也不會太少,這會導致在上傳時影響前端網站的訪問速度。
這里具體講下服務器帶寬問題(網上查詢后整理的):
首先對服務器帶寬方向的描述一般是用上行和下行,上傳和下載是指動作。
上行是指從服務器流出的帶寬,如果是在其他機器下載服務器上的文件,用的主要是服務器的上行帶寬(這里說下我們平時的網頁瀏覽,其實也是不同客戶端從服務器下數據, html文件、css等然后渲染,所以網頁瀏覽占用的也是上行帶寬)。
下行是指流入到服務器的帶寬,如果是在其他機器上傳文件到服務器,比如用FTP上傳文件,用的主要是服務器的下行帶寬(服務器上下載文件用的也是下行帶寬)。
現在的云提供商比如阿里云不限制的是下行帶寬,大部分服務器的使用環境,都是上行帶寬用的多,下行帶寬用的少。
通過對帶寬的理解,再回到我們項目的上傳實現思路,可以看到一開始就錯了(不該用應用服務器作為中轉)!
三期(最終)方案當初為了節省時間,直接跳過官方文檔,而使用第三方擴展。 現在看來,不得不又回到官方文檔了。
通過把七牛的文檔過一遍,發現是有方案可以避開那個占用服務器上行帶寬的問題的。
主體思路是要避開應用服務器上行帶寬的使用,因為上行帶寬很寶貴,盡量使用下行帶寬(免費、速度很快!阿里的大概60M多每秒)。
具體實現是通過七牛的表單上傳方案直接把客戶端的文件先上傳到七牛(這一步根本不關應用服務器什么事,所以避開了,而且直接上傳到七牛的速度非常快,基本只取決于用戶端的網速,而且對于一般需求,七牛提供了對于到我們應用服務器的回調方法)。然后由于我們應用服務器也需要文件,所以方案是直接在我們應用服務器直接下載七牛的文件(這里可以同步阻塞住,前端做個等待效果解決用戶體驗問題)。因為前面說到流入到服務器占用的是下行帶寬。所以這里速度也會非常快(而且是免費的^_^)。
這種方案基本是完美的了。
總結首先是對個人的反省,前期調研不充足,但是項目初期有點緊,這里也說明投入時間的重要性。
其次關于項目經驗:上傳第三方云存儲,千萬不要使用應用服務器做中轉!可以直接上傳到第三方云服務器,如果有后續處理邏輯的,可以使用他們的回調接口。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/31196.html
摘要:月日下午,七牛云美圖共享日在廈門舉行,來自七牛云美圖廈門大學羅普特等眾位大咖齊聚一堂。七牛云美圖共享日精華語錄計算機識別是按照具體問題具體分析,具體場景具體分析。又稱小牛匯共享日,是小牛匯舉辦的第一個系列活動。 時間機器、穿越星際的宇宙飛船、飛行汽車,幾乎每一部科幻電影作品中都能發明點新東西。超現實技術在引起人們陣陣贊嘆的同時,也在激勵著人們思考如何將不可能變成可能。而在我們的生活當中...
摘要:現在我們必須給七牛云空間綁定一個自己的域名。如對七牛云及其他用戶造成損害,七牛云保留進一步追責的權利。然而七牛目前并不支持這類短期的免費證書。 〇、七牛將定期回收測試域名,正在使用測試域名的小伙伴們必須設置自定義域名了 想必最近很多小伙伴都收到了這封來自七牛云的郵件,這意味著創建七牛云空間時附帶自動生成的域名每30日就會變更一次,再也無法長期使用。現在我們必須給七牛云空間綁定一個自己的...
摘要:現在我們必須給七牛云空間綁定一個自己的域名。如對七牛云及其他用戶造成損害,七牛云保留進一步追責的權利。然而七牛目前并不支持這類短期的免費證書。 〇、七牛將定期回收測試域名,正在使用測試域名的小伙伴們必須設置自定義域名了 想必最近很多小伙伴都收到了這封來自七牛云的郵件,這意味著創建七牛云空間時附帶自動生成的域名每30日就會變更一次,再也無法長期使用。現在我們必須給七牛云空間綁定一個自己的...
閱讀 994·2023-04-25 19:35
閱讀 2633·2021-11-22 09:34
閱讀 3679·2021-10-09 09:44
閱讀 1713·2021-09-22 15:25
閱讀 2931·2019-08-29 14:00
閱讀 3371·2019-08-29 11:01
閱讀 2595·2019-08-26 13:26
閱讀 1735·2019-08-23 18:08