数据库运维
控制面把全部状态保存在一个 PostgreSQL 数据库中,可以是随附的 PostgreSQL 实例,也可以是外部数据库。本文面向该数据库的运维人员,说明哪些数据会增长、需要规划多少磁盘、控制面会自动完成哪些维护,以及需要关注哪些指标。
数据库中大部分是配置数据,体量很小。少数几张表会随流量或时间增长,控制面会定期删除其中的旧数据,无需你执行例行维护任务。
哪些数据会增长,如何受限
控制面按计划分小批删除旧数据,大多每天一次,首次运行在 cp-api 启动时。删除组织时,控制面还会在后台移除该组织的用量记录、审计事件和通知投递记录。
| 数据 | 表 | 保留期 |
|---|---|---|
| 用量记录,即 Request Logs 和 Usage 背后的数据 | dpmgr_usage_events | 每个组织的用量保留窗口:默认 30 天,可在 1 到 365 天之间调整。参见数据保留。 |
| 审计事件 | audit_events | audit.retention_days,默认 730 天。0 表示永久保留。参见审计日志保留。 |
| 通知投递记录 | notification_deliveries | 90 天。 |
| 预算告警记录,用于避免同一预算周期内重复触发告警 | budget_alert_firings | 所属预算周期开始后 90 天。 |
| 网关上报的配置拒绝记录及其历史 | dpmgr_rejected_resources、dpmgr_rejected_resources_audit | 网关最后一次上报该拒绝后 7 天;历史保留 90 天。 |
| 网关实例记录 | dp_nodes | 网关 实例停止发送心跳后约 1 小时。 |
| 用量上报回执,用于丢弃网关重复发送的上报 | dpmgr_usage_batches | 24 小时。 |
| 控制台登录会话 | auth.console_session | 过期后 1 天。 |
| 配置修订版本 | kine | 被取代的修订版本每隔几分钟压缩一次。 |
只有用量记录的体量与请求量成正比,因此它占据数据库的绝大部分。如需超过组织保留窗口的用量历史,请通过可观测性导出器把用量事件发送到外部存储。
规划容量
按各组织使用的用量保留期规划数据库容量,默认 30 天,最长 365 天。根据在测试部署上的实测估算,每条用量记录连同索引约占 750 字节。控制面为每次请求尝试写入一条记录,因此发生重试或回退到其他目标的请求会写入多条记录。
存储 ≈ 750 字节 × 每日请求数 × 保留天数,再加上余量
例如,每天处理 1,000,000 个请求、使用默认 30 天保留期的部署大约存储 750 字节 × 1,000,000 × 30 ≈ 23 GB 用量记录。为它们规划约 35 GB,可为重试、两次清理之间的膨胀和流量增长留出空间。再加上审 计日志、PostgreSQL 预写日志(WAL)以及回收磁盘空间所需的空闲空间,并在运行几周后用监控查询对照实际表大小校准估算。
例行维护自动完成
PostgreSQL autovacuum 会回收已删除行占用的空间,供新行复用。由于控制面每天删除旧数据,大表会稳定在某个大小,而不会无限增长。
PostgreSQL 默认的 autovacuum 设置要等表中五分之一的数据发生变化后才触发,对于数千万行的表来说太迟了。控制面在启动时为其大表设置以下表级参数:
autovacuum_vacuum_scale_factor = 0.02
autovacuum_vacuum_insert_scale_factor = 0.02
autovacuum_analyze_scale_factor = 0.01
请勿手动修改这三个参数,控制面会在下次启动时将其恢复。你自行添加的其他表级参数会保持不变。如需查看哪些表带有这些参数,请运行:
SELECT n.nspname AS schema, c.relname AS table_name, c.reloptions
FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.reloptions IS NOT NULL
ORDER BY 1, 2;
请保持实例级 autovacuum 开启(autovacuum = on,即 PostgreSQL 默认值),也不要为这些表关闭 autovacuum。autovacuum 关闭时,表级设置不起作用。
回收磁盘空间
autovacuum 让表内空间可以复用,但不会把空间归还给操作系统。一次性大批量删除后,表文件会保持在峰值大小。例如删除一个大型组织、缩短某个组织的用量保留窗口,或从无限期保留审计事件的版本升级后执行的首次清理。
新数据写入时会复用这些空间,因此只有在必须缩小磁盘占用时才需要回收。稳定运行时通常不需要。最可能需要回收的表是 dpmgr_usage_events、audit_events 和配置存储表 kine。
以下两种方法都会重写整张表,需要大致等于该表当前大小(含索引)的空闲磁盘空间。 请先完成备份。
pg_repack在线重写表,只在开始和结束时短暂持有排他锁。如果你的数据库平台提供该扩展(例如 Amazon RDS),可以使用它。控制面本身不需要也不会安装任何扩展,是否安装由你的数据库团队决定。VACUUM FULL是内置命令,但在完成前会锁住整张表,阻塞读写。请在维护窗口内逐表执行,例如VACUUM (FULL, ANALYZE) dpmgr_usage_events;。在dpmgr_usage_events上执行期间,Request Logs 和 Usage 无法加载,新的用量记录也无法写入。在kine上执行期间,配置变更无法下发到网关。
监控数据库
以下查询均为只读查询。请以控制面的数据库角色,或有权访问统计视图的监控角色运行。
最大的表
SELECT schemaname, relname,
pg_size_pretty(pg_total_relation_size(relid)) AS total_size
FROM pg_statio_user_tables
ORDER BY pg_total_relation_size(relid) DESC
LIMIT 10;
dpmgr_usage_events 通常是最大的表。请将其大小与你的容量估算对照。如果某张表在超过其保留期之后仍持续增长,说明删除或 vacuum 没有 跟上。
死元组与 autovacuum 活动
SELECT schemaname, relname, n_live_tup, n_dead_tup,
round(100.0 * n_dead_tup / nullif(n_live_tup + n_dead_tup, 0), 1) AS dead_pct,
last_autovacuum, last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT 10;
每日清理后,大表上的死元组会短暂上升,autovacuum 应在数小时内清理完毕。如果某张大表的死元组比例持续高于约 10%–20%,或者表仍在写入而 last_autovacuum 已是数天前,就需要排查。常见原因是有东西让旧行保持可见,例如处于事务中却空闲的会话、运行时间很长的查询,或不活跃的复制槽:
SELECT pid, usename, state, now() - xact_start AS transaction_age, left(query, 60) AS query
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY xact_start
LIMIT 5;
SELECT slot_name, active, xmin, catalog_xmin FROM pg_replication_slots;
事务 ID 年龄
SELECT datname, age(datfrozenxid) AS xid_age
FROM pg_database
ORDER BY xid_age DESC;
当旧事务 ID 的年龄达到 autovacuum_freeze_max_age(默认 2 亿)时,PostgreSQL 会对表执行 vacuum 以冻结它们,因此几亿以内的值是正常的。如果年龄持续攀升超过约 5 亿,请用上面的查询找出阻碍 vacuum 的原因。接近 10 亿时应作为紧急情况处理:当年龄接近约 20 亿时,PostgreSQL 会停止接受写入,直到数据库完成 vacuum。