Eseguire un PITR di un database PostgreSQL su Compute Engine


Questo tutorial mostra come configurare il processo di archiviazione ed eseguire un recupero in un determinato momento (PITR) di un database PostgreSQL in esecuzione su Compute Engine.

In questo tutorial, creerai un database di dimostrazione ed eseguirai un carico di lavoro dell'applicazione. Dopodiché, configura le procedure di archiviazione e backup. Successivamente, scoprirai come verificare le procedure di backup, archiviazione e recupero. Infine, scoprirai come recuperare il database in un momento specifico.

Questo tutorial è rivolto ad amministratori di database, operatori di sistema, professionisti DevOps e architetti cloud interessati a configurare una strategia di backup e recupero per i database PostgreSQL.

Questo tutorial presuppone che tu abbia dimestichezza con i contenitori Docker e che abbia familiarità con i comandi Linux, i motori di database PostgreSQL e Compute Engine.

Obiettivi

  • Configura una procedura di backup e archiviazione.
  • Esegui un PITR.
  • Monitora il backup.
  • Verificare un recupero.

Costi

In questo documento utilizzi i seguenti componenti fatturabili di Google Cloud:

Per generare una stima dei costi in base all'utilizzo previsto, utilizza il Calcolatore prezzi. I nuovi Google Cloud utenti potrebbero avere diritto a una prova gratuita.

Al termine delle attività descritte in questo documento, puoi evitare la fatturazione continua eliminando le risorse che hai creato. Per ulteriori informazioni, consulta la sezione Pulizia.

Prima di iniziare

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  3. Make sure that billing is enabled for your Google Cloud project.

  4. Enable the Compute Engine and Cloud Storage APIs.

    Enable the APIs

  5. Install the Google Cloud CLI.
  6. To initialize the gcloud CLI, run the following command:

    gcloud init
  7. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Go to project selector

  8. Make sure that billing is enabled for your Google Cloud project.

  9. Enable the Compute Engine and Cloud Storage APIs.

    Enable the APIs

  10. Install the Google Cloud CLI.
  11. To initialize the gcloud CLI, run the following command:

    gcloud init
  12. In the Google Cloud console, activate Cloud Shell.

    Activate Cloud Shell

    At the bottom of the Google Cloud console, a Cloud Shell session starts and displays a command-line prompt. Cloud Shell is a shell environment with the Google Cloud CLI already installed and with values already set for your current project. It can take a few seconds for the session to initialize.

Concetti

Prima di iniziare il tutorial, rivedi i seguenti concetti di PostgreSQL:

  • Archiviazione continua. Quando il database salva continuamente le transazioni sequenziali in un file.
  • Log Write Ahead (WAL). Le modifiche ai file di dati vengono registrate nel WAL prima di essere apportate al file.
  • Record WAL. Ogni transazione applicata al database viene formattata e memorizzata come record WAL.
  • Segmenta i file. I file di segmento hanno nomi di file in aumento monotonico e contengono il maggior numero possibile di record WAL. Le dimensioni del file sono configurabili, con un valore predefinito di 16 MiB. Potresti scegliere una dimensione maggiore se prevedi transazioni di grandi dimensioni o con un numero elevato di transazioni, per ridurre il numero aggregato di file di segmenti generati e il carico di gestione dei file.

Per ulteriori informazioni, consulta Affidabilità e log Write-Ahead.

Il seguente diagramma mostra come i WAL vengono mantenuti in due fasi.

2 fasi di WAL permanenti.

Nel diagramma precedente, la prima fase della persistenza dei WAL consiste nel fatto che il motore del database registra le transazioni di scrittura nel buffer WAL contemporaneamente alla scrittura in una tabella. Quando la transazione viene confermata, il buffer WAL viene scritto (svuotato) sul disco durante la seconda fase con un accodamento al file di segmento WAL.

Scegliere un PITR

Un PITR è appropriato per i seguenti scenari:

  • Riduci al minimo il Recovery Point Objective (RPO). L'RPO è il tempo massimo di perdita di dati tollerato prima che influisca in modo significativo sulle procedure aziendali. Il salvataggio di tutte le transazioni nei WAL tra gli snapshot di backup riduce drasticamente la quantità di dati persi perché hai le transazioni dall'ultimo backup completo da applicare al database.
  • Riduci al minimo l'RTO (Recovery Time Objective). Il RTO è il tempo necessario per recuperare un database in caso di evento dannoso. Dopo aver configurato i backup binari e l'archiviazione dei log, il tempo necessario per recuperare il database può essere minimo.
  • Risanamento di un bug di danneggiamento dei dati o di un errore amministrativo. Se una release del codice causa una corruzione catastrofica dei dati o viene commesso un errore irrecuperabile durante la manutenzione di routine, puoi recuperare la situazione precedente a questo momento.

