← 中文资源

简体中文版本

清理过期的幂等键

按天分区幂等记录、定时删除旧分区,并把保留窗口设置为长于客户端最大重试周期。

阅读英文原文

概述

幂等表以追加写入为主,并按精确键读取。用 DELETE 删除数百万行会产生膨胀、更新所有索引并长时间持锁;删除旧分区只是元数据操作,能立即释放空间且不影响当前分区。按天做范围分区同时匹配访问模式和保留策略。

步骤

  1. 将表重建为按 created_at 范围分区。PostgreSQL 要求分区列出现在唯一约束中,因此主键改为 (key, created_at):
CREATE TABLE idempotency_keys (
  key text NOT NULL,
  request_hash text NOT NULL,
  response_status int,
  response_body jsonb,
  created_at timestamptz NOT NULL DEFAULT now(),
  PRIMARY KEY (key, created_at)
) PARTITION BY RANGE (created_at);
  1. 编写维护函数,预先创建明天的分区,并删除 7 天前的分区。
  2. 用 pg_cron 在每天 02:15 执行:SELECT cron.schedule('idem-maintenance', '15 2 * * *', 'SELECT maintain_idempotency_partitions();');。
  3. 查询保留窗口之外是否还有数据,并确认点查仍走索引。

验证

预期 SELECT count(*) FROM idempotency_keys WHERE created_at < now() - interval '7 days'; 返回 0,EXPLAIN 对按 key 的查询显示索引扫描。检查 cron.job 中存在任务,且第二天能看到新建的分区。

注意事项

  • 保留时间必须长于所有客户端的最大重试周期,移动端可能离线数天后重试。
  • 删除分区不可逆,保留决策应写入运维手册,避免被随意缩短。
  • 分区必须在插入前存在,遗漏分区会导致午夜写入失败,应对维护任务连续失败告警。
  • 删除分区需要短暂的 AccessExclusiveLock,建议设置 lock_timeout 并在低峰执行;其他表不要外键引用分区表。