檔案上傳系統設計 (9) —— 多媒體處理流水線
在上一篇中,我們成功地將大檔案切片並「流」進了伺服器。但是,如果使用者上傳的是一段 4K 影片,或者是一個 100MB 的 PDF,後端的工作才剛剛開始。
你不能在同一個 HTTP 請求中進行影片轉碼,因為那可能需要幾分鐘甚至幾小時,瀏覽器會直接超時 (Timeout)。這就是 多媒體處理流水線 (Media Pipeline) 登場的時候。
一、 不要阻塞你的 API:非同步架構
處理大型檔案(縮圖、轉碼、語音轉文字)的核心原則是:解耦 (Decoupling)。
- API Server:只負責接收檔案,存好後立即回傳「上傳成功,處理中」。
- Worker Server:專門負責運算的背景服務,從隊列中領取任務執行。
- Message Queue:中間的調度中心。
二、 任務隊列:以 BullMQ 為例 (Redis-based)
在 Node.js 生態中,BullMQ 是處理這類背景任務的首選。
工作流程:
- Producer (API):當檔案合併完成,將「處理任務」丟進 Redis 隊列。
- Consumer (Worker):Worker 閒置時自動從隊列抓取任務。
javascript
// Producer: API 段
await imageQueue.add("process-thumbnail", {
fileId: "abc-123",
path: "/uploads/raw/me.mp4",
});三、 FFmpeg 實戰:轉碼與封面擷取
FFmpeg 是多媒體處理界的瑞士刀。透過它,你可以自動化產生展示所需的素材。
1. 擷取影片第一秒作為封面
bash
ffmpeg -i input.mp4 -ss 00:00:01 -vframes 1 thumbnail.jpg2. 在 Node.js 中調用 (使用 fluent-ffmpeg)
javascript
const ffmpeg = require("fluent-ffmpeg");
ffmpeg("/path/to/video.mp4").screenshots({
timestamps: ["00:01"],
filename: "thumb.png",
folder: "/uploads/thumbs",
size: "320x240",
});四、 狀態追蹤:處理完了怎麼辦?
當背景任務完成(或失敗)時,系統必須有機制告訴使用者。
- 輪詢 (Polling):前端每隔 3 秒問一次 API:「好了嗎?」。簡單但浪費資源。
- WebSocket:Worker 處理完後,透過 Socket.io 直接推送通知給對應的 User。
- Webhook:如果處理是交給外部雲端服務(如 AWS Elastic Transcoder),它們會發送一個 HTTP 請求到你的專用 URL 告知結果。
總結
一個專業的多媒體系統,其強大之處在於「上傳後的自動化」:
- 解耦:保護 API Server 不被重型任務壓垮。
- 持久化:隊列確保任務即使在重啟後也不會遺失。
- 標準化:利用 FFmpeg 統一所有使用者上傳的混亂格式。
下一篇,我們將討論檔案系統的最後一道關卡:私有檔案的訪問控制。
️ 進階挑戰
如果有多個 Worker 同時在處理轉碼,你該如何防止兩個 Worker 同時處理同一個檔案?任務隊列中的「原子性 (Atomicity)」在此起到了什麼作用?
延伸閱讀與資源
- FFmpeg Official: Documentation
- BullMQ: Guide to message queues