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 秒为单位:
| PK | SK | action | expiresAt | note |
|---|---|---|---|---|
| TENANT#acme | EVENT#2026-03-26T…#a0 | login.success | 1758873600 | 90-day tenant: eligible now |
| TENANT#acme | EVENT#2026-06-24T…#a1 | invoice.export | 1766620800 | still inside window |
| TENANT#globex EVENT#2026-06-24T…#b9 | role.granted | 1798156800 | 7-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。

坑与后续步骤
- Epoch 秒,且为 Number。 这是最常见的 TTL 错误。一个毫秒值会把过期时间推到约 5 万年以后; 一个 ISO 字符串则会被完全忽略。请核实类型和单位。
- 不要依赖删除时机。 从过期到删除之间可能过去多达约 48 小时。如果“一过期就消失”很重要, 请在读取中对该属性做筛选;不要假设那一行已经物理消失了。
- TTL 删除会出现在 Streams 中。 一次 TTL 删除会发出一条被标记为系统生成的 stream 记录 —— 这是在过期事件消失之前把它们归档到 S3 的标准钩子。参见 DynamoDB Streams。
- TTL 删除同样会作用于 GSI。 移除一个项也会把它从它所在的任何二级索引中移除 —— 这是预期 内的清理,但如果某个索引驱动着一个计数,那就值得知道。
TTL 廉价地处理了一个事件生命的终点。下一个问题是,最初为这些写入你要付什么 —— 按需与预置容量对比。
下载 DynoTable,检查你各项的属性类型,在你开启 TTL 之前确认你的 TTL 属性是一个 Unix-epoch Number。