In alcune architetture di applicazioni, ad esempio un'architettura di microservizi, potrebbero essere presenti database paralleli che potrebbero richiedere ripristini indipendenti. Ad esempio, un'applicazione di vendita al dettaglio potrebbe avere i dati dei clienti in un database e i dettagli degli ordini e le informazioni sull'inventario in altri database. A seconda dello stato complessivo dei dati, potrebbe essere necessario recuperare uno, due o tutti i database in parallelo.

Un PITR non è appropriato nei seguenti scenari:

  • Il RPO è elevato. Se il tuo criterio di ripristino dei disastri può tollerare la perdita di eventuali transazioni ricevute dopo lo snapshot recente, puoi evitare passaggi aggiuntivi e concentrarti sulla riduzione del tempo necessario per recuperare i dati.
  • È necessario un recupero completo del database. Se il tuo obiettivo è recuperare la transazione più recente, il target di recupero è il timestamp dell'ultima transazione persistente. Questo scenario è un caso specifico di PITR, ma semanticamente questo obiettivo è definito recupero completo.

Considerazioni sulle prestazioni

Il processo di archiviazione comporta un carico I/O aggiuntivo sul server di database. Il caricamento aggiuntivo dipende dalle caratteristiche del carico di lavoro, perché è proporzionale al volume di transazioni di scrittura, aggiornamento ed eliminazione.

Se vuoi ridurre l'impatto I/O che l'attività di archiviazione WAL potrebbe comportare sul tuo database principale, puoi eseguire le archiviazioni WAL periodiche utilizzando una replica di sola lettura.

Questa configurazione isola il database principale dalle attività di I/O batch relative al trasferimento dei file WAL. Le transazioni destinate alla replica di sola lettura vengono trasmesse in uno stream costante dal database principale, con un impatto molto minore sulla velocità effettiva in stato stazionario.

Inoltre, se la topologia del database di produzione include già una replica di sola lettura, questa configurazione non aggiunge alcun onere aggiuntivo: gestione, prezzo o altro.

Architettura di riferimento

Il seguente diagramma illustra l'architettura implementata in questo tutorial.

Infrastruttura cloud del PITR che utilizza Compute Engine e Cloud Storage.

In questo tutorial crei l'infrastruttura cloud per osservare un PITR che utilizza i seguenti componenti:

  • Un server di database PostgreSQL in esecuzione su Compute Engine.
  • Cloud Storage per l'archiviazione di snapshot e log delle transazioni.

Il seguente diagramma mostra i due container Docker lanciati sulla VM (macchina virtuale) del database PostgreSQL. Come separazione dei problemi, il server di database è in esecuzione in uno dei container e l'archiviatore WAL è in esecuzione nell'altro container.

Container Docker per il server di database e l'archiviatore WAL.

Questo diagramma mostra come i volumi Docker in ogni contenitore vengono mappati ai punti di montaggio del disco persistente sulla VM host.

Configurazione delle variabili di ambiente

Gli script e i comandi utilizzati in questo tutorial si basano sulle variabili di ambiente shell.

  1. In Cloud Shell, imposta le variabili di ambiente per il progetto, il nome dell'istanza e il database PostgreSQL di dimostrazione.

    export PROJECT_ID=your-gcp-project
    export PG_INSTANCE_NAME=instance-pg-pitr
    export POSTGRES_PASSWORD=PasswordIsThis
    export POSTGRES_PITR_DEMO_DBNAME=pitr_demo
    

    Sostituisci quanto segue:

    • your-gcp-project: il nome del progetto che hai creato per questo tutorial.
    • PasswordIsThis: una password sicura per il database PostgreSQL.
  2. Imposta la variabile di ambiente per la Google Cloud zona. Sostituisci choose-an-appropriate-zone con una Google Cloud zona.

    export ZONE=choose-an-appropriate-zone
    export REGION=${ZONE%-[a-z]}
    
  3. Imposta la variabile di ambiente per la sottorete Virtual Private Cloud (VPC) predefinita per la regione della tua zona:

    export SUBNETWORK_URI=$(gcloud compute networks subnets \
        describe default --format=json --region=$REGION | \
        jq --raw-output '.ipCidrRange')
    
  4. Imposta la variabile di ambiente per il bucket Cloud Storage. Sostituisci archive-bucket con un nome univoco per il bucket Cloud Storage in cui vengono salvati i WAL.

    export ARCHIVE_BUCKET=archive-bucket
    

Creazione di un bucket Cloud Storage

  • Crea un bucket Cloud Storage per archiviare i file WAL dal database PostgreSQL:

    gcloud storage buckets create gs://${ARCHIVE_BUCKET}
    

