存儲介質使用Mongo的GridFS技術實現,同時採用Mongo的Replica Set與Sharding。前端
應用採用分佈式的環境進行部署,現架構採用Memcache、ActiveMQ、MongoDB、MySQL。java
多人上傳相同文件或者單人上傳多份相同分件,進度條是真實上傳進度,當其中一個用戶上傳完成,其他人也同時變爲秒傳,同時服務器上只存儲一份文件數據,同時支持高併發。ios
Thinking:服務器
Each file has a MD5 value,the same file names,the same MD5 value。網絡
當上傳文件時,首先驗證該MD5值是否存在於Memacache。若是不存在則在Memcache服務器中根據MD5值設置一個標識,好比Uploading。當後續的請求檢測到是Uploading,也可正常上傳,相互不影響。設置一個檢查時間,上傳線程每隔多少秒則到Memcached中檢測狀態是否發生改變,如未發生改變,則繼續讀取數據流內容,當其中一個線程上傳完成時,則將狀態變爲Finished,此操做必定要保證原子性。其餘線程檢測到時,中斷上傳同時產生一個快照,指向底層的真實文件數據塊,並反饋用戶秒傳。同時在系統任務中新增一條刪除任務記錄,經過JMS消息來實現,在服務器空閒時間段自動刪除已經上傳的塊內容,避免數據冗餘,避免出現數據冗餘產生的讀取問題和存儲空間佔用。架構
此種方式能夠實現,可是對Memcache來講,壓力稍大,也可能在檢查時間點未到時,兩人同時上傳,此時冗餘塊也須要作處理,不然會產生數據錯亂,這是一個問題,上傳完成後還須要檢查服務器是否同時存在兩份數據,如存在則取其中一份便可。併發
因爲是分佈式部署,本來想法是經過在多個線程在上傳時,相同MD5值上傳文件的線程,同時持有一個對象實例,對象實例中經過標識屬性來通知其餘線程是否上傳完成,是否繼續讀流。好比經過回調設置標識狀態:分佈式
while (!flag) { //do something... }
可是由於是分佈式部署,此種方式行不通。高併發
此方案雖可實現,但Memcache輪詢壓力稍大,待考慮。spa
網盤上傳文件時,Send check request,判斷服務器中是否有相同MD5的文件存在,若是不存在,則調用newFile接口上傳文件,不然調用updateFile接口,新增該文件版本。
調用UpdateFile接口生成新的FileVersion時,前端的按鈕還處於可點狀態,例如暫停和開始,由於尚未接收到請求響應,響應若是有延遲的話,此時屢次點擊暫停開始的話,會發送多個check和updateFile請求,會產生多個文件版本。
網盤已經存在文件A,有兩種狀況會產生多個版本:
1.客戶端再次在相同位置上傳同名文件。
2.多個客戶端上傳相同文件。
目標
文件版本正常疊加,而且當同一客戶上傳相同文件經過屢次點擊暫停和開始仍是上傳多條相同文件時版本號只發生一次疊加。不一樣用戶上傳相同文件時,多少個用戶則產生多少次疊加操做。
Question:
單用戶上傳相同文件,經過屢次點擊暫停和開始,產生多個版本號,是由於在檢查秒傳的過程當中,請求可能還未響應,此時屢次點擊,會發送屢次秒傳請求道後臺,因此產生多個版本號。
Solution:
相似於表單的重複提交,網絡帶寬和服務器響應中間可能存在延遲,頻繁的點擊上傳開始和暫停按鈕與日常的表達提交屢次點擊是相同的效果。此時能夠在調用UpdateFile接口時使按鈕變灰,當響應後再使按鈕可點擊。
歡迎各位指出缺點和提出好的建議。