文章詳情

AWS國際帳號辦理 S3 儲存桶對象數量破千萬後條目列出(ListObjects)極慢?效能最佳化

亞馬遜雲AWS2026-08-04 14:47:52全球雲代付

先看清楚:慢的不是 S3 壞了,而是你在做全桶掃描

很多團隊第一次遇到 S3 儲存桶內物件數量破千萬後的列出變慢,直覺都會懷疑是不是 AWS 出問題了。其實大多數情況不是。真正的原因很單純:你在用 ListObjects 做一件本來就不適合它的事,也就是把整個桶當成可瞬間翻完的資料表來看。

S3 的設計重點不是提供資料庫式的即時索引查詢,而是提供大規模、低成本、高耐久的物件儲存。當物件數還少時,列出前幾頁看起來很正常;可是一旦進到百萬、千萬級別,任何需要「把全部列出來」的流程,延遲都會快速放大。因為 ListObjects 有頁數限制,每次最多只回傳固定數量的 key,應用程式若要看完整內容,就得一頁一頁翻,這個成本會隨物件數線性上升。

所以問題的核心不是「怎麼讓 ListObjects 變快一點」,而是「能不能不要靠 ListObjects 做這件事」。如果要真正改善效能,思路要從查詢方式、資料結構、鍵值命名和應用架構一起下手。

為什麼物件一多,ListObjects 就開始拖

每次只回傳一小段,總量一大自然慢

ListObjectsListObjectsV2 的回傳是分頁式的,單次最多通常是 1000 筆。這代表你要列出 1000 萬個物件,理論上至少得做一萬次請求。即使單次回應只有幾百毫秒,總耗時也會非常可觀。更麻煩的是,請求次數越多,受到網路波動、TLS 建立、SDK 重試、偶發延遲影響的機會也越高。

很多人只看到「單次 list 還不算慢」,卻忽略了總量。真正卡住的不是某一次請求,而是整個流程被頁數拖長,最後讓前端等待、批次任務延後、背景工作塞車。

如果你在列整桶,等於沒有用上前綴的優勢

S3 的 key 設計很重要。當你沒有用 prefix 限縮範圍,而是直接列整個 bucket,S3 就得回傳一大段結果給你自己篩。這種做法的問題不只是資料量大,還包括你把本該在服務端縮小的範圍,拖到客戶端處理。對一個千萬級 bucket 來說,這種做法幾乎等於把查詢成本全部攤在網路與應用層。

相反地,如果你的 key 有清楚的前綴規劃,例如依日期、租戶、環境、檔案類型切分,列出時就能直接縮小掃描面,速度會差很多。

鍵值命名不佳,會把查詢變成大海撈針

有些系統一開始只顧著上傳方便,key 直接用流水號或檔名,後來才發現需要依日期、客戶或任務編號查詢。這時候你會被迫從整桶掃過去找目標物件,ListObjects 就會變成最昂貴的工具。S3 雖然不是傳統資料庫,但它的列出效率和 key 結構高度相關。命名規劃沒做好,後面再怎麼優化都有限。

先釐清一件事:你真的需要「列出全部」嗎

大多數業務需求,其實只需要索引,不需要掃桶

AWS國際帳號辦理 很多系統說要「列出物件」,真正的需求其實不是把 S3 裡所有東西翻一遍,而是要做幾種常見操作:顯示某一頁清單、找某個時間範圍內的檔案、查某位使用者上傳的資料、統計今天新增了多少筆。這些需求看似像 list,實際上更像查詢索引。

如果需求本質是查詢,最好的做法通常不是讓前端或服務直接掃 S3,而是另外維護一份索引。可用 DynamoDB、OpenSearch、RDS,甚至是你自己產生的 manifest 檔。S3 負責存檔,索引系統負責查找。分工清楚後,效能會穩很多。

把 S3 當檔案系統,用法往往會出事

