<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: LUIS FERNANDO VILCA BARRIENTOS</title>
    <description>The latest articles on DEV Community by LUIS FERNANDO VILCA BARRIENTOS (@fernan101002).</description>
    <link>https://dev.to/fernan101002</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4160760%2F9e880f13-0274-4093-9cb7-cea7498ffb5d.jpg</url>
      <title>DEV Community: LUIS FERNANDO VILCA BARRIENTOS</title>
      <link>https://dev.to/fernan101002</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/fernan101002"/>
    <language>en</language>
    <item>
      <title>Estrategias de respaldo en PostgreSQL: lógico, físico y PITR (con un laboratorio que corre en tu navegador)</title>
      <dc:creator>LUIS FERNANDO VILCA BARRIENTOS</dc:creator>
      <pubDate>Sun, 04 Oct 2026 03:01:49 +0000</pubDate>
      <link>https://dev.to/fernan101002/estrategias-de-respaldo-en-postgresql-logico-fisico-y-pitr-con-un-laboratorio-que-corre-en-tu-boc</link>
      <guid>https://dev.to/fernan101002/estrategias-de-respaldo-en-postgresql-logico-fisico-y-pitr-con-un-laboratorio-que-corre-en-tu-boc</guid>
      <description>&lt;p&gt;&lt;strong&gt;Autor:&lt;/strong&gt; Luis Fernando Vilca Barrientos, estudiante de Ingeniería de Sistemas de la Universidad Privada de Tacna, curso Base de Datos II.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔗 &lt;strong&gt;Demo en vivo:&lt;/strong&gt; &lt;a href="https://fernan101002.github.io/backup-strategies-postgresql/" rel="noopener noreferrer"&gt;https://fernan101002.github.io/backup-strategies-postgresql/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💻 &lt;strong&gt;Repositorio público:&lt;/strong&gt; &lt;a href="https://github.com/FeRnAn101002/backup-strategies-postgresql" rel="noopener noreferrer"&gt;https://github.com/FeRnAn101002/backup-strategies-postgresql&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1. El día que cinco copias no sirvieron de nada
&lt;/h2&gt;

&lt;p&gt;El 31 de enero de 2017, un administrador de GitLab.com ejecutó por error un borrado sobre el directorio de datos del servidor PostgreSQL principal. La empresa tenía réplicas, volcados diarios con &lt;code&gt;pg_dump&lt;/code&gt; hacia Amazon S3 y &lt;em&gt;snapshots&lt;/em&gt; de disco. Aun así perdió cerca de seis horas de datos de producción: los volcados fallaban en silencio, porque usaban &lt;code&gt;pg_dump&lt;/code&gt; 9.2 contra un servidor 9.6 y las alertas por correo eran rechazadas. Los demás mecanismos tampoco permitían una recuperación limpia (GitLab, 2017).&lt;/p&gt;

&lt;p&gt;La lección se resume en una frase del libro de &lt;em&gt;Site Reliability Engineering&lt;/em&gt; de Google: “nadie quiere realmente hacer respaldos; lo que la gente quiere son restauraciones” (Blum &amp;amp; Singh, 2016). En este artículo reviso las tres estrategias de respaldo que ofrece PostgreSQL, cuándo conviene cada una y cómo comprobar que de verdad se pueden restaurar. Para practicarlas construí &lt;strong&gt;PgBackupLab&lt;/strong&gt;, una aplicación web que ejecuta un PostgreSQL 18 real en el navegador.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Dos números antes de elegir: RPO y RTO
&lt;/h2&gt;

