进阶阅读约 1 分钟

DynamoDB TTL

生存时间(TTL)让 DynamoDB 在你存储在项上的某个时间戳过去之后自动删除该项。你指定一个 持有 Unix-epoch 过期时间的属性,DynamoDB 就会在后台清收已过期的项 —— 无需清收作业,也没有 额外成本。

在审计日志的场景中,每个租户都有一份保留策略:保留事件 90 天、或 1 年、或对那些合规要求严格 的租户保留 7 年。TTL 就是你在无需自行运行删除扫描的情况下落实这一点的方式。

DynamoDB TTL 是如何工作的?

DynamoDB TTL 会在你存储在指定属性中的 Unix-epoch(秒)时间戳过去后自动删除项。你在表上启用 TTL,指定过期属性的名称,DynamoDB 便会在后台清收已过期的项 —— 通常在 48 小时内完成,且不消耗写入容量。已过期的项在被物理删除之前仍可被读取。

  • TTL 是一个持有 Unix-epoch(秒)时间戳的属性。 当那个时间过去时,该项就符合被删除的条件。
  • 删除是后台的、尽力而为的 —— 通常在过期后一两天内,而非精确到秒。AWS 的目标是 48 小时之内。
  • TTL 删除是免费的 —— 它们不消耗写入容量。
  • 已过期但尚未删除的项仍会出现在读取中,所以如果你需要立刻把它们隐藏,请对过期属性做筛选。

问题所在:自己让旧数据过期代价高昂

没有 TTL,落实“删除超过 90 天的事件”意味着运行你自己的清收器:按计划扫描(或查询)旧项, 并对每一个执行 DeleteItem。那次扫描会烧掉读取容量,那些删除会烧掉写入容量,而调度、失败 和重试都得你自己承担。

对于一个高吞吐的审计日志,这只是为了把数据扔掉而背上的一笔持续且不断增长的税。TTL 把整件 工作搬进了 DynamoDB,而且免费。

TTL 如何工作

你在一张表上启用 TTL,并告诉它哪个属性持有过期时间。据 AWS 公告所述, 你“指定一个包含 Unix epoch 过期时间戳的项属性,DynamoDB 就会在后台自动处理删除 —— 而不影响 表性能”。

有两个属性对正确性很重要:

  • 它是尽力而为的,而非精确的。 DynamoDB 在后台扫描并删除已过期的项;AWS 的目标是在过期 后 48 小时内删除。一个项在其时间戳处即符合条件,但可能会短暂滞留。
  • 已过期的项在被清收之前仍可读取。 一次 Query 可能返回一个 TTL 已过但尚未被删除的项 —— 所以如果“过期 = 立即不可见”是一项硬性要求,请对过期属性加上一个 FilterExpression

而且 TTL 删除不消耗写入容量,这正是它严格地比自行运行的清收器更便宜的原因。

一个实战示例:按租户保留

每个审计事件都带有一个 expiresAt 属性,在事件被写入时设置 —— 当前时间 + 该租户的保留窗口, 以 epoch 秒为单位:

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

expiresAt 作为 TTL 属性启用 TTL。当 acme 那条 90 天的事件越过 1758873600 时, DynamoDB 会在大约两天内自行将其删除。合规租户的事件带有一个远在未来的 expiresAt,所以它们 会留存下来 —— 同一张表、同一套机制,每个项却有不同的保留期。

写入侧只是在你创建事件时多加一个数字。你可以在 DynamoDB 表达式构建器中拼出 SET expiresAt = :ttl 子句 并验证带类型的 :ttl 值。

要立刻把一个已过期但未清收的事件从读取中隐藏,请向查询的 FilterExpression 加上 expiresAt > :now —— 不过请记住,筛选并不会降低读取成本(Query 与 Scan 对比)。

在 DynoTable 中操作

经典的 TTL 缺陷是一个错误的 expiresAt:以毫秒而非秒存储,或者存成 ISO 字符串,于是该项 要么永不过期,要么立刻消失。捕捉它的唯一办法,就是去查看实际存储的值及其类型。

DynoTable 会连同 DynamoDB 类型一起展示每个项的属性,因此你可以确认 expiresAt 是一个以 epoch 为单位的 Number —— 而不是 String、不是毫秒 —— 然后再放心地把真实的保留交给 TTL。

在 DynoTable 中验证某个审计事件上的 expiresAt 属性是一个以 Unix-epoch 秒为单位的 Number —— 这是 TTL 唯一会据以行动的值。
在 DynoTable 中验证某个审计事件上的 expiresAt 属性是一个以 Unix-epoch 秒为单位的 Number —— 这是 TTL 唯一会据以行动的值。

坑与后续步骤

  • Epoch 秒,且为 Number。 这是最常见的 TTL 错误。一个毫秒值会把过期时间推到约 5 万年以后; 一个 ISO 字符串则会被完全忽略。请核实类型和单位。
  • 不要依赖删除时机。 从过期到删除之间可能过去多达约 48 小时。如果“一过期就消失”很重要, 请在读取中对该属性做筛选;不要假设那一行已经物理消失了。
  • TTL 删除会出现在 Streams 中。 一次 TTL 删除会发出一条被标记为系统生成的 stream 记录 —— 这是在过期事件消失之前把它们归档到 S3 的标准钩子。参见 DynamoDB Streams
  • TTL 删除同样会作用于 GSI。 移除一个项也会把它从它所在的任何二级索引中移除 —— 这是预期 内的清理,但如果某个索引驱动着一个计数,那就值得知道。

TTL 廉价地处理了一个事件生命的终点。下一个问题是,最初为这些写入你要付什么 —— 按需与预置容量对比

下载 DynoTable,检查你各项的属性类型,在你开启 TTL 之前确认你的 TTL 属性是一个 Unix-epoch Number。

更新于