Docker 部署 PostgreSQL 16 + pg_partman + pg_cron 实战
背景
在业务系统中,日志表、邮件发送记录、MQ 消费记录、审计记录等数据增长速度非常快。
例如:
email_log
task_log
mq_log
audit_log当数据达到千万级甚至亿级后,单表查询和维护成本会明显增加。
PostgreSQL 原生提供了 Partition(分区表)功能,而 pg_partman 可以帮助我们自动管理分区生命周期。
本文记录使用 Docker 部署:
PostgreSQL 16
+
pg_partman
+
pg_cron实现:
- 自动创建未来分区
- 自动删除历史分区
- 自动维护分区
什么是 pg_partman
pg_partman 是 PostgreSQL 生态中最成熟的分区管理扩展。
它可以自动完成:
创建未来分区
删除过期分区
维护分区状态例如按月分区:
email_log
├── email_log_p2026_06
├── email_log_p2026_07
├── email_log_p2026_08
├── email_log_p2026_09即使业务代码只执行:
INSERT INTO email_log ...也无需关心具体写入哪个分区。
项目结构
PostgreSQL/
├── docker-compose.yml
└── DockerfileDockerfile
基于 PostgreSQL 16 安装:
FROM postgres:16
RUN apt-get update && \
apt-get install -y \
postgresql-16-partman \
postgresql-16-cron && \
rm -rf /var/lib/apt/lists/*docker-compose.yml
version: '3.8'
services:
db:
build: .
container_name: postgres_db
environment:
POSTGRES_USER: root
POSTGRES_PASSWORD: root
POSTGRES_DB: database
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
command:
- postgres
- -c
- shared_preload_libraries=pg_cron
- -c
- cron.database_name=database
volumes:
postgres_data:启动服务
构建并启动:
docker compose up -d --build查看容器:
docker ps进入容器:
docker exec -it postgres_db bash连接数据库:
psql -U root -d database安装扩展
创建 schema:
CREATE SCHEMA partman;安装 pg_partman:
CREATE EXTENSION pg_partman SCHEMA partman;安装 pg_cron:
CREATE EXTENSION pg_cron;查看已安装扩展:
SELECT extname
FROM pg_extension;正常结果:
plpgsql
pg_cron
pg_partman创建分区父表
创建邮件日志表:
CREATE TABLE email_log (
id BIGSERIAL,
content TEXT,
created_at TIMESTAMP NOT NULL
)
PARTITION BY RANGE (created_at);注册到 pg_partman
将表交给 pg_partman 管理:
SELECT partman.create_parent(
p_parent_table := 'public.email_log',
p_control := 'created_at',
p_interval := '1 month',
p_type := 'range'
);参数说明:
p_parent_table 分区父表
p_control 分区字段
p_interval 分区间隔
p_type 分区类型本例表示:
按 created_at
按月分区
使用 PostgreSQL 原生 Range Partition配置预创建分区
设置提前创建未来 3 个分区:
UPDATE partman.part_config
SET premake = 3
WHERE parent_table = 'public.email_log';例如当前时间:
2026-06则会自动存在:
2026-06
2026-07
2026-08
2026-09手动执行维护
首次测试可以手动执行:
SELECT partman.run_maintenance();该命令负责:
创建未来分区
删除过期分区
同步配置查看分区
查看当前分区结构:
SELECT *
FROM pg_partition_tree('email_log');示例结果:
email_log
├── email_log_p2026_06
├── email_log_p2026_07
├── email_log_p2026_08
├── email_log_p2026_09测试数据插入
插入数据:
INSERT INTO email_log (
content,
created_at
)
VALUES (
'test message',
now()
);查询:
SELECT *
FROM email_log;PostgreSQL 会自动路由到对应月份分区。
业务层无需关心具体分区表名称。
配置历史数据保留
仅保留最近 12 个月:
UPDATE partman.part_config
SET retention = '12 months'
WHERE parent_table = 'public.email_log';允许自动删除:
UPDATE partman.part_config
SET retention_keep_table = false
WHERE parent_table = 'public.email_log';效果:
2025-06
2025-07
...
2026-06当进入:
2026-07时:
2025-06对应分区将自动删除。
配置自动维护任务
利用 pg_cron 定时执行维护。
创建任务:
SELECT cron.schedule(
'partman-maintenance',
'*/5 * * * *',
$$SELECT partman.run_maintenance();$$
);表示:
每 5 分钟
执行一次分区维护查看任务:
SELECT *
FROM cron.job;生产环境推荐配置
对于日志类业务:
email_log
task_log
mq_log
audit_log推荐:
PostgreSQL Native Partition
+
pg_partman
+
pg_cron参数建议:
premake = 3
retention = 12 months架构如下:
应用程序 ↓ INSERT ↓ PostgreSQL ↓ 自动路由 ↓ email_log_p2026_06 email_log_p2026_07 email_log_p2026_08
应用层完全感知不到分区的存在。
总结
pg_partman 解决了 PostgreSQL 分区表最麻烦的问题:
自动创建分区
自动删除分区
自动维护分区pg_partman 采用“巡检补缺”模式,而不是“定时创建”模式。 结合 pg_cron 后,可以实现完全自动化管理。
对于:
- 邮件日志
- MQ 消费记录
- API 访问日志
- 审计日志
- 任务执行记录
等典型时序数据场景,是 PostgreSQL 非常成熟且稳定的解决方案。