中階閱讀時間 1 分鐘

DynamoDB TTL 完整指南:讓項目自動過期

存留時間(Time to Live,TTL)讓 DynamoDB 在你存在項目上的一個時間戳 過去之後自動刪除它。你指定一個持有 Unix-epoch 到期時間的屬性,然後 DynamoDB 就在背景收割到期的項目 — 沒有收割工作、沒有額外成本。

在那個稽核日誌的情境裡,每個租戶都有一個保留政策:事件保留 90 天、或 1 年、或對合規要求高的租戶保留 7 年。TTL 就是你不必自己跑一趟 刪除掃描就能執行那份政策的方法。

DynamoDB 的 TTL 是怎麼運作的?

DynamoDB TTL 會在你存在一個指定屬性中的 Unix-epoch(秒)時間戳過去之後,自動刪除項目。你在表格上啟用 TTL、指定那個到期屬性,然後 DynamoDB 就在背景收割到期的項目 — 通常在幾天之內,且沒有寫入容量成本。到期的項目在被實體刪除之前仍然可讀。

  • TTL 是一個持有 Unix-epoch(秒)時間戳的屬性。 當那個時間 過去,這個項目就符合刪除的資格。
  • 刪除是背景且盡力而為的 — 通常在到期後幾天之內,而不是 精確的那一秒。
  • TTL 刪除是免費的 — 它們不消耗寫入容量,不過在一個 global table 上,被複寫的刪除在每一個其他複本區域都算一次寫入。
  • 已到期但尚未刪除的項目仍會出現在讀取中,所以如果你需要 立即隱藏它們,就在那個到期屬性上做篩選。

問題所在:自己讓舊資料到期很貴

沒有 TTL,執行「丟棄超過 90 天的事件」意味著跑你自己的 收割器:定時掃描(或查詢)舊項目,並對每一個 DeleteItem。 那個掃描燒讀取容量、那些刪除燒寫入容量,而排程、失敗和 重試都歸你負責。

對一個高流量的稽核日誌而言,那是一筆持續、不斷增長、只為了 丟掉資料的稅。TTL 把整份工作移進 DynamoDB,免費。

TTL 如何運作

你在一個表格上啟用 TTL,並告訴它哪個屬性持有到期時間。按照 AWS 的公告, 你指定一個持有 Unix-epoch 到期時間戳的項目屬性,而 DynamoDB 就在背景自動處理刪除,不影響表格 效能。

有兩個屬性對正確性很重要:

  • 它是盡力而為,不是精確的。 DynamoDB 在背景掃描到期的項目並 刪除它們;刪除通常發生在到期後幾天之內。一個項目在它的時間戳 就_符合資格_,但可能短暫地滯留。
  • 到期的項目在被收割之前仍然可讀。 一個 Query 可以回傳一個 TTL 已過但尚未被刪除的項目 — 所以如果「到期=立即不可見」 是一個硬性要求,就在那個到期屬性上加一個 FilterExpression

而且 TTL 刪除不消耗寫入容量,這正是讓它嚴格比一個 自己跑的收割器更便宜的原因。

一個實作範例:每租戶的保留

每一個稽核事件在被寫入時都帶著一個設定好的 expiresAt 屬性 — 現在 + 該租戶的保留窗口,以 epoch 秒計:

PKSKactionexpiresAtnote
TENANT#acmeEVENT#2026-03-26T…#a0login.success178225920090-day tenant: eligible now
TENANT#acmeEVENT#2026-06-24T…#a1invoice.export1790035200still inside window
TENANT#globex EVENT#2026-06-24T…#b9role.granted20031840007-year compliance tenant

TTL 以 expiresAt 作為 TTL 屬性啟用。當 acme 的 90 天事件 越過 1782259200,DynamoDB 就在大約兩天之內自行刪除它。那個 合規租戶的事件帶著一個遠在未來的 expiresAt,所以它們存活下來 — 同一個 表格、同一套機制、每個項目不同的保留。

寫入端只是在你建立事件時多加一個數字。你可以在 DynamoDB Expression Builder 中組合那個 SET expiresAt = :ttl 子句並驗證那個帶型別的 :ttl 值。

要立即從一次讀取中隱藏一個已到期但未收割的事件,就在查詢的 FilterExpression 上加 expiresAt > :now — 不過記得一個篩選 並不會降低讀取成本(query 與 scan)。

在 DynoTable 中操作

經典的 TTL bug 是一個錯的 expiresAt:以毫秒而非 秒儲存,或以一個 ISO 字串儲存,於是那個項目要嘛永不到期、要嘛 立即消失。抓到它的唯一方法,是去看那個實際儲存的值和 它的型別。

DynoTable 顯示每個項目的屬性連同它們的 DynamoDB 型別,所以你可以 確認 expiresAt 是一個以 epoch _秒_計的 Number — 不是一個 String、不是 毫秒 — 然後才把真正的保留託付給 TTL。

在 DynoTable 中驗證一個稽核事件上的 expiresAt 屬性是一個以 Unix-epoch 秒計的 Number,也就是 TTL 唯一會據以動作的值。
在 DynoTable 中驗證一個稽核事件上的 expiresAt 屬性是一個以 Unix-epoch 秒計的 Number,也就是 TTL 唯一會據以動作的值。

陷阱與後續步驟

  • 是 epoch 秒,作為一個 Number。 這是最常見的 TTL 錯誤。一個 毫秒值會把到期推到約 50,000 年後;一個 ISO 字串會被完全 忽略。驗證型別和單位。把值貼進 TTL 轉換器——它會自動偵測秒 與毫秒,而它標出的正是這個錯誤。
  • 別依賴刪除的時機。 到期與刪除之間可能過幾天。如果「一 到期就消失」很重要,就在讀取中對那個屬性篩選;別假設那一列 已經實體消失了。
  • TTL 刪除會出現在 Streams 中。 一次 TTL 刪除會發出一筆被標記為 系統產生的串流記錄 — 那是在到期事件消失之前把它們歸檔到 S3 的標準掛鉤。見 DynamoDB Streams
  • TTL 刪除也會打到 移除一個項目也會把它從它 曾在的任何次要索引裡移除 — 那是預期中的清理,但如果一個索引 驅動了某個計數,這件事就值得知道。

TTL 便宜地處理一個事件生命的終點。下一個問題是你一開始為那些 寫入付了什麼 — On-Demand 與 Provisioned 容量

下載 DynoTable,在你開啟 TTL 之前,先檢視你項目的屬性 型別,並確認你的 TTL 屬性是一個 Unix-epoch Number。

已更新