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