Consentire l'accesso alle istanze degli indirizzi IP privati

Per le istanze utilizzate in questo tutorial, come in molti casi d'uso di produzione, non è necessario che le istanze VM ottengano indirizzi IP pubblici. Tuttavia, le istanze richiedono l'accesso a internet pubblico per estrarre le immagini container di esempio e devi disporre dell'accesso per connetterti utilizzando una shell sicura. Configura un gateway di Network Address Translation (NAT) e Identity-Aware Proxy (IAP) per l'inoltro TCP.

Crea un gateway NAT

Poiché le istanze VM che crei non hanno indirizzi IP pubblici, devi creare un gateway NAT in modo che le istanze possano eseguire il pull delle immagini dei container da Docker Hub.

  1. In Cloud Shell, crea un router Cloud:

    export CLOUD_ROUTER_NAME=${PROJECT_ID}-nat-router
    gloud compute routers create $CLOUD_ROUTER_NAME \
        --network=default --region=$REGION
    
  2. Crea il gateway NAT:

    gcloud compute routers nats create ${PROJECT_ID}-nat-gateway \
        --region=$REGION \
        --router=$CLOUD_ROUTER_NAME \
        --auto-allocate-nat-external-ips \
        --nat-all-subnet-ip-ranges
    

Configurare IAP per l'inoltro TCP

IAP controlla l'accesso alle applicazioni cloud e alle VM in esecuzione su Google Cloud. IAP verifica l'identità dell'utente e il contesto della richiesta per determinare se un utente è autorizzato ad accedere a una VM.

  1. In Cloud Shell, consenti il traffico dal blocco di rete per l'inoltro TCP alle istanze del progetto:

    export IAP_FORWARDING_CIDR=35.235.240.0/20
    gcloud compute --project=$PROJECT_ID firewall-rules create \
        cloud-iap-tcp-forwarding --direction=INGRESS  \
        --priority=1000 --network=default \
        --action=ALLOW --rules=all  \
        --source-ranges=$IAP_FORWARDING_CIDR
    
  2. Per connetterti utilizzando un tunnel di inoltro TCP, aggiungi un'associazione di criteri Identity and Access Management (IAM). Sostituisci your-email-address con l'indirizzo email che utilizzi per accedere alla console Google Cloud.

    export GRANT_EMAIL_ADDRESS=your-email-address
    gcloud projects add-iam-policy-binding $PROJECT_ID \
       --member=user:$GRANT_EMAIL_ADDRESS \
       --role=roles/iap.tunnelResourceAccessor
    

Creazione dell'infrastruttura del database PostgreSQL

  1. In Cloud Shell, clona il repository di origine contenente gli script di configurazione e modifica il contesto della shell in modo che corrisponda al repository locale:

    git clone https://github.com/GoogleCloudPlatform/gcs-postgresql-recovery-tutorial
    cd gcs-postgresql-recovery-tutorial
    
  2. Per creare e configurare l'istanza VM del database, esegui il seguente script:

    cd bin
    ./create_postgres_instance.sh
    

    Per questo tutorial, lo script avvia un'istanza VM nella zona scelta con il sistema operativo ottimizzato per i container e due nuovi dischi permanenti collegati. In questo caso, puoi ignorare il messaggio di avviso restituito dall'API relativo alle scarse prestazioni I/O perché gli script creano piccoli dischi rigidi permanenti.

Controllo della configurazione di cloud-init

Cloud-init è un pacchetto multi-distribuzione che inizializza un'istanza cloud.

Esamina il seguente esempio di codice cloud-init:

write_files:
- path: /var/tmp/docker-entrypoint-initdb.d/init-pitr-demo-db.sql
  permissions: 0644
  owner: root
  content: |
    CREATE DATABASE ${POSTGRES_PITR_DEMO_DBNAME};

    \c ${POSTGRES_PITR_DEMO_DBNAME}

    CREATE SCHEMA pitr_db_schema;

    CREATE TABLE pitr_db_schema.customer
       (id SERIAL NOT NULL,
        name VARCHAR(255),
        create_timestamp TIMESTAMP DEFAULT current_timestamp,
        PRIMARY KEY (id));

    CREATE TABLE pitr_db_schema.invoice
       (id SERIAL NOT NULL,
        customer_id INTEGER
          REFERENCES pitr_db_schema.customer(id),
        description VARCHAR(1000),
        create_timestamp TIMESTAMP DEFAULT current_timestamp,
        PRIMARY KEY (customer_id, id));

