由 John Doe 九月 17, 2025
你需要克隆数据库和迁移表空间吗?现在,PostgreSQL 支持更快的实现了。
特性提交日志
引入 file_copy_method 配置项。
该配置项可设置为COPY
(默认值)或CLONE
(需系统支持)。当设置为 CLONE
时,会使调用copydir()
函数的操作,目前包括 CREATE DATABASE ... STRATEGY=FILE_COPY
和ALTER DATABASE ... SET TABLESPACE = ...
,通过copy_file_range
(适用于 Linux、FreeBSD 系统)或copyfile
(适用于 MacOS 系统)进行文件复制,而非通过对文件内容执行 “读写循环” 的方式复制。
在支持写时复制(Copy-On-Write)的文件系统上,CLONE
模式能让内核有机会实现块范围共享;在其他类型的文件系统上,内核则可根据配置将复制操作下推到存储层执行。在部分系统中,通过CREATE DATABASE ... TEMPLATE=源数据库 STRATEGY=FILE_COPY
语句,结合CLONE
模式可快速克隆大型数据库。
该特性未来可扩展至其他操作系统,欢迎提交补丁贡献代码。
讨论:https://postgr.es/m/CA%2BhUKGLM%2Bt%2BSwBU-cHeMUXJCOgBxSHLGZutV5zCwY4qrCcE02w%40mail.gmail.com
特性解析
在 PostgreSQL 数据库运维中,有时需要进行数据库克隆(如基于生产库创建测试库)和表空间迁移(如将数据从机械盘迁移到 SSD)。但长期以来,PostgreSQL 默认的文件复制方式依赖用户态读写循环,先从源文件读取数据到内存,再写入目标文件,不仅存在频繁的内核态/用户态切换开销,还会占用大量 IO 资源,导致大文件复制时耗时漫长、存储开销倍增。
为解决这一痛点,PostgreSQL 社区引入了file_copy_method
配置项,新增CLONE
文件复制模式。该模式借助操作系统底层系统调用(如 Linux 的copy_file_range
、MacOS 的copyfile
),让内核直接主导文件复制,支持写时复制(Copy-On-Write, COW)机制,实现秒级克隆大文件和零额外存储占用等特性。file_copy_method
的核心是为 PostgreSQL 的文件复制操作提供两种差异化实现,适配性能和存储方面的不同需求。
复制模式 COPY:
- 实现方式:用户态读写循环:
read()
读取源文件 → 内存缓存 →write()
写入目标文件。 - 性能特点:存在内核态/用户态切换开销,IO 占用高,复制速度慢。
- 适用场景:不支持
CLONE
的老旧操作系统/文件系统,或需兼容传统复制逻辑的场景。
复制模式 CLONE:
- 实现方式:内核态系统调用:直接调用操作系统接口(Linux/FreeBSD 用
copy_file_range
,MacOS 用copyfile
)。 - 性能特点:无用户态切换,支持写时复制,IO 开销低,复制速度快。
- 适用场景:支持
CLONE
的系统(Linux 4.5+、FreeBSD 11+、MacOS 10.12+),需快速克隆大文件或节省存储的场景。
file_copy_method
并非全局生效,仅对 PostgreSQL 中依赖copydir
函数的文件复制操作产生影响,具体包括:
CREATE DATABASE ... STRATEGY=FILE_COPY
:基于模板库克隆新数据库时,使用文件直接复制策略(而非逻辑备份恢复);ALTER DATABASE ... SET TABLESPACE ...
:将数据库的默认表空间迁移到新存储(仅迁移默认表空间下的文件,非默认表空间文件不受影响)。
这两类操作是运维中文件复制开销最高的场景(往往涉及 GB 级甚至 TB 级数据),也是CLONE
模式的核心优化对象。
示例
file_copy_method
的价值在大文件复制和存储敏感场景中尤为突出。让我们来实际测试一下。
秒级克隆大数据库
生产环境有一个 100GB 的业务数据库prod_db
,需基于其创建测试库test_db
用于功能测试。若用默认COPY
模式,复制过程需读取100GB 数据并写入 100GB;若用CLONE
模式,借助copy_file_range
和支持写时复制的文件系统,可实现快速完成克隆,且不额外占用存储。
临时生效CLONE
模式(仅当前会话生效,避免影响其他操作),用FILE_COPY
策略克隆数据库:
SET file_copy_method = CLONE;
CREATE DATABASE test_db TEMPLATE prod_db
STRATEGY = FILE_COPY;
方法验证:查询pg_stat_activity
,克隆过程中会话的等待事件为COPY_FILE_COPY
,而非传统的COPY_FILE_READ
和COPY_FILE_WRITE
。
优化数据库表空间迁移
生产库prod_db
最初使用默认表空间(存储在机械盘),因查询性能不足,需将其默认表空间迁移到 SSD 上的ssd_tablespace
(已创建)。prod_db
默认表空间下有 50GB 数据,若用COPY
模式,迁移需大量IO,可能导致业务中断;用CLONE
模式可减少 IO 开销,节省迁移时间。
全局生效CLONE
模式(若需长期使用,可修改配置文件):
ALTER SYSTEM SET file_copy_method = CLONE;
SELECT pg_reload_conf();
迁移数据库默认表空间:
-- 注意:迁移前需确保无用户连接到 prod_db(可强制断开)
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE datname = 'prod_db' AND pid != pg_backend_pid();
-- 将 prod_db 的默认表空间迁移到 ssd_tablespace
ALTER DATABASE prod_db
SET TABLESPACE ssd_tablespace;
方法验证:查询pg_stat_activity
,迁移过程中会话的等待事件为COPY_FILE_COPY
,而非传统的COPY_FILE_READ
和COPY_FILE_WRITE
。
非常不错的特性。感谢社区的所有相关人员。
参考
提交日志:https://git.postgresql.org/pg/commitdiff/f78ca6f3ebbbff8c675c34b8ee61047223073866