AWS國際帳號服務 AWS S3 大檔案分段上傳失敗續傳方法
前言:為什麼你需要「續傳」而不是「重來」
大檔案上傳 S3,真正讓人痛的往往不是「能不能上傳」,而是「上傳到一半失敗後怎麼辦」。網路抖動、公司代理不穩、用戶端休眠、行動網路切換、同一時間大量上傳造成限流、甚至簽章到期……都可能讓你把已花掉的時間與流量付諸流水。
分段上傳(Multipart Upload)本來就是為了讓大檔案能分批傳、加速上傳、提升可靠性。更重要的是:它提供了「續傳」所需要的關鍵資訊——每次上傳會有一個 UploadId,以及每個分段(part)都有自己的 PartNumber。當上傳中斷,你不必從頭開始,只要知道目前已成功的分段有哪些,就能接著傳剩下的。
本文會用實務角度,把「失敗後怎麼續傳」講清楚:你要保存什麼、重試怎麼做、如何避免分段不一致、如何在 API 層判斷哪些 part 已存在,最後再給出一套可落地的排障流程。
分段上傳的底層機制:續傳的核心其實很簡單
在 S3 分段上傳裡,流程大致是這樣:
- 發起分段上傳:S3 回傳 UploadId。
- 把檔案切成多個 part,每個 part 指定 PartNumber,並上傳。
- 當所有 part 上傳完成後,呼叫 CompleteMultipartUpload,把各 part 合併成最終物件。
如果中途失敗,你保有兩個關鍵線索:
- UploadId:同一次 multipart upload 的識別碼。
- 已完成的 PartNumber 清單:哪些分段已成功上傳到同一個 UploadId。
續傳的本質就是:用原 UploadId 繼續上傳缺失的 part,最後再 Complete。
什麼情況會導致「分段上傳失敗」
AWS國際帳號服務 你遇到的失敗可能不只是一種,原因不同,處理方式也會不同。下面是常見類型:
1. 網路中斷或超時
最常見。尤其是長時間上傳,TCP 連線重置、DNS 波動、代理重連都會造成某些 part 傳輸失敗。這種情況通常「不必重來」,因為已完成的 part 仍然在 S3 端。
2. 用戶端程式中止
例如程式崩潰、使用者關閉、容器被重啟。只要你保存了 UploadId,就有機會續傳。
3. 權限或策略改變
若上傳憑證(IAM 權限)在上傳期間被撤銷或變更,後續 part 可能會被拒絕。這時續傳還是可以做,但你要先處理授權問題,否則會一直失敗。
4. 簽章過期(尤其是 pre-signed URL 或 STS)
如果你用的是臨時憑證或簽章式上傳,簽章可能在中途過期。這種失敗通常需要重新取得有效的憑證或簽章,再繼續上傳。
5. 你重切檔導致分段配置不一致
這是很多人忽略的雷。Multipart Upload 要求同一個 UploadId 的 part 內容與大小邏輯要一致;如果你採用不同分段大小,或在續傳時切片策略不一致,可能導致校驗失敗或直接合併失敗。
續傳方案設計:先存狀態,再動手重試
真正可落地的續傳,不是靠「運氣」,而是靠狀態管理。建議你在本地或外部存儲保存以下資料:
- 檔案唯一識別:可用檔案大小、最後修改時間、或計算雜湊(但雜湊本身也要成本)。至少要能辨識「這次上傳的檔案」是不是同一個。
- UploadId:發起後立刻存。
- 分段大小(part size)與切片規則:例如每個 part 多少 MB,以及最後一段的處理方式。
- 已完成的 PartNumber 列表:可以在每次成功上傳 part 後更新。
- ETag/Checksum(可選但建議):用於後續驗證或除錯。
如果你不想本地保存「已完成的 PartNumber」,也可以在需要續傳時直接查 S3 已完成的 part 清單(後面會講)。但本地狀態仍然很有用,因為它能減少查詢次數,且能讓你在斷線期間持續進行更精準的判斷。
實務核心:如何判斷哪些 part 已成功(續傳的關鍵一步)
在你要續傳時,最可靠的做法是向 S3 詢問這個 UploadId 的目前進度。AWS 提供用於列出 multipart upload 的接口,可以得到已上傳的 part 列表(通常包含 PartNumber 以及對應的 ETag)。
你拿到清單後,就可以把「缺失的 part」收集起來,對它們發起上傳。已存在的 part 直接略過。
這個步驟的好處是:就算你的本地狀態丟了,只要 UploadId 還在(或你能從持久化儲存回收它),仍然可以續傳。
續傳流程範本(概念層,不綁特定語言)
你可以把整個流程拆成四段:初始化、上傳、恢復、完成。
第一步:初始化(發起 Multipart Upload 並落盤 UploadId)
- 檢查本地是否已存在該檔案的上傳紀錄:包含 UploadId、part size、切片規則。
- 若不存在:發起 CreateMultipartUpload,取得 UploadId,並立刻保存。
- 若存在:確認檔案特徵一致;不一致就不要續傳,避免產生不可預期的錯誤。
第二步:上傳(以 part 為單位重試)
- AWS國際帳號服務 計算每個 part 的起訖範圍。
- 逐個上傳 part(可以併發,但併發度要可控)。
- 每次 part 成功後立刻更新本地狀態(至少更新 PartNumber 已完成)。
- 失敗的 part:只重試該 part,不要重複從頭。
AWS國際帳號服務 重試策略建議採用「指數退避 + 隨機抖動」,並設置最大重試次數。對網路類錯誤重試,對權限類錯誤就立刻停止並回報。
第三步:恢復(從 UploadId 查詢缺失 part)
- 當偵測到整體上傳失敗(或程式重啟)後:使用保存的 UploadId。
- 呼叫列出已上傳 part 的接口,得到已完成清單。
- 對照本次檔案的分段規則,計算缺失 PartNumber 集合。
- 只對缺失 part 進行上傳,並繼續更新狀態。
第四步:完成(CompleteMultipartUpload)與清理
- 當缺失 part 全部上傳完成:呼叫 CompleteMultipartUpload。
- 成功後刪除本地狀態檔或標記已完成。
- 若上傳長時間無法完成,可考慮 AbortMultipartUpload 釋放資源,避免產生累積的未完成 multipart upload。
把常見錯誤拆解:為什麼續傳仍然可能失敗
續傳不是萬靈丹。即使你做了保存 UploadId 與查詢已存在 part,仍可能遇到失敗。這時你要有判斷能力。
錯誤一:PartNumber 對不上(切片規則不一致)
如果續傳時你改了 part size,或檔案內容已變(例如檔案被替換、重新生成),PartNumber 對應的內容就不再一致。S3 端可能允許部分上傳,但最終 Complete 可能失敗,或生成的檔案內容與預期不同。
建議:把 part size 與檔案特徵(大小、最後修改時間或摘要)一起保存,續傳時比對,不符合就改走新上傳。
錯誤二:你以為 part 已成功,但其實你沒有正確記錄
很多人把「送出請求就算成功」或「收到回應但沒確認 ETag」當作完成標記。真正的完成應以 S3 返回成功狀態為準,並保存 S3 回傳的 ETag(或至少確保是對應到該 PartNumber 的成功回應)。
錯誤三:權限不足只在某些 part 發生
AWS國際帳號服務 例如 bucket policy 有條件限制(依路徑、依標籤、依加密方式),有些 part 可能會嘗試使用不同頭部(如 SSE-KMS 的 KeyId),導致只有某一段失敗。續傳時你也會一直撞到同樣錯誤。
建議:在初始化時就把需要的上傳參數(StorageClass、SSE、KMS key、ACL 等)全部固定並一致,避免「前後 part 參數漂移」。
錯誤四:簽章過期導致重試失敗
如果你用 pre-signed URL 或臨時 STS,在重試時你可能重用舊簽章,導致每次都失敗。這種錯誤通常是 403 或簽章相關訊息。
建議:把「重新簽章」做成可重用的回呼流程;當偵測到簽章過期錯誤時,先刷新憑證/簽章再重試該 part。
設計重試策略:不要把所有錯誤都當作暫時性
續傳需要重試,但重試也會放大問題。關鍵是你要分辨錯誤類型。
可重試的常見情況
- 網路層錯誤(timeout、connection reset、DNS error)。
- 服務端暫時性錯誤(某些 5xx)。
- 節流/限流(可讀取重試建議的錯誤回應時尤需尊重 Retry-After)。
不建議重試的常見情況
- 明確的權限錯誤(403 且訊息顯示缺少權限)。
- 參數錯誤(例如 part size 或頭部與 CreateMultipartUpload 不一致)。
- 檔案內容變更(你自己的比對顯示非同一檔案)。
一旦判定不可重試,就應該停止並回報,而不是一直拖著重試造成更長的卡住。
併發上傳與續傳:如何避免「同一個 part 被重複上傳」
當你採用併發上傳(同時多個 part),續傳更容易遇到競態問題:兩個執行緒可能同時嘗試上傳同一個 PartNumber,造成不必要的重複請求,甚至讓狀態記錄混亂。
建議作法:
- 以 PartNumber 作為鎖粒度。狀態更新採用原子化或一致性機制(例如單一排程器負責分配 part)。
- 成功上傳後才把 PartNumber 標記為完成;失敗則回到待重試佇列。
- 續傳查詢缺失 part 後再重建併發佇列,確保同一 part 只會被分配一次。
校驗與確認:怎麼確定結果是真的對的
AWS國際帳號服務 完成合併後,你通常還需要確定上傳結果沒有問題。實務上可以做幾種層級:
AWS國際帳號服務 1. 以 S3 回傳結果為主要依據
CompleteMultipartUpload 成功通常代表 S3 已接受並完成合併。這是最低保障。
2. 進行大小一致性檢查
上傳完成後可用 HeadObject 檢查 Content-Length 是否等於原始檔案大小。
3. 需要更嚴格時做雜湊校驗
對「整體檔案雜湊」或「區塊雜湊」做比對,可以更有效偵測上傳過程中內容不一致的情況。注意:S3 的 ETag 在 multipart 情境下不等同於簡單 MD5,因此你要用合適的策略。
這一塊視你的可靠性要求而定:若你上傳的內容是可容忍的備份,可先做大小檢查;若是必須確保一致性(例如資料管線輸入),就引入雜湊。
一套可落地的狀態模型:你可以直接照做
下面是一個你在專案中很容易落地的狀態模型(用文字描述,實際可用 JSON 存檔或資料庫存儲)。
- uploadKey:你自行定義的鍵,例如 bucket + objectKey + 檔案特徵。
- fileFingerprint:檔案大小 + 最後修改時間 + 可選雜湊。
- uploadId:S3 回傳。
- partSize:本次切片大小。
- parts:以 PartNumber 為索引的 map;內容包含 status、etag、uploadTime。
- status:running / completed / aborted / failed。
- lastError:最後一次失敗的錯誤碼與訊息(便於排障)。
只要你維護好這份狀態,續傳就會變得可預期:你不再猜測到底成功了哪些 part,而是以 S3 與本地狀態共同決定。
排障流程:遇到問題時怎麼快速定位
當續傳還是失敗,不要先改一堆參數。依序做以下檢查,你會更快找到根因。
第一步:確認 UploadId 是否正確且仍有效
若你的狀態檔遺失或被覆蓋,可能導致你拿到錯的 UploadId。此時查詢 part 會直接失敗,或上傳邏輯根本對不上。
AWS國際帳號服務 第二步:查詢已上傳的 part 清單是否符合預期
若 S3 顯示該 UploadId 下已存在部分 part,但你本地狀態顯示不存在,通常是你的狀態保存流程有缺漏。
第三步:檢查續傳時的 part size 與切片邏輯
重啟後如果你的程式版本不同、預設 part size 變了,就可能出現「缺失清單計算錯誤」。把 part size 當成必須持久化的配置。
第四步:看錯誤碼屬於哪一類
- 403 / AccessDenied:先處理權限或簽章。
- InvalidPart / InvalidRequest:多半是參數或切片規則不一致。
- Network / Timeout:用重試與退避,必要時降低併發。
第五步:檢查 SSE、KMS 與上傳參數一致性
若你使用 SSE-KMS,KMS key 或授權可能在不同環境不同。續傳時要確保 Create/Upload/Complete 全程一致。
常見最佳實踐清單:把可靠性做成習慣
- 每個 part 上傳成功後立刻持久化:不要等整個上傳完成才寫檔。
- 保存 UploadId:至少保存到本地可持久化的儲存或外部資料庫。
- 在續傳時以 S3 查詢為準:本地可能失真,S3 是最終狀態。
- 把切片規則固定並持久化:part size、對齊規則都要一致。
- AWS國際帳號服務 區分錯誤類型:可重試與不可重試分流。
- 併發要節制:大量併發容易觸發限流或放大網路抖動。
- 設定超時與退避:避免無限卡住。
- 失敗後有清理策略:長時間失敗可 Abort,避免未完成 multipart upload 堆積。
結語:真正的續傳,是把不確定性變成流程
很多人把「續傳」想得太神秘,最後還是做成「重來」。但在 S3 的 multipart upload 体系裡,續傳其實是可工程化的:UploadId 給你持續性,PartNumber 給你可追蹤性,查詢已存在 part 給你可恢復性。你只要把狀態保存與錯誤處理做好,失敗就不再是災難,而是一次可控的中斷。
當你的上傳流程能夠:斷線照樣續、重啟照樣接、權限/憑證過期也能刷新、切片策略一致、錯誤分類清楚——那麼「大檔案上傳」會變得很可靠。你投入的時間和流量,不再因為一次意外而被重置。