- path: /etc/systemd/system/postgres.service
  permissions: 0644
  owner: root
  content: |
    [Unit]
    Requires=docker.service
    After=docker.service
    Description=postgres docker container

    [Service]
    TimeoutStartSec=0
    KillMode=none
    Restart=always
    RestartSec=5s
    ExecStartPre=-/usr/bin/docker kill postgres-db
    ExecStartPre=-/usr/bin/docker rm -v postgres-db
    ExecStart=/usr/bin/docker run -u postgres --name postgres-db \
                                  -v /var/tmp/docker-entrypoint-initdb.d:/docker-entrypoint-initdb.d \
                                  -v /mnt/disks/data:/var/lib/postgresql/data \
                                  -v /mnt/disks/wal:/var/lib/postgresql/wal \
                                  -e PGDATA=/var/lib/postgresql/data/pgdata \
                                  -e POSTGRES_PASSWORD=${POSTGRES_PASSWORD} \
                                  -e POSTGRES_INITDB_WALDIR=/var/lib/postgresql/wal/pg_wal \
                                  -p ${POSTGRES_PORT}:${POSTGRES_PORT} \
                               postgres:11-alpine
    ExecStop=-/usr/bin/docker stop postgres-db
    ExecStopPost=-/usr/bin/docker rm postgres-db

- path: /etc/systemd/system/wal_archive.service
  permissions: 0644
  owner: root
  content: |
    [Unit]
    Requires=docker.service postgres.service
    After=docker.service postgres.service
    Description=WAL archive docker container

    [Service]
    TimeoutStartSec=10min
    Type=oneshot
    ExecStart=/usr/bin/docker run --name wal-archive \
                                  -v /mnt/disks/wal/pg_wal_archive:/mnt/wal_archive \
                               google/cloud-sdk:slim gsutil mv /mnt/wal_archive/[0-9A-F]*[0-9A-F] gs://${ARCHIVE_BUCKET}
    ExecStopPost=-/usr/bin/docker rm wal-archive

- path: /etc/systemd/system/wal_archive.timer
  permissions: 0644
  owner: root
  content: |
    [Unit]
    Description=Archive WAL to GCS (every 5 minutes)

    [Timer]
    OnBootSec=5min
    OnUnitInactiveSec=5min
    OnUnitActiveSec=5min

    [Install]
    WantedBy=timers.target

Per questo tutorial, cloud-init viene utilizzato per:

  1. Crea due dispositivi di archiviazione a blocchi di dischi permanenti.
  2. Crea i file system sui due dispositivi: uno per i dati e uno per gli archivi dei log.
  3. Monta i dispositivi in punti di montaggio logici sull'istanza VM condivisi con i container Docker.
  4. Crea e avvia un servizio systemd (postgres.service), che avvia un contenitore Docker PostgreSQL con quanto segue:
    • I dischi permanenti montati come volumi.
    • La porta PostgreSQL (5432) pubblicata sulla VM host.
  5. Crea un file /var/tmp/docker-entrypoint-initdb.d/init-pitr-demo-db.sql per creare un semplice insieme di tabelle in un database e schema di dimostrazione.
  6. Crea e avvia un secondo servizio systemd (wal_archive.service) che gestisce un contenitore Docker Google Cloud CLI con i dischi WAL montati come volume. Questo servizio esegue il backup dei file WAL archiviati su Cloud Storage.
  7. Crea, abilita e avvia un timer systemd (wal_archive.timer) che esegue periodicamente il wal_archive.service.
  8. Assicurati che la porta PostgreSQL (5432) sia aperta per la sottorete VPC in modo che il generatore di transazioni possa raggiungere la porta del database.

Modifica la configurazione dell'istanza di database

Il server di database è in esecuzione, ma devi configurare l'accesso alla rete e avviare la procedura di archiviazione WAL.

Connettiti all'istanza VM del database

  1. Nella console Google Cloud, vai alla pagina Istanze VM.

    Vai all'istanza VM

  2. Per aprire una shell del terminale, fai clic su SSH accanto all'istanza instance-pg-pitr che hai creato.

  3. Nella shell del terminale, controlla che il contenitore Docker sia stato avviato: docker ps

    L'output è simile al seguente:

    CONTAINER ID   IMAGE                COMMAND                  CREATED              STATUS              PORTS   NAMES
    8bb65d8c1197   postgres:11-alpine   "docker-entrypoint.s…"   About a minute ago   Up About a minute           postgres-db
    

    Se il contenitore non è ancora in esecuzione, attendi un istante e poi utilizza lo stesso comando per controllare di nuovo.