&lt;p&gt;La guía de contingencia del NIST define dos objetivos que deberían guiar cualquier política de respaldo (Swanson et al., 2010):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RPO&lt;/strong&gt; (&lt;em&gt;Recovery Point Objective&lt;/em&gt;): cuántos datos, medidos en tiempo, puede perder el negocio. Si respaldas una vez al día a medianoche y el servidor falla a las 6 p. m., pierdes 18 horas de transacciones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RTO&lt;/strong&gt; (&lt;em&gt;Recovery Time Objective&lt;/em&gt;): cuánto tiempo puede estar caído el sistema mientras se restaura.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A estos dos objetivos se suma la &lt;strong&gt;regla 3-2-1&lt;/strong&gt;, que recomienda tener tres copias de los datos, en dos medios distintos y una de ellas fuera del sitio (Ruggiero &amp;amp; Heckathorn, 2012). Las guías actuales contra &lt;em&gt;ransomware&lt;/em&gt; agregan que esas copias deben estar &lt;strong&gt;cifradas, desconectadas y probadas periódicamente&lt;/strong&gt; (CISA et al., 2023).&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Las tres estrategias de PostgreSQL
&lt;/h2&gt;

&lt;p&gt;La documentación oficial organiza los respaldos en tres enfoques (PostgreSQL Global Development Group, 2025a).&lt;/p&gt;

&lt;h3&gt;
  
  
  3.1 Respaldo lógico (&lt;em&gt;SQL dump&lt;/em&gt;)
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;pg_dump&lt;/code&gt; genera un archivo con las sentencias SQL necesarias para recrear la base. Toma una instantánea consistente sin bloquear a los demás usuarios, porque trabaja dentro de una transacción &lt;code&gt;REPEATABLE READ&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pg_dump &lt;span class="nt"&gt;-Fc&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; tienda &lt;span class="nt"&gt;-f&lt;/span&gt; tienda.dump      &lt;span class="c"&gt;# formato personalizado y comprimido&lt;/span&gt;
pg_restore &lt;span class="nt"&gt;-d&lt;/span&gt; tienda_nueva tienda.dump    &lt;span class="c"&gt;# restauración, se puede paralelizar con -j&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;✅ Es portable entre versiones y arquitecturas, y permite restaurar una sola tabla.&lt;/li&gt;
&lt;li&gt;❌ En bases grandes es lento de generar y de restaurar, porque hay que reconstruir los índices. Además, el RPO es tan amplio como el intervalo entre volcados.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.2 Respaldo físico (a nivel de sistema de archivos)
&lt;/h3&gt;

&lt;p&gt;Se copian los archivos del directorio de datos (&lt;code&gt;PGDATA&lt;/code&gt;). La forma segura de hacerlo con el servidor encendido es &lt;code&gt;pg_basebackup&lt;/code&gt;, que coordina la copia con el WAL para que el resultado sea consistente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pg_basebackup &lt;span class="nt"&gt;-D&lt;/span&gt; /respaldos/base_2026_10_03 &lt;span class="nt"&gt;-Ft&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="nt"&gt;-P&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;✅ La restauración es muy rápida, porque basta copiar los archivos y arrancar el servidor.&lt;/li&gt;
&lt;li&gt;❌ Solo sirve para la misma versión mayor de PostgreSQL y siempre copia el clúster completo.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.3 Archivado continuo y PITR
&lt;/h3&gt;