S3 可以模擬資料夾,但它本質不是 POSIX 檔案系統。很多操作習慣從本機檔案系統搬過來,例如列出某個「資料夾」底下所有內容、反覆掃描目錄找最新檔、用刪除與重建來做同步,這些在小規模時看不出問題,到了千萬級物件時就會原形畢露。真正成熟的做法,是把 S3 視為物件儲存,所有「可查找、可排序、可聚合」的需求,盡量放到專門的索引層處理。

實務上最有效的優化方向

一、改用 ListObjectsV2,並正確使用 prefix 與 continuation token

如果你還在用舊版 ListObjects,先升級到 ListObjectsV2。它的分頁與續列方式比較清楚,也更適合現代 SDK 的 paginator。重點不是「版本名稱比較新」,而是你能更穩定地接續下一頁,減少自己管理 marker 時的錯誤。

但要注意,換成 V2 並不會神奇地讓全桶掃描變快。真正有效的地方在於你要搭配 prefix 使用。只列出必要範圍,例如 2025/01/tenant-a/logs/ 這類前綴,讓請求從一開始就縮小範圍。若能再結合 delimiter,只看某層級下的 common prefixes,也能減少你看到的項目數。

二、重新設計 key 結構,先分片再存放

要讓 S3 的列出變快,最有用的手段之一就是把 key 設計成可分片、可定位、可縮小掃描面的形式。常見做法包括:

按日期分層:year=/month=/day=/。這適合日誌、報表、批次輸出。

按租戶或業務線分層:tenant-id=/。這適合多租戶系統。

按 hash 前綴打散:例如在高併發寫入時,前面加上幾位雜湊值,避免 key 過度集中在單一前綴下。

真正好的 key 結構,不只是方便存取,也要讓未來的 list 盡可能只碰到一小塊資料。很多人把 key 命名當成美觀問題,其實它直接影響查詢效率。

三、不要即時掃桶,改用索引表或清單檔

如果你需要的是「某個頁面上顯示最近 50 筆檔案」,最穩定的方式不是每次進頁面就去掃 S3,而是把上傳事件同步到索引層。做法可以很簡單:上傳完成後,把檔名、大小、時間、owner、標籤寫入 DynamoDB;前端查詢時只打索引,不直接打 S3。這樣的好處是查詢穩定、速度可控,也方便加排序、過濾和權限控制。

如果不想再引入資料庫,也可以定期產生清單檔,例如每天或每小時產生一份 manifest,列出該時段內新增的物件。查詢時先讀 manifest,再針對小範圍做補充 list。這種方式很適合批次處理與離線分析。

四、善用 S3 Inventory,而不是自己手工全桶盤點

AWS國際帳號辦理 當你需要的是「盤點整個 bucket 目前有哪些物件」時,S3 Inventory 往往比自己寫程式一直 list 更合適。它可以定期產生物件清單,讓你用批次方式查閱,不必每次都從 API 一頁一頁翻。對大桶來說,Inventory 的價值不在即時,而在穩定、可預期、成本較低。

如果你的需求是做稽核、清點、對帳、離線分析,Inventory 幾乎比即時 list 更符合場景。把全桶掃描從線上請求移到離線產物,是很常見也很有效的降本方案。

五、前端與後端都要做分頁,不要硬拉全量

很多效能問題,其實是介面設計造成的。後端一口氣吐出幾萬筆,前端再自己切頁,最後每次查詢都慢得不合理。正確做法是前後端都採用分頁。後端只回當前頁需要的資料,並保留續查資訊;前端只要求下一頁,不做全量抓取。這不只是速度問題,也會影響記憶體使用、請求失敗率與使用者體驗。

如果你有後台管理系統,最好不要提供「一次看完全部檔案」這種功能。千萬級資料本來就不適合被人用肉眼慢慢翻,應該改成搜尋、篩選、匯出、標籤、日期區間等操作模式。

AWS國際帳號辦理 進階做法:把「列出」改成「查詢事件」

從物件清單思維,轉成事件流思維