Consenti connessioni di rete in entrata al database

  1. Nella shell del terminale dell'istanza instance-pg-pitr, apri il file di configurazione dell'autenticazione basata su host PostgreSQL per la modifica:

    sudoedit /mnt/disks/data/pgdata/pg_hba.conf
    
  2. Per rimuovere l'accesso predefinito di tutti gli indirizzi IP al database, commenta la riga seguente dalla fine del file aggiungendo # all'inizio della riga. La riga nel file è simile alla seguente:

    #host all all all md5
    
  3. Per consentire le connessioni protette da password dagli host nel blocco CIDR 10.0.0.0/8, aggiungi la seguente riga alla fine del file:

    host    all             all             10.0.0.0/8               md5
    

    Questa voce abilita la connettività dalla subnet VPC in cui viene successivamente creato il generatore di transazioni.

  4. Salva e chiudi il file.

Configurare l'archiviazione WAL

  1. Nella shell del terminale dell'istanza instance-pg-pitr, modifica il file postgresql.conf:

    sudoedit /mnt/disks/data/pgdata/postgresql.conf
    
  2. Sostituisci le righe archive_mode, archive_command e archive_timeout esistenti con commenti con quanto segue:

    archive_mode=on
    archive_command = '( ARCHIVE_PATH=/var/lib/postgresql/wal/pg_wal_archive;
    test ! -f $ARCHIVE_PATH/%f && cp %p $ARCHIVE_PATH/%f.cp && mv
    $ARCHIVE_PATH/%f.cp $ARCHIVE_PATH/%f ) '
    archive_timeout = 120
    

    Quando sostituisci le righe nel file modificato, il codice sarà simile al seguente snippet:

    
    .... illustrative snippet start ....
    
    # - Archiving -
    archive_mode=on
    archive_command = '( ARCHIVE_PATH=/var/lib/postgresql/wal/pg_wal_archive;  test ! -f $ARCHIVE_PATH/%f && cp %p $ARCHIVE_PATH/%f.cp && mv $ARCHIVE_PATH/%f.cp $ARCHIVE_PATH/%f ) '
    archive_timeout = 120
    #------------------------------------------------------------------------------
    # REPLICATION
    #------------------------------------------------------------------------------
    
    .... illustrative snippet end ....
    
    
  3. Salva e chiudi il file.

Applica e verifica le modifiche alla configurazione

  1. Nella shell del terminale dell'istanza instance-pg-pitr, riavvia il contenutore per applicare le modifiche:

    sudo systemctl restart postgres
    
  2. Controlla i file del segmento WAL:

    sudo ls -l /mnt/disks/wal/pg_wal
    

    L'output è simile al seguente:

    total 16388
    -rw------- 1 postgres 70 16777216 Sep  5 23:07 000000010000000000000001
    drwx------ 2 postgres 70     4096 Sep  5 23:05 archive_status
    
  3. Verifica la connettività di rete al database:

    export LOCAL_IP=127.0.0.1
    docker exec postgres-db psql -w --host=$LOCAL_IP \
          --command='SELECT 1'
    

    L'output è simile al seguente:

    ?column?
    ----------
           1
    (1 row)
    
  4. Chiudi la connessione SSH all'istanza.

Avvio del generatore di transazioni per compilare il database

I passaggi che seguono avviano un programma Go che genera transazioni per questo tutorial. Il programma viene eseguito all'interno di un contenitore su un'istanza VM.

L'immagine del contenitore è già stata creata e ospitata in un progetto con un Container Registry pubblico.

  1. In Cloud Shell, passa alla directory del generatore di transazioni:

    cd ~/gcs-postgresql-recovery-tutorial/bin
    
  2. Imposta le variabili di ambiente:

    export TRANS_GEN_INSTANCE_NAME=instance-trans-gen
    export POSTGRES_HOST_IP=$(gcloud compute instances describe  \
        --format=json --zone=${ZONE} ${PG_INSTANCE_NAME} | \
        jq --raw-output '.networkInterfaces[0].networkIP')
    
  3. Per eseguire il generatore di transazioni, avvia l'istanza:

    ./run_trans_gen_instance.sh
    

    Ignora il messaggio di avviso relativo alle scarse prestazioni I/O.

  4. Attendi qualche istante e controlla che le transazioni raggiungano il database PostgreSQL:

    gcloud compute ssh $PG_INSTANCE_NAME \
       --tunnel-through-iap \
       --zone=$ZONE \
       --command="docker exec postgres-db psql \
       --dbname=$POSTGRES_PITR_DEMO_DBNAME \
       --command='SELECT COUNT(*) FROM pitr_db_schema.customer;'"
    

    L'output contiene un conteggio maggiore di 0 quando i record vengono aggiunti al database dal generatore di transazioni:

     count
    -------
       413
    (1 row)
    

Configurazione della pianificazione del backup degli snapshot binari

Puoi eseguire il backup dei dischi permanenti in base a una pianificazione e conservarli per un periodo di tempo definito nel criterio della risorsa.