&lt;p&gt;PostgreSQL escribe cada cambio primero en el &lt;strong&gt;WAL&lt;/strong&gt; (&lt;em&gt;Write-Ahead Log&lt;/em&gt;). Si esos segmentos se archivan de forma continua (&lt;code&gt;archive_mode = on&lt;/code&gt; y &lt;code&gt;archive_command&lt;/code&gt;), un respaldo físico base más el WAL archivado permiten &lt;strong&gt;reproducir la historia hasta cualquier instante&lt;/strong&gt;: es la recuperación a un punto en el tiempo, o PITR (PostgreSQL Global Development Group, 2025a).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# postgresql.conf
&lt;/span&gt;&lt;span class="py"&gt;archive_mode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;on&lt;/span&gt;
&lt;span class="py"&gt;archive_command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'test ! -f /archivo/%f &amp;amp;&amp;amp; cp %p /archivo/%f'&lt;/span&gt;
&lt;span class="c"&gt;# Durante la recuperación:
&lt;/span&gt;&lt;span class="py"&gt;restore_command&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'cp /archivo/%f %p'&lt;/span&gt;
&lt;span class="py"&gt;recovery_target_time&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'2026-10-03 21:23:52'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;✅ El RPO queda en segundos y permite volver justo al momento previo a un &lt;code&gt;DELETE&lt;/code&gt; accidental.&lt;/li&gt;
&lt;li&gt;❌ Requiere más configuración y espacio para el WAL, y hay que vigilar que el archivado no falle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Desde &lt;strong&gt;PostgreSQL 17&lt;/strong&gt; existe además el respaldo &lt;strong&gt;incremental nativo&lt;/strong&gt;: &lt;code&gt;pg_basebackup --incremental&lt;/code&gt; copia solo los bloques modificados desde un respaldo anterior, y &lt;code&gt;pg_combinebackup&lt;/code&gt; reconstruye el respaldo completo antes de restaurarlo (PostgreSQL Global Development Group, 2025b). En producción, herramientas como &lt;strong&gt;pgBackRest&lt;/strong&gt;, &lt;strong&gt;Barman&lt;/strong&gt; o &lt;strong&gt;WAL-G&lt;/strong&gt; automatizan todo lo anterior: compresión, cifrado, retención y envío a almacenamiento en la nube.&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Comparación rápida
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Estrategia&lt;/th&gt;
&lt;th&gt;RPO típico&lt;/th&gt;
&lt;th&gt;RTO&lt;/th&gt;
&lt;th&gt;Portabilidad&lt;/th&gt;
&lt;th&gt;Granularidad&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Lógico (&lt;code&gt;pg_dump&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Horas (intervalo entre volcados)&lt;/td&gt;
&lt;td&gt;Alto en bases grandes&lt;/td&gt;
&lt;td&gt;Alta (entre versiones)&lt;/td&gt;
&lt;td&gt;Base, esquema o tabla&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Físico (&lt;code&gt;pg_basebackup&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Horas (intervalo entre copias)&lt;/td&gt;
&lt;td&gt;Bajo&lt;/td&gt;
&lt;td&gt;Misma versión mayor&lt;/td&gt;
&lt;td&gt;Clúster completo&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Físico + WAL (PITR)&lt;/td&gt;
&lt;td&gt;Segundos&lt;/td&gt;
&lt;td&gt;Bajo a medio&lt;/td&gt;
&lt;td&gt;Misma versión mayor&lt;/td&gt;
&lt;td&gt;Cualquier instante&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;En la práctica se combinan: &lt;strong&gt;PITR como estrategia principal&lt;/strong&gt; y &lt;strong&gt;&lt;code&gt;pg_dump&lt;/code&gt; periódico como respaldo secundario y portable&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. PgBackupLab: practicar sin instalar nada
&lt;/h2&gt;

&lt;p&gt;Para no quedarme en la teoría, desarrollé una aplicación web que ejecuta &lt;strong&gt;PostgreSQL 18.3 real dentro del navegador&lt;/strong&gt;. Usa &lt;a href="https://pglite.dev" rel="noopener noreferrer"&gt;PGlite&lt;/a&gt;, una compilación de PostgreSQL a WebAssembly desarrollada por ElectricSQL (ElectricSQL, 2025). No necesita servidor, así que se publica gratis en GitHub Pages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa1skbrcjh38e1v29yzwz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fa1skbrcjh38e1v29yzwz.png" alt="Panel principal de PgBackupLab" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La app crea una base &lt;code&gt;tienda&lt;/code&gt; con cuatro tablas relacionadas (&lt;code&gt;clientes&lt;/code&gt;, &lt;code&gt;productos&lt;/code&gt;, &lt;code&gt;pedidos&lt;/code&gt; y &lt;code&gt;detalle_pedido&lt;/code&gt;) y permite recorrer el ciclo completo:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Respaldar de forma lógica o física.&lt;/li&gt;
&lt;li&gt;Generar actividad del negocio.&lt;/li&gt;
&lt;li&gt;Provocar un desastre: &lt;code&gt;DELETE&lt;/code&gt; sin &lt;code&gt;WHERE&lt;/code&gt;, &lt;code&gt;UPDATE&lt;/code&gt; masivo, &lt;code&gt;TRUNCATE&lt;/code&gt; o &lt;code&gt;DROP TABLE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Recuperar y verificar.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4.1 Respaldo lógico con el pg_dump real
&lt;/h3&gt;

&lt;p&gt;PGlite incluye el propio &lt;code&gt;pg_dump&lt;/code&gt; compilado a WebAssembly, así que el respaldo lógico es el auténtico:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pgDump&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@electric-sql/pglite-tools/pg_dump&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;backupLogico&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;archivo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;pgDump&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;pg&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;          &lt;span class="c1"&gt;// tienda.sql&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;archivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tipo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logico&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;datos&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Blob&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt; &lt;span class="na"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sql&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;huella&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;huella&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.2 Respaldo físico del directorio de datos
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;backupFisico&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;CHECKPOINT&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                   &lt;span class="c1"&gt;// fuerza a disco las páginas pendientes&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;datos&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumpDataDir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gzip&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;    &lt;span class="c1"&gt;// PGDATA comprimido, como pg_basebackup -Ft -z&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;tipo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fisico&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;datos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;datos&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;huella&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;huella&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;En mis pruebas, el respaldo lógico de la base de demostración ocupó &lt;strong&gt;45 KB&lt;/strong&gt; y tardó unos 120 ms. El físico ocupó &lt;strong&gt;4,46 MB&lt;/strong&gt; y tardó unos 400 ms, porque incluye el catálogo del sistema y todo el clúster. Este es justamente el compromiso entre ambas estrategias.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwrqjvouqgiokoze5sfzi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwrqjvouqgiokoze5sfzi.png" alt="Catálogo de respaldos con tamaño, tiempo y SHA-256" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 PITR: respaldo base y reproducción de cambios
&lt;/h3&gt;

&lt;p&gt;PGlite no expone el WAL físico, así que lo emulé con un &lt;strong&gt;WAL lógico&lt;/strong&gt;. Un &lt;em&gt;trigger&lt;/em&gt; registra cada fila insertada, modificada o borrada con un número de secuencia (LSN) y una marca de tiempo, y la aplicación copia esos registros fuera de la base, igual que lo haría &lt;code&gt;archive_command&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;_journal&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lsn&lt;/span&gt; &lt;span class="n"&gt;bigserial&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt; &lt;span class="n"&gt;timestamptz&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;clock_timestamp&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                       &lt;span class="n"&gt;tabla&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt; &lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nuevo&lt;/span&gt; &lt;span class="n"&gt;jsonb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;viejo&lt;/span&gt; &lt;span class="n"&gt;jsonb&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;FUNCTION&lt;/span&gt; &lt;span class="n"&gt;_journal_fila&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;RETURNS&lt;/span&gt; &lt;span class="k"&gt;trigger&lt;/span&gt; &lt;span class="k"&gt;LANGUAGE&lt;/span&gt; &lt;span class="n"&gt;plpgsql&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="k"&gt;INSERT&lt;/span&gt; &lt;span class="k"&gt;INTO&lt;/span&gt; &lt;span class="n"&gt;_journal&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tabla&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;op&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nuevo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;viejo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;VALUES&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TG_TABLE_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TG_OP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;TG_OP&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'DELETE'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;to_jsonb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;CASE&lt;/span&gt; &lt;span class="k"&gt;WHEN&lt;/span&gt; &lt;span class="n"&gt;TG_OP&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'INSERT'&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt; &lt;span class="n"&gt;to_jsonb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;OLD&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;La recuperación restaura el respaldo físico en una &lt;strong&gt;instancia nueva&lt;/strong&gt; y reproduce los cambios archivados hasta el LSN elegido. Durante la reproducción desactiva los &lt;em&gt;triggers&lt;/em&gt; con &lt;code&gt;session_replication_role = 'replica'&lt;/code&gt;, como hace una réplica:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;restaurarPITR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;archivo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;lsnObjetivo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;pg&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;restaurar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                         &lt;span class="c1"&gt;// 1. respaldo base&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cambios&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;archivo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lsn&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lsn&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lsn&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;lsnObjetivo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;pg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SET LOCAL session_replication_role = 'replica'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;cambios&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;aplicarCambio&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;        &lt;span class="c1"&gt;// 2. reproducir hasta el punto&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;pg&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4.4 Verificar antes de confiar
&lt;/h3&gt;

&lt;p&gt;Cada restauración se compara contra una &lt;strong&gt;huella&lt;/strong&gt; del estado original: el número de filas y el MD5 del contenido de cada tabla, ordenado por clave primaria. Además, el SHA-256 de cada archivo se comprueba antes de restaurarlo, así que un respaldo alterado se rechaza.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;filas&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="n"&gt;md5&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string_agg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'|'&lt;/span&gt; &lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt; &lt;span class="n"&gt;md5&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pedidos&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8qa9g1fsmo5yavtqlmub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8qa9g1fsmo5yavtqlmub.png" alt="Resultado de una recuperación PITR verificada" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En la demostración del video ocurre lo siguiente:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tomo un respaldo físico y luego registro 10 pedidos nuevos.&lt;/li&gt;
&lt;li&gt;Ejecuto &lt;code&gt;DELETE FROM pedidos&lt;/code&gt; sin &lt;code&gt;WHERE&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Con PITR recupero &lt;strong&gt;todo&lt;/strong&gt;, incluidos los pedidos posteriores al respaldo. Se reprodujeron 50 cambios y la restauración tardó unos 250 ms.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Con solo el respaldo completo, esos 10 pedidos se habrían perdido.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Despliegue automatizado
&lt;/h2&gt;

&lt;p&gt;El repositorio tiene dos &lt;em&gt;workflows&lt;/em&gt; de GitHub Actions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;deploy.yml&lt;/code&gt;&lt;/strong&gt;: en cada &lt;em&gt;push&lt;/em&gt; a &lt;code&gt;main&lt;/code&gt; ejecuta las pruebas con Vitest contra PostgreSQL real (respaldo lógico, físico, PITR, detección de archivos alterados y retención GFS). Después construye la app con Vite, la publica en &lt;strong&gt;GitHub Pages&lt;/strong&gt; y termina con una prueba de humo sobre la URL pública.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;simulacro.yml&lt;/code&gt;&lt;/strong&gt;: cada lunes repite el ciclo respaldar → desastre → restaurar → verificar. Es la versión automatizada del consejo de probar periódicamente las restauraciones (CISA et al., 2023).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v5&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm ci&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm test&lt;/span&gt;          &lt;span class="c1"&gt;# pruebas de respaldo y restauración&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm run build&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-pages-artifact@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;dist&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/deploy-pages@v4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvgl4bxvxezmmhdgrlepv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvgl4bxvxezmmhdgrlepv.png" alt="Workflows en GitHub Actions" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Lista de verificación para producción
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Define el &lt;strong&gt;RPO y el RTO&lt;/strong&gt; con el negocio antes de elegir herramientas.&lt;/li&gt;
&lt;li&gt;Usa &lt;strong&gt;respaldo físico + archivado de WAL&lt;/strong&gt; (pgBackRest, Barman o WAL-G) como estrategia principal, y &lt;code&gt;pg_dump&lt;/code&gt; como copia portable.&lt;/li&gt;
&lt;li&gt;Aplica &lt;strong&gt;3-2-1&lt;/strong&gt;: al menos una copia en otra región o proveedor, y una inmutable o desconectada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cifra&lt;/strong&gt; los respaldos y guarda las claves separadas de los datos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Verifica sumas de control&lt;/strong&gt; y restaura siempre en una instancia nueva, nunca sobre la dañada.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitorea&lt;/strong&gt; que el archivado no falle: un &lt;code&gt;archive_command&lt;/code&gt; roto deja el PITR inservible sin avisar.&lt;/li&gt;
&lt;li&gt;Define una &lt;strong&gt;retención&lt;/strong&gt; clara (por ejemplo, GFS: 7 diarios, 4 semanales y 12 mensuales).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatiza los simulacros de restauración&lt;/strong&gt; y mide el RTO real.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  7. Conclusión
&lt;/h2&gt;

&lt;p&gt;Un respaldo es una promesa; la restauración es la prueba de que se cumple. En PostgreSQL, &lt;code&gt;pg_dump&lt;/code&gt; aporta portabilidad, el respaldo físico aporta velocidad y el archivado continuo convierte un desastre de horas en una recuperación al segundo exacto. Lo que de verdad protege los datos es combinarlos, verificarlos y ensayar la recuperación hasta que sea rutina. Puedes intentarlo tú mismo en la &lt;a href="https://fernan101002.github.io/backup-strategies-postgresql/" rel="noopener noreferrer"&gt;demo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Referencias
&lt;/h2&gt;

&lt;p&gt;Blum, R., &amp;amp; Singh, R. (2016). Data integrity: What you read is what you wrote. En B. Beyer, C. Jones, J. Petoff &amp;amp; N. R. Murphy (Eds.), &lt;em&gt;Site reliability engineering: How Google runs production systems&lt;/em&gt; (cap. 26). O’Reilly Media. &lt;a href="https://sre.google/sre-book/data-integrity/" rel="noopener noreferrer"&gt;https://sre.google/sre-book/data-integrity/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;CISA, MS-ISAC, NSA &amp;amp; FBI. (2023). &lt;em&gt;#StopRansomware guide&lt;/em&gt;. Cybersecurity and Infrastructure Security Agency. &lt;a href="https://www.cisa.gov/stopransomware/ransomware-guide" rel="noopener noreferrer"&gt;https://www.cisa.gov/stopransomware/ransomware-guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ElectricSQL. (2025). &lt;em&gt;PGlite documentation&lt;/em&gt;. &lt;a href="https://pglite.dev/docs/" rel="noopener noreferrer"&gt;https://pglite.dev/docs/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitLab. (2017, 10 de febrero). &lt;em&gt;Postmortem of database outage of January 31&lt;/em&gt;. &lt;a href="https://about.gitlab.com/blog/postmortem-of-database-outage-of-january-31/" rel="noopener noreferrer"&gt;https://about.gitlab.com/blog/postmortem-of-database-outage-of-january-31/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL Global Development Group. (2025a). Chapter 25. Backup and restore. En &lt;em&gt;PostgreSQL 18 documentation&lt;/em&gt;. &lt;a href="https://www.postgresql.org/docs/current/backup.html" rel="noopener noreferrer"&gt;https://www.postgresql.org/docs/current/backup.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL Global Development Group. (2025b). pg_basebackup. En &lt;em&gt;PostgreSQL 17 documentation&lt;/em&gt;. &lt;a href="https://www.postgresql.org/docs/17/app-pgbasebackup.html" rel="noopener noreferrer"&gt;https://www.postgresql.org/docs/17/app-pgbasebackup.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ruggiero, P., &amp;amp; Heckathorn, M. A. (2012). &lt;em&gt;Data backup options&lt;/em&gt;. United States Computer Emergency Readiness Team (US-CERT). &lt;a href="https://www.cisa.gov/sites/default/files/publications/data_backup_options.pdf" rel="noopener noreferrer"&gt;https://www.cisa.gov/sites/default/files/publications/data_backup_options.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Swanson, M., Bowen, P., Phillips, A. W., Gallup, D., &amp;amp; Lynes, D. (2010). &lt;em&gt;Contingency planning guide for federal information systems&lt;/em&gt; (NIST Special Publication 800-34 Rev. 1). National Institute of Standards and Technology. &lt;a href="https://doi.org/10.6028/NIST.SP.800-34r1" rel="noopener noreferrer"&gt;https://doi.org/10.6028/NIST.SP.800-34r1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>postgres</category>
      <category>database</category>
      <category>backup</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