當物件數量到達千萬級後,最成熟的架構思維通常不是「去查現在有哪些檔案」,而是「從事件流知道有哪些變化」。例如檔案上傳、刪除、版本更新、狀態變更,這些都可以透過事件處理同步到下游系統。這樣一來,使用者要看的不是 S3 原始清單,而是經過整理的業務資料。

這個轉變很重要。因為一旦你把查詢依賴從 S3 轉到事件與索引,ListObjects 只會在少數管理或補償場景中出現,不再是日常主路徑,自然也不會卡住主要流程。

AWS國際帳號辦理 資料量很大時,快不是靠單次優化,而是靠少做事

在千萬級物件下,性能優化的核心不是把一次 list 從 300 毫秒壓到 150 毫秒,而是把原本要做的 1 萬次請求,變成 100 次,甚至 10 次。也就是說,真正有效的優化,往往來自架構改造,而不是參數微調。

這也是為什麼很多團隊在一開始優化 SDK 重試、連線池、併發數之後,還是覺得不夠快。因為它們只能改善局部,不能改變你在做全量掃描的本質。若不先改需求與資料組織,後面的優化都只是止痛藥。

常見誤區:做了很多,還是沒有變快

誤區一:以為提高併發就會更快

把多個 List 請求同時打出去,確實能縮短部分等待,但前提是你的掃描範圍本來就被切得夠細。若所有請求都在碰同一大範圍,結果只會把壓力轉嫁到 S3、網路與你的應用服務,甚至更容易遭遇限流與重試風暴。

誤區二:以為換成更大的實例就能解決

升級 CPU、記憶體、連線數,能讓你的程式撐更久,但不會讓 list 變成 O(1)。如果瓶頸是 API 次數太多,那擴機只是讓你花更多錢做同樣的事。這種做法在短期救火可以,長期卻不划算。

誤區三:以為 S3 強一致之後就沒有 list 問題

S3 的一致性改善,解決的是讀寫可見性的問題,不是把列出大量物件這件事變成便宜操作。即使資料完全一致,你還是要付出分頁、網路傳輸與應用處理的成本。把一致性和列出效能混為一談,容易做出錯誤判斷。

實戰建議:如果你現在就很慢,先照這個順序處理

第一步:確認是不是在列整桶

先看目前的程式是不是沒有加 prefix,或者加了卻太寬。很多慢的問題,其實只要把前綴縮小一層,延遲就會立刻下降。

第二步:把 ListObjects 改成 ListObjectsV2 並檢查分頁邏輯

確認 SDK 用法正確,能穩定續列,不會因為 marker、token 管理錯誤而重複抓取或漏抓。這是最基本的穩定性要求。

第三步:評估是否能改成索引查詢

如果這個 list 是服務核心功能,別再硬撐。直接做索引層,讓 S3 只負責儲存。這一步通常是從「能用」變成「真的可維運」的關鍵。

第四步:把全桶盤點移到離線流程

需要全量盤點就用 Inventory 或批次作業,不要把線上 API 當成盤點工具。線上請求應該服務即時需求,而不是做大掃除。

結語:ListObjects 慢,不是問題本身,而是設計在提醒你

當 S3 物件數破千萬後,ListObjects 變慢其實是一種很正常的現象。它在提醒你:現在的資料量,已經不適合再靠單純列舉來支撐日常操作。這時候最重要的不是繼續追求把 list 壓快幾十毫秒,而是重新回答一個更根本的問題——你到底想查的是什麼。

如果只是看某一小段資料,用好 prefix 與分頁就夠了;如果要做搜尋、篩選、排序,就應該上索引;如果要做全量盤點,就交給 Inventory 或離線批次。當你把需求和工具對齊,S3 才會真的好用。否則,再多優化技巧,也只是替一個不適合的設計續命。

Telegram售前客服
客服ID
@cloudcup
联系
Telegram售后客服
客服ID
@yanhuacloud
联系