Crea la pianificazione degli snapshot

  1. In Cloud Shell, imposta le variabili di ambiente:

    export ZONE=zone-of-your-instance
    export SNAPSHOT_SCHEDULE_NAME=pg-disk-schedule
    export REGION=${ZONE%-[a-z]}
    export SNAPSHOT_WINDOW_START=$(TZ=":GMT" date "+%H:00")
    export SNAPSHOT_RETENTION_DAYS=2
    export SNAPSHOT_FREQUENCY_HOURS=1
    

    Sostituisci zone-of-your-instance con la Google Cloud zona in cui hai avviato in precedenza la VM del database.

  2. Crea la pianificazione degli snapshot:

    gcloud compute resource-policies create snapshot-schedule \
        $SNAPSHOT_SCHEDULE_NAME \
        --region=$REGION \
        --max-retention-days=$SNAPSHOT_RETENTION_DAYS \
        --on-source-disk-delete=apply-retention-policy \
        --hourly-schedule=$SNAPSHOT_FREQUENCY_HOURS \
        --start-time=$SNAPSHOT_WINDOW_START \
        --storage-location=$REGION
    

Collega la pianificazione degli snapshot ai dischi

Quando hai eseguito lo script per creare un'istanza, i volumi di dati e WAL sono stati creati come due dischi permanenti indipendenti. Per creare snapshot di dischi permanenti in base a una pianificazione definita, associa un criterio di risorsa a ogni disco permanente. In questo caso, vuoi che gli snapshot dei dischi vengano eseguiti contemporaneamente, quindi utilizzi lo stesso criterio per entrambi i dischi permanenti collegati alla VM Compute Engine.

  1. In Cloud Shell, imposta le variabili di ambiente:

    export SNAPSHOT_SCHEDULE_NAME=pgdata-disk-schedule
    export PG_INSTANCE_NAME=instance-pg-pitr
    export ZONE=zone-of-your-instance
    
  2. Collega il criterio di pianificazione al disco di dati permanente:

    gcloud beta compute disks add-resource-policies ${PG_INSTANCE_NAME}-data \
        --resource-policies $SNAPSHOT_SCHEDULE_NAME \
        --zone $ZONE
    
  3. Collega il criterio di pianificazione al disco WAL permanente:

    gcloud beta compute disks add-resource-policies ${PG_INSTANCE_NAME}-wal \
        --resource-policies $SNAPSHOT_SCHEDULE_NAME \
        --zone $ZONE
    

Eseguire manualmente uno snapshot

(Facoltativo) Gli snapshot pianificati vengono eseguiti all'interno della finestra di pianificazione, pertanto è improbabile che uno snapshot venga acquisito immediatamente dopo la creazione della pianificazione. Se non vuoi attendere lo snapshot pianificato, puoi eseguire manualmente lo snapshot iniziale.

  1. In Cloud Shell, imposta le variabili di ambiente:

    export ZONE=zone-of-your-instance
    export PG_INSTANCE_NAME=instance-pg-pitr
    export REGION=${ZONE%-[a-z]}
    
  2. Crea uno snapshot dei due dischi permanenti dell'istanza PostgreSQL:

    gcloud compute disks snapshot \
        ${PG_INSTANCE_NAME}-data ${PG_INSTANCE_NAME}-wal \
        --snapshot-names=${PG_INSTANCE_NAME}-data-`date+%s`,${PG_INSTANCE_NAME}-wal-`date +%s` \
        --zone=$ZONE --storage-location=$REGION
    
  3. Visualizza gli snapshot che hai creato:

    gcloud compute snapshots list
    

    L'output è simile al seguente:

    NAME                              DISK_SIZE_GB  SRC_DISK                                   STATUS
    instance-pg-pitr-data-1578339767  200           us-central1-f/disks/instance-pg-pitr-data  READY
    instance-pg-pitr-wal-1578339767   100           us-central1-f/disks/instance-pg-pitr-wal   READY
    

Eseguire un PITR

Un PITR viene spesso eseguito per recuperare i dati persi a causa di un errore operativo o programmatico.

In questa sezione del tutorial, esegui un aggiornamento del database per simulare una perdita catastrofica di dati. Simula quindi una risposta in preda al panico, prima di avviare un recupero fino al momento precedente all'emissione del comando errato.

Assicurati che sia possibile eseguire un PITR

Prima di eseguire un PITR, devi attendere il tempo sufficiente per l'esecuzione di quanto segue:

  • I backup binari (snapshot dei dischi)
  • Archiviazione WAL

