- PostgreSQL 18 puede clonar bases de datos casi al instante al combinar la estrategia de copia de archivos (FILE_COPY) con la función de clonación del sistema de archivos
- Con la nueva configuración
file_copy_method = clone, es posible aprovechar la función de clonación de sistemas de archivos modernos (FICLONE) como XFS, ZFS y APFS
- Según los benchmarks, al clonar una base de datos de 6 GB, el método tradicional WAL_LOG tarda unos 67 segundos, mientras que el método con clonación lo reduce a alrededor de 0.2 segundos
- La base de datos clonada comparte inicialmente los mismos bloques físicos, pero se separa mediante copy-on-write cuando hay operaciones de escritura
- Sin embargo, solo se puede clonar cuando no hay conexiones activas y existe la restricción de que solo funciona dentro de un mismo sistema de archivos
Estructura de clonación basada en plantillas en PostgreSQL
- En PostgreSQL, al ejecutar el comando
CREATE DATABASE dbname, internamente se clona la base de datos template1 para crear una nueva base de datos
- Esto equivale al comportamiento de
CREATE DATABASE dbname TEMPLATE template1
- En lugar de
template1, se puede especificar otra base de datos, por lo que es posible clonar usando plantillas personalizadas
- En PostgreSQL 18, este sistema de plantillas se amplió a una estructura capaz de clonación instantánea
CREATE DATABASE ... STRATEGY
- Desde PostgreSQL 15 se introdujo el parámetro
CREATE DATABASE ... STRATEGY, que permite elegir el método de clonación
- El valor predeterminado es
WAL_LOG, que realiza una clonación por bloques mediante Write-Ahead Log
- Este método reduce la carga de I/O y mejora el soporte de concurrencia, pero es más lento al clonar grandes volúmenes de datos
- Si se especifica
STRATEGY=FILE_COPY, se puede volver al método tradicional de copia de archivos y, en PostgreSQL 18, sobre esa base se añadió una nueva opción de clonación
FILE_COPY y file_copy_method
- La configuración
file_copy_method de PostgreSQL 18 controla el método de copia de archivos a nivel del sistema operativo
- El valor predeterminado es
copy, que lee todos los bytes y los escribe en una nueva ubicación
- Si se cambia a
clone, se usa la función de clonación del sistema de archivos (FICLONE) para lograr clonación instantánea sin consumo adicional de espacio
- Sistemas de archivos compatibles: XFS, ZFS, APFS, FreeBSD ZFS
- Procedimiento de configuración
- Configurar el clúster de PostgreSQL sobre uno de esos sistemas de archivos
- Establecer
file_copy_method = clone y recargar la configuración
Resultados del benchmark
- Tras crear una base de datos de prueba de unos 6 GB (
source_db), se compararon dos métodos
- Método
WAL_LOG: 67,000 ms (unos 67 segundos)
- Método
FILE_COPY + clone: 212 ms
- Con el mismo volumen de datos, se confirmó una mejora de velocidad de más de 300 veces
- La base de datos clonada (
fast_clone) casi no usa espacio adicional en disco
Cómo funciona internamente la data clonada
- Al usar
file_copy_method = clone, solo se clona el metadato del sistema de archivos, por lo que ambas bases de datos comparten los mismos bloques físicos
- El tamaño de la base de datos que reporta PostgreSQL sigue siendo el tamaño lógico (unos 6 GB)
- Cuando se producen escrituras, entra en acción copy-on-write (COW) y se separan las páginas correspondientes
- Páginas que contienen filas modificadas
- Páginas donde se escriben nuevas tuplas
- Páginas de índices, FSM y visibility map, entre otras
- Incluso al ejecutar
VACUUM se producen separaciones adicionales de páginas
Verificación de bloques compartidos en XFS
- Con el comando
filefrag -v se puede comprobar si dos bases de datos comparten bloques físicos
- En el estado inicial, todos los extents aparecen marcados como
shared
- Si se actualizan algunas filas, los primeros 40 bloques (unos 160 KB) se separan y pasan a direcciones físicas diferentes
- Los demás extents siguen compartidos
Precauciones y restricciones
- No debe haber conexiones activas a la base de datos origen al momento de clonar
- Esta es una restricción de PostgreSQL, no un problema del sistema de archivos
- En entornos de producción, lo habitual es usar una base de datos de plantilla separada
- Solo se puede clonar dentro de un mismo sistema de archivos
- Si varios tablespaces están en distintos puntos de montaje, se usará copia normal en su lugar
- En servicios administrados en la nube (AWS RDS, Google Cloud SQL, etc.) no se puede usar esta función porque no hay acceso al sistema de archivos
- En entornos con VM propia o bare metal sí es posible tener control total
Conclusión
- La función
file_copy_method = clone de PostgreSQL 18 aprovecha directamente la clonación a nivel del sistema operativo para
reducir drásticamente el tiempo de clonación de grandes bases de datos
- Hace posible implementar flujos de trabajo con bases de datos que se clonan y reinician al instante en entornos de prueba, desarrollo y aprendizaje
- Aun así, se necesita un diseño operativo que tenga en cuenta la restricción de conexiones activas y la necesidad de un solo sistema de archivos
1 comentarios
Comentarios en Hacker News
Para quienes no pueden esperar o necesitan aislamiento completo de instancias en PG18, hice Velo, una herramienta que crea ramas al instante usando snapshots de ZFS
Funciona con cualquier versión de PostgreSQL y cada rama tiene su propio contenedor y puerto
Puede crearse en unos 2 a 5 segundos para una DB de 100 GB
La diferencia frente al enfoque de PG18 es que no comparte una sola instancia, sino que ofrece aislamiento total del servidor
Enlace a GitHub
Hace tiempo, cuando mi empresa migró a RDS, armamos internamente un sistema parecido
Como durante las migraciones a producción surgían problemas con frecuencia, automatizamos los siguientes pasos para evitarlos
Gracias a este proceso pudimos detectar muchos bugs específicos de producción que no aparecían ni en local ni en CI
Después lo automatizamos con un simple script de Ruby, y escuché que todavía lo siguen usando
Recién me entero de que la estrategia de clonado desde plantilla es configurable
Yo usé Neon para crear entornos de integración en tiempo real, y en mi proyecto de Golang pgtestdb se crea una DB de Postgres con todas las migraciones de esquema aplicadas para cada prueba
Hace tiempo vi en una startup que usaban btrfs para crear DBs de staging al instante, y me parece interesante cómo reaparece la misma idea
Este tipo de clonado rápido y pruebas es una gran ventaja de Postgres y Sqlite, y ojalá también existiera en Clickhouse o MySQL
Últimamente PostgreSQL parece haberse convertido en una DB todoterreno que cubre casi todos los usos de SQL
Y además es gratis
Me pregunto si todavía hay alguna razón real para usar otra DB SQL
Clickhouse es muchísimo más rápido para analítica, y DBs como Cassandra son mejores para cargas centradas en escritura
En otras palabras, cada DB sigue teniendo sus fortalezas
Cuando los datos crecen, aparecen degradación de rendimiento y problemas de migración
En mi caso, el rendimiento del particionado nativo era malo y tuve que implementar particiones personalizadas por mi cuenta
Esa decisión trae varios efectos negativos cuando la carga aumenta
Es un tema que también se trató en el blog de Uber
Aun así, en la nube sigo confiando más en Postgres
Por eso, en despliegues grandes de OLTP, MySQL sigue usándose mucho (por ejemplo, YouTube y Uber)
Si se usan estructuras de datos inmutables (HAMT), se puede construir una DB con clonación instantánea sin importar el tipo de sistema de archivos
Dijeron que era teoría, pero yo realmente lo implementé
No entiendo por qué no hay más DBs basadas en HAMT
Enlace a la documentación relacionada
No sabía que en Postgres v15 WAL_LOG pasó a ser el valor por defecto
En entornos de pruebas paralelas en CI, tiene más sentido volver a la estrategia FILE_COPY
Abrí un issue relacionado en mi proyecto anterior integresql
Hace tiempo hice una herramienta GUI simple pgtt para probar apps basadas en Postgres en local
Simplifica mucho la configuración del entorno de desarrollo
Parece que ayudaría con el trabajo repetitivo de las migraciones SQL
Leí otros artículos del blog y en general son excelentes
En particular, fue la primera vez que supe de los tipos range de Postgres
Me pregunto si MariaDB también tiene algo así
Me preocupa que sea lento devolver la DB a su estado inicial en cada prueba
Como usamos MariaDB en producción, es difícil cambiar de DB
Aunque la opción de Postgres sí parece mejor
Es un método bastante eficiente
AWS también ofrece una función similar
Documentación de clones de Aurora
Para pruebas de integración no es realista