1. 程式人生 > >php 大文件上傳 redis+php resque 較低io消耗

php 大文件上傳 redis+php resque 較低io消耗

最大 序號 服務 長時間 同時 切片 問題: 出現 mys

在做視頻站的時候存在這麽一個情景,用戶需要上傳較大的視頻文件,一般在兩個G以上,且可能存在多人同時上傳的情況。

經過查閱資料解決方案有如下幾種:

1、調整php和nginx文件上傳的最大限制

2、在前端將文件切片上傳後再進行合並

經過我們的評估發現,方案1的做法並不合適,單純的調大文件大小限制,會導致上傳一個文件需要一個連續很長的時間, 占用一個php進程,且可能出現超時等各種情況。

所以我們選擇方案二進行探索:

使用百度webuploader前端插件對大文件進行切片處理,等待所有文件全部上傳完畢後再進行合並。

但是用著用著凸顯出一些問題:

1、大文件在完全上傳完畢後,把一個一個小的切片文件合並成一個大文件,這個時間可能是很長的,很有可能超過php或者nginx的超時限制,這樣給用戶的就是超時提醒,是極為不友好的。

2、文件在合並的時候需要連續長時間的寫入到磁盤中,對服務器io壓力很大,如果mysql在同一臺服務器上也將對整個網站產生壓力。

3、多人同時上傳,且差不多同一時間上傳完畢,再合並對服務器的壓力將更大。。。超時問題也將更加的嚴重。

4、php接收上傳的文件臨時區默認是在磁盤上,整個流程就是接收->寫入磁盤->上傳完畢->讀取切片文件->寫入磁盤,整個流程對服務器壓力較大。

經過查找資料(但是沒找到太多,難道是關鍵詞不對)我們想出了如下大致的解決方案

1、修改php文件上傳存放的臨時目錄,放到ubuntu分配的內存文件目錄,減少io。

2、將上傳完畢再合成修改為邊上傳邊合並,這樣用戶發完最後一個文件就能很快的得到上傳成功或失敗的提醒,同時減少了上面提到的連續長時間磁盤io。

第1點沒什麽說的,修改php配置即可,但是需要註意的是內存的大小限制。

難點主要在第2點中:

具體如下:

1、切片上傳的文件是無序的,可能上傳切片的順序是1、5、3、4、2這樣的,如何保證合並的順序?

2、同一用戶同時上傳多個文件?

3、不同用戶上傳同名文件,如何命名?

這裏主要針對難點1的解決方案進行闡述:

需要的兩個工具:redis和任務調度框架php resque

利用redis維護

一個有序集合(存儲已經上傳的切片文件編號,有序是因為合並切片需要切片的順序)

and

一個普通列表(存儲已經合並的切片編號,用於判讀切片是否連續)

php resque去發起合並任務(每個上傳的文件對應唯一的任務標誌id)

根據php resque的任務狀態確保同一個文件同時只有一個合並任務在進行

每次切片上傳成功後,向該上傳文件的有序集合中,添加一個數據,鍵為切片序號,值也為切片序號

php resque中的job內容:參數主要為(臨時文件名、切片文件總長度,最終保存的文件名)

job:

循環執行:

從有序集合從取第一小的切片號,判斷該切片號-1是否已經在已經合並的切片的普通列表中(切片為1直接開始合並),不在的話循環結束

讀取切片號對應的文件,寫入到最終的文件中,最剛開始不存在則創建。

寫入完畢後,向切片列表中加入該切片編號

刪除該切片文件

繼續循環

如果切片號==文件切片長度,任務over

php 大文件上傳 redis+php resque 較低io消耗