Per questo tutorial, archive_timeout è stato impostato su un valore insolitamente basso di 120 secondi per forzare una rotazione frequente dei file WAL. Devi anche attendere che sia stato eseguito almeno uno snapshot del disco pianificato o devi eseguire manualmente lo snapshot del disco.

  1. Verifica che sia stato acquisito almeno uno snapshot:

    1. Nella console Google Cloud, vai alla pagina Snapshot.

      Vai alla pagina Snapshot

    2. Verifica che siano presenti almeno due istantanee, ad esempio una per il volume di dati e una per il volume WALinstance-pg-pitr--us-central1-a-20190805023535-i3hpw7kn.

  2. Verifica che i file di segmento siano archiviati in Cloud Storage:

    1. Nella console Google Cloud, vai alla pagina Browser Cloud Storage.

      Vai alla pagina Browser Cloud Storage

    2. Fai clic su archive-bucket.

      Bucket Cloud Storage contenente oggetti.

Danneggiare i dati

Per simulare una perdita catastrofica di dati, apri una shell a riga di comando per il database PostgreSQL e danneggia i dati nella tabella compilata dal generatore di transazioni.

  1. Nella console Google Cloud, vai alla pagina Istanze VM.

    Vai alla pagina Istanze VM

  2. Per l'istanza instance-pg-pitr, fai clic su SSH.

  3. Nel terminale SSH, esegui il frontend PostgreSQL basato su terminale nel container Docker:

    docker exec -it postgres-db psql --dbname=pitr_demo
    
  4. Per modificare una riga nella tabella customer, invia un'istruzione DML SQL con un errore ortografico intenzionale nella shell PostgreSQL:

    UPDATE pitr_db_schema.customer
    SET name = 'New Name for customer id=1';
    WHERE id = 1;
    

    L'output è simile al seguente:

    UPDATE 999
    pitr_demo=#  WHERE id = 1;
    ERROR:  syntax error at or near "WHERE"
    LINE 1: WHERE id = 1;
            ^
     

    L'errore è stato generato perché è stato inserito un punto e virgola aggiuntivo prima della clausolaWHERE. Tutte le righe del database sono state aggiornate. Ora puoi eseguire un recupero dei dati dopo il ripristino per recuperare le righe modificate dall'istruzione errata.

Determina l'ora target per il recupero

Il primo passaggio di un PITR consiste nel determinare la data e l'ora di destinazione del recupero. Questo periodo di tempo viene determinato esaminando i dati per identificare un punto leggermente prima dell'evento che ha danneggiato i dati.

  1. Nella shell del terminale dell'istanza instance-pg-pitr, ottieni il timestamp massimo delle righe danneggiate:

    SELECT MAX(create_timestamp)::timestamptz
      FROM pitr_db_schema.customer
    WHERE name = 'New Name for customer id=1';
    

    L'output è simile al seguente:

                 max              .
    -------------------------------
    2019-08-05 18:14:58.226511+00
    (1 row)
    

    In un database di produzione, la query per determinare la destinazione del recupero è più complessa, soprattutto nei casi in cui la tabella interessata è di grandi dimensioni e la colonna indicativa non è indicizzata.

  2. Copia il risultato. Utilizzerai il valore restituito da questa query nel passaggio successivo.

Recupera il database

Per questo tutorial, uno script di recupero automatizza il PITR. Ti consigliamo di avere una procedura automatica per il recupero del database e di testarla periodicamente.

  1. In Cloud Shell, imposta la directory di lavoro attuale sulla posizione dello script di recupero:

    cd ~/gcs-postgresql-recovery-tutorial/bin
    
  2. Imposta le variabili di ambiente richieste per lo script. Sostituisci YYYY-MM-DD HH:MM:SS.999999+00 con l'output della query che hai copiato in precedenza.

    export PROJECT_ID=$(gcloud config get-value project)
    export PG_INSTANCE_NAME=instance-pg-pitr
    export POSTGRES_PASSWORD=PasswordIsThis
    export PG_INSTANCE_NAME=instance-pg-pitr
    export RECOVER_BUCKET=archive-bucket
    export PIT_RECOVERY_TARGET="YYYY-MM-DD HH:MM:SS.999999+00"
    export ZONE=zone-of-your-instance
    
  3. Esegui lo script di recupero:

    ./recover_to_point_in_time.sh
    

Informazioni sullo script di recupero

Questa sezione fornisce alcuni dettagli sui parametri di input e sui passaggi eseguiti dallo script.

Lo script richiede che siano impostate le seguenti variabili di ambiente:

  • PIT_RECOVERY_TARGET: l'ora target del recupero.
  • PROJECT_ID: il progetto in cui si trova l'istanza PG_INSTANCE_NAME.
  • ZONE: la zona in cui si trova l'istanza PG_INSTANCE_NAME.
  • PG_INSTANCE_NAME: l'istanza in cui è in esecuzione l'istanza PostgreSQL di produzione.
  • RECOVER_BUCKET: il bucket Cloud Storage dove vengono archiviati i file di segmento WAL.
  • POSTGRES_PASSWORD: la password utilizzata per l'utente del database PostgreSQL.

Lo script esegue i seguenti passaggi:

  1. Determina gli snapshot dei dischi più recenti in base alla data e all'ora del destinazione di recupero.
  2. Crea un file cloud-init.yaml fornito a una VM di archiviazione ottimizzata per i container che esegue il database PITR. Il cloud-init.yaml file crea file di configurazione ed esegue diversi comandi di sistema per stabilire il seguente ambiente:

    • Un container gcsfuse che monta il bucket dell'archivio dei file del segmento WAL come volume, che viene poi esposto all'host con un mount bind Docker.
    • Un postgres-dbcontenitore in cui il motore del database esegue quanto segue:

      • Il file system host a cui sono collegati i dischi permanenti come volumi.
      • Il file system host a cui è collegato il bucket Cloud Storage come volume.
    • Un file di recupero recovery.conf nella directory dei dati PostgreSQL con le seguenti informazioni:

      • La data target.
      • Il comando restore: un comando di copia parametrizzato utilizzato dal database per copiare i file dei segmenti WAL in base alle esigenze dal file system dell'archivio. %f è il file del segmento e %p è il percorso utilizzato dal database per l'elaborazione dei file durante il recupero.
    • Le impostazioni archive_ sono commentate nel file di impostazioni postgresql.conf per evitare di danneggiare la directory dell'archivio WAL.

  3. Avvia l'istanza PITR con le seguenti informazioni:

    • Un nome creato combinando la variabile di ambiente $PG_INSTANCE_NAME e i valori alfanumerici della variabile di ambiente $PIT_RECOVERY_TARGET.
    • Dischi permanenti creati dagli snapshot dei dischi identificati in precedenza.

Di seguito è riportato un esempio di file recovery.conf:

restore_command = '(test -d /var/lib/postgresql/wal/pg_wal_recover && cp /var/lib/postgresql/wal/pg_wal_recover/%f %p ) '
recovery_target_time='YYYY-MM-DD HH:MM:SS UTC'
recovery_target_inclusive=true

Convalida il recupero

  1. Nella console Google Cloud, vai alla pagina Istanze VM.

    Vai alla pagina Istanze VM

  2. Per l'istanza instance-pg-pitr-YYYYMMDDHHMMSS, fai clic su SSH.

  3. Nei terminali SSH, esegui il frontend PostgreSQL basato su terminale nel container Docker:

    docker exec -it postgres-db psql --dbname=pitr_demo
    

    Se viene visualizzato il seguente errore, attendi un momento per l'avvio del contenitore PostgreSQL e riavvia il comando:

    Error: No such container: postgres-db
    
  4. Controlla i dati nella tabella customer:

    SELECT * FROM pitr_db_schema.customer
    WHERE id > (SELECT MAX(id)-10 FROM pitr_db_schema.customer);
    

    L'output è simile al seguente:

       id  |           name            |      create_timestamp
    ------+---------------------------+----------------------------
      711 | customer_name_from_golang | 2019-12-06 18:03:51.229444
      712 | customer_name_from_golang | 2019-12-06 18:03:52.531755
      713 | customer_name_from_golang | 2019-12-06 18:03:53.555441
      714 | customer_name_from_golang | 2019-12-06 18:03:54.581872
      715 | customer_name_from_golang | 2019-12-06 18:03:55.607459
      716 | customer_name_from_golang | 2019-12-06 18:03:56.633362
      717 | customer_name_from_golang | 2019-12-06 18:03:57.658523
      718 | customer_name_from_golang | 2019-12-06 18:03:58.685469
      719 | customer_name_from_golang | 2019-12-06 18:03:59.706939
    

    Il nome mostra il valore creato dal generatore di transazioni. La riga finale ha un timestamp precedente a quello del target di recupero (che hai fornito allo script di recupero in una variabile di ambiente). A seconda del numero di record da recuperare, potrebbe essere necessario attendere qualche istante per l'aggiornamento di tutte le righe.

Esegui la pulizia

Il modo più semplice per eliminare la fatturazione è eliminare il progetto Google Cloud che hai creato per il tutorial. In alternativa, puoi eliminare le singole risorse.

Elimina il progetto

  1. In the Google Cloud console, go to the Manage resources page.

    Go to Manage resources

  2. In the project list, select the project that you want to delete, and then click Delete.
  3. In the dialog, type the project ID, and then click Shut down to delete the project.

Passaggi successivi