Melakukan PITR database PostgreSQL di Compute Engine


Tutorial ini menunjukkan cara menyiapkan proses pengarsipan, dan kemudian melakukan pemulihan point-in-time (PITR) dari database PostgreSQL yang berjalan di Compute Engine.

Dalam tutorial ini, Anda akan membuat database demonstrasi dan menjalankan workload aplikasi. Kemudian, Anda mengonfigurasi proses pengarsipan dan pencadangan. Selanjutnya, Anda akan mempelajari cara memverifikasi proses pencadangan, pengarsipan, dan pemulihan. Terakhir, Anda akan mempelajari cara memulihkan database ke titik waktu tertentu.

Tutorial ini ditujukan bagi administrator database, operator sistem, profesional DevOps, dan arsitek cloud yang tertarik untuk mengonfigurasi strategi pencadangan dan pemulihan untuk database PostgreSQL.

Tutorial ini mengasumsikan bahwa Anda sudah memahami container Docker dan sudah terbiasa menggunakan perintah Linux, mesin database PostgreSQL, dan Compute Engine.

Tujuan

  • Menyiapkan proses pencadangan dan pengarsipan.
  • Melakukan PITR.
  • Memantau pencadangan Anda.
  • Memverifikasi pemulihan.

Biaya

Dalam dokumen ini, Anda menggunakan komponen Google Cloud yang dapat ditagih berikut:

Untuk membuat perkiraan biaya berdasarkan proyeksi penggunaan Anda, gunakan kalkulator harga. Pengguna baru Google Cloud mungkin memenuhi syarat untuk mendapatkan uji coba gratis.

Setelah menyelesaikan tugas yang dijelaskan dalam dokumen ini, Anda dapat menghindari penagihan berkelanjutan dengan menghapus resource yang Anda buat. Untuk mengetahui informasi selengkapnya, lihat Pembersihan.

Sebelum memulai

  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. Di konsol Google Cloud, pada halaman pemilih project, pilih atau buat project Google Cloud.

    Buka pemilih project

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

  4. Aktifkan API Compute Engine and Cloud Storage.

    Mengaktifkan API

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

    gcloud init
  7. Di konsol Google Cloud, pada halaman pemilih project, pilih atau buat project Google Cloud.

    Buka pemilih project

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

  9. Aktifkan API Compute Engine and Cloud Storage.

    Mengaktifkan API

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

    gcloud init
  12. Di konsol Google Cloud, aktifkan Cloud Shell.

    Aktifkan Cloud Shell

    Di bagian bawah Google Cloud Console, Cloud Shell sesi akan terbuka dan menampilkan perintah command line. Cloud Shell adalah lingkungan shell dengan Google Cloud CLI yang sudah terinstal, dan dengan nilai yang sudah ditetapkan untuk project Anda saat ini. Diperlukan waktu beberapa detik untuk melakukan inisialisasi sesi.

Konsep

Sebelum memulai tutorial, tinjau konsep PostgreSQL berikut:

  • Pengarsipan berkelanjutan. Saat database terus menyimpan transaksi berurutan ke file.
  • Write Ahead Log (WAL). Perubahan pada file data dicatat di WAL sebelum dibuat pada file.
  • Catatan WAL. Setiap transaksi yang diterapkan ke database diformat dan disimpan sebagai catatan WAL.
  • Menyegmentasikan file. File segmen memiliki nama file yang meningkat secara monoton, dan berisi catatan WAL sebanyak mungkin. Ukuran file dapat dikonfigurasi, dengan default 16 MiB. Anda dapat memilih ukuran yang lebih besar jika Anda mengharapkan ukuran atau jumlah transaksi yang besar, untuk menurunkan jumlah agregat file segmen yang dihasilkan dan untuk mengurangi beban pengelolaan file.

Untuk informasi selengkapnya, lihat Keandalan dan Write-Ahead Log.

Diagram berikut menunjukkan bagaimana WAL dipertahankan dalam dua tahap.

2 tahap WAL persisten.

Pada diagram sebelumnya, tahap pertama mempertahankan WAL terdiri dari mesin database yang mencatat transaksi tulis di buffer WAL secara bersamaan dengan penulisan ke tabel. Saat transaksi di-commit, buffer WAL akan ditulis (dibuang) ke disk selama tahap kedua dengan penambahan ke file segmen WAL.

Memilih PITR

PITR sesuai untuk skenario berikut:

  • Minimalkan batas titik pemulihan (RPO). RPO adalah waktu maksimum kehilangan data yang ditoleransi sebelum berdampak signifikan pada proses bisnis. Menyimpan semua transaksi di WAL antar-snapshot pencadangan akan secara drastis mengurangi jumlah data yang hilang karena Anda memiliki transaksi sejak pencadangan penuh terakhir yang diterapkan ke database.
  • Meminimalkan batas waktu pemulihan (RTO). RTO adalah jumlah waktu yang diperlukan untuk memulihkan database jika terjadi peristiwa destruktif. Setelah Anda menyiapkan pencadangan biner dan pengarsipan log, waktu yang diperlukan untuk memulihkan database bisa sangat minimal.
  • Perbaikan bug kerusakan data, atau kesalahan administratif. Jika rilis kode menyebabkan kerusakan data besar, atau terjadi kesalahan yang tidak dapat dipulihkan selama pemeliharaan rutin, Anda dapat memulihkannya sebelum momen tersebut.

Di beberapa arsitektur aplikasi, seperti arsitektur microservice, mungkin ada database paralel yang mungkin memerlukan pemulihan independen. Misalnya, sebuah aplikasi retail mungkin memiliki data pelanggan dalam satu database dan detail pesanan retail serta informasi inventaris di database lain. Bergantung pada status data secara keseluruhan, satu, dua, atau semua database mungkin perlu dipulihkan secara paralel.

PITR tidak sesuai dalam skenario berikut:

  • RPO itu besar. Jika kebijakan pemulihan dari bencana Anda dapat menoleransi kehilangan transaksi yang diterima setelah snapshot terbaru, Anda dapat menghindari langkah-langkah tambahan dan berfokus untuk mengurangi waktu pemulihan data Anda.
  • Diperlukan pemulihan database menyeluruh. Jika tujuan Anda adalah memulihkan ke transaksi terbaru, target pemulihan Anda adalah stempel waktu transaksi terakhir yang dipertahankan. Skenario ini merupakan kasus khusus PITR, tetapi secara semantis tujuan ini disebut sebagai pemulihan penuh.

Pertimbangan performa

Proses pengarsipan menempatkan beban I/O tambahan pada server database Anda. Beban tambahan bergantung pada karakteristik workload Anda karena beban ini sebanding dengan volume operasi tulis, update, dan penghapusan.

Jika ingin mengurangi dampak I/O yang mungkin ditimbulkan oleh aktivitas arsip WAL pada database utama, Anda dapat menjalankan pengarsipan WAL berkala menggunakan replika hanya baca.

Konfigurasi ini mengisolasi database utama dari aktivitas I/O berorientasi batch yang terkait dengan transfer file WAL. Transaksi yang ditujukan untuk replika hanya baca akan ditransmisikan dalam aliran konstan dari database utama, sehingga memerlukan dampak yang jauh lebih rendah pada throughput dalam keadaan stabil.

Selanjutnya, jika topologi database produksi Anda sudah menyertakan replika hanya baca, konfigurasi ini tidak menambah beban tambahan: pengelolaan, harga, atau sebaliknya.

Arsitektur referensi

Diagram berikut mengilustrasikan arsitektur yang Anda implementasikan dalam tutorial ini.

Infrastruktur cloud PITR menggunakan Compute Engine dan Cloud Storage.

Dalam tutorial ini, Anda akan membuat infrastruktur cloud untuk mengamati PITR yang menggunakan komponen berikut:

  • Server database PostgreSQL yang berjalan di Compute Engine.
  • Cloud Storage untuk penyimpanan snapshot dan log transaksi.

Diagram berikut menunjukkan dua container Docker yang diluncurkan di mesin virtual (VM) database PostgreSQL. Sebagai pemisahan fokus, server database berjalan di salah satu container, dan pengarsipan WAL berjalan di container lainnya.

Container Docker untuk server database dan pengarsipan WAL.

Diagram ini menunjukkan bagaimana volume Docker di setiap container dipetakan ke direktori pemasangan Persistent Disk di VM host.

Menyiapkan variabel lingkungan

Skrip dan perintah yang digunakan dalam tutorial ini mengandalkan variabel lingkungan shell.

  1. Di Cloud Shell, tetapkan variabel lingkungan untuk project Anda, nama instance, dan database PostgreSQL demonstrasi.

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

    Ganti kode berikut:

    • your-gcp-project: nama project yang Anda buat untuk tutorial ini.
    • PasswordIsThis: sandi yang aman untuk database PostgreSQL.
  2. Tetapkan variabel lingkungan untuk zona Google Cloud. Ganti choose-an-appropriate-zone dengan zona Google Cloud.

    export ZONE=choose-an-appropriate-zone
    export REGION=${ZONE%-[a-z]}
    
  3. Menetapkan variabel lingkungan untuk default Virtual Private Cloud (VPC) subnet untuk region zona Anda:

    export SUBNETWORK_URI=$(gcloud compute networks subnets \
        describe default --format=json --region=$REGION | \
        jq --raw-output '.ipCidrRange')
    
  4. Menetapkan variabel lingkungan untuk bucket Cloud Storage. Ganti archive-bucket dengan nama unik untuk bucket Cloud Storage tempat WAL disimpan.

    export ARCHIVE_BUCKET=archive-bucket
    

Membuat bucket Cloud Storage

  • Buat bucket Cloud Storage untuk mengarsipkan file WAL dari database PostgreSQL:

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

Mengizinkan akses ke instance alamat IP pribadi

Untuk instance yang digunakan dalam tutorial ini, seperti pada banyak kasus penggunaan produksi, instance VM tidak perlu mendapatkan alamat IP publik. Namun, instance memerlukan akses ke internet publik untuk mengambil image container contoh, dan Anda memerlukan akses agar dapat terhubung menggunakan shell yang aman. Anda mengonfigurasi gateway penafsiran alamat jaringan (NAT) dan mengonfigurasi Identity-Aware Proxy (IAP) untuk penerusan TCP.

Buat gateway NAT

Karena instance VM yang Anda buat tidak memiliki alamat IP publik, Anda dapat membuat gateway NAT agar instance dapat mengambil image container dari Docker Hub.

  1. Di Cloud Shell, buat Cloud Router:

    export CLOUD_ROUTER_NAME=${PROJECT_ID}-nat-router
    gloud compute routers create $CLOUD_ROUTER_NAME \
        --network=default --region=$REGION
    
  2. Buat 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
    

Mengonfigurasi IAP untuk penerusan TCP

IAP mengontrol akses ke aplikasi cloud dan VM yang berjalan di Google Cloud. IAP memverifikasi identitas pengguna dan konteks permintaan untuk menentukan apakah pengguna diizinkan untuk mengakses VM atau tidak.

  1. Di Cloud Shell, izinkan traffic dari blok net penerusan TCP ke instance dalam project Anda:

    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. Untuk terhubung menggunakan terowongan penerusan TCP, tambahkan Identity and Access Management (IAM) pengikatan kebijakan. Ganti your-email-address dengan alamat email yang Anda gunakan untuk login ke Konsol 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
    

Membuat infrastruktur database PostgreSQL

  1. Di Cloud Shell, clone repositori sumber yang berisi skrip konfigurasi, dan ubah konteks shell ke repositori lokal:

    git clone https://github.com/GoogleCloudPlatform/gcs-postgresql-recovery-tutorial
    cd gcs-postgresql-recovery-tutorial
    
  2. Untuk membuat dan mengonfigurasi instance VM database, jalankan skrip berikut:

    cd bin
    ./create_postgres_instance.sh
    

    Untuk tutorial ini, skrip ini memulai instance VM di zona yang Anda pilih dengan sistem operasi yang dioptimalkan untuk container, dan dua persistent disk baru yang terpasang. Dalam hal ini, Anda dapat mengabaikan pesan peringatan yang ditampilkan oleh API tentang performa I/O yang buruk karena skrip tersebut membuat Persistent Disk yang kecil.

Meninjau konfigurasi cloud-init

Cloud-init adalah paket multi-distribusi yang menginisialisasi instance cloud.

Tinjau contoh kode cloud-init berikut:

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

Untuk tutorial ini, cloud-init digunakan untuk melakukan hal-hal berikut:

  1. Membuat dua perangkat block storage Persistent Disk.
  2. Membuat sistem file di kedua perangkat: satu untuk data dan satu untuk log arsip.
  3. Memasang perangkat pada direktori pemasangan logis pada instance VM yang dibagikan dengan container Docker.
  4. Buat dan kemudian mulai layanan systemd (postgres.service), yang memulai container Docker PostgreSQL dengan hal berikut:
    • Persistent disk dipasang sebagai volume.
    • Port PostgreSQL (5432) dipublikasikan ke host VM.
  5. Buat file /var/tmp/docker-entrypoint-initdb.d/init-pitr-demo-db.sql untuk membuat kumpulan tabel sederhana dalam database dan skema demonstrasi.
  6. Buat dan mulai layanan systemd kedua (wal_archive.service) yang menjalankan container Docker Google Cloud CLI dengan disk WAL yang dipasang sebagai volume. Layanan ini mencadangkan file WAL yang diarsipkan ke Cloud Storage.
  7. Buat, aktifkan, lalu mulai timer systemd (wal_archive.timer) yang menjalankan wal_archive.servicesecara berkala.
  8. Pastikan port PostgreSQL (5432) terbuka untuk subnet VPC sehingga generator transaksi dapat mencapai port database.

Mengubah konfigurasi instance database

Server database sedang berjalan, tetapi Anda perlu mengonfigurasi akses jaringan, dan memulai proses pengarsipan WAL.

Menghubungkan ke instance VM database

  1. Di Konsol Google Cloud, buka halaman Instance VM.

    Buka instance VM

  2. Untuk membuka shell terminal, di samping instance instance-pg-pitr yang Anda buat, klik SSH.

  3. Di shell terminal, pastikan container Docker telah dimulai: docker ps

    Outputnya mirip dengan yang berikut ini:

    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
    

    Jika penampung belum berjalan, tunggu beberapa saat, lalu gunakan perintah yang sama untuk memeriksa lagi.

Mengizinkan koneksi jaringan masuk ke database

  1. Di shell terminal instance instance-pg-pitr buka file konfigurasi autentikasi berbasis host PostgreSQL untuk mengedit:

    sudoedit /mnt/disks/data/pgdata/pg_hba.conf
    
  2. Untuk menghapus semua akses alamat IP default ke database, jadikan sebagai komentar baris berikut dari akhir file dengan menambahkan # pada awal baris. Baris dalam file terlihat mirip dengan berikut ini:

    #host all all all md5
    
  3. Untuk mengizinkan koneksi yang dilindungi sandi dari host dalam blok CIDR 10.0.0.0/8 tambahkan baris berikut pada akhir file:

    host    all             all             10.0.0.0/8               md5
    

    Entri ini mengaktifkan konektivitas dari subnet VPC tempat generator transaksi nantinya akan dibuat.

  4. Simpan, lalu tutup file tersebut.

Konfigurasikan pengarsipan WAL

  1. Di shell terminal instance instance-pg-pitr, edit file postgresql.conf:

    sudoedit /mnt/disks/data/pgdata/postgresql.conf
    
  2. Ganti baris archive_mode, archive_command, dan archive_timeout yang sudah dijadikan sebagai komentar dengan baris berikut:

    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
    

    Saat Anda mengganti baris dalam file yang diubah, baris tersebut akan terlihat mirip dengan cuplikan kode berikut:

    
    .... 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. Simpan, lalu tutup file tersebut.

Menerapkan dan memverifikasi perubahan konfigurasi

  1. Di shell terminal instance instance-pg-pitr, mulai ulang container untuk menerapkan perubahan:

    sudo systemctl restart postgres
    
  2. Periksa file segmen WAL:

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

    Outputnya mirip dengan yang berikut ini:

    total 16388
    -rw------- 1 postgres 70 16777216 Sep  5 23:07 000000010000000000000001
    drwx------ 2 postgres 70     4096 Sep  5 23:05 archive_status
    
  3. Periksa konektivitas jaringan ke database:

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

    Outputnya mirip dengan yang berikut ini:

    ?column?
    ----------
           1
    (1 row)
    
  4. Tutup koneksi SSH ke instance.

Memulai transaksi generator untuk mengisi database

Langkah-langkah berikut memulai Mulai program yang menghasilkan transaksi untuk tutorial ini. Program ini berjalan di dalam container pada instance VM.

Image untuk container sudah di-build dan dihosting di project dengan Container Registry public.

  1. Di Cloud Shell, ubah ke direktori generator transaksi:

    cd ~/gcs-postgresql-recovery-tutorial/bin
    
  2. Tetapkan variabel lingkungan:

    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. Untuk menjalankan generator transaksi, mulai instance:

    ./run_trans_gen_instance.sh
    

    Abaikan pesan peringatan tentang performa I/O yang buruk.

  4. Tunggu beberapa saat, dan periksa apakah transaksi mencapai 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;'"
    

    Output-nya berisi jumlah yang lebih besar dari 0 ketika record ditambahkan ke database oleh generator transaksi:

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

Mengonfigurasi jadwal pencadangan snapshot biner

Anda dapat mencadangkan persistent disk sesuai jadwal, dan menyimpannya selama waktu yang ditentukan dalam kebijakan resource.

Membuat jadwal snapshot

  1. Di Cloud Shell, tetapkan variabel lingkungan:

    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
    

    Ganti zone-of-your-instance dengan zona Google Cloud tempat Anda memulai VM database sebelumnya.

  2. Buat jadwal 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
    

Memasang jadwal snapshot ke disk

Saat Anda menjalankan skrip untuk membuat instance, volume data dan WAL dibuat sebagai dua persistent disk independen. Untuk membuat snapshot persistent disk sesuai dengan jadwal yang ditentukan, Anda harus mengaitkan kebijakan resource dengan setiap persistent disk. Dalam hal ini, Anda ingin snapshot disk terjadi secara bersamaan, sehingga gunakan kebijakan yang sama untuk kedua persistent disk yang terpasang ke VM Compute Engine.

  1. Di Cloud Shell, tetapkan variabel lingkungan:

    export SNAPSHOT_SCHEDULE_NAME=pgdata-disk-schedule
    export PG_INSTANCE_NAME=instance-pg-pitr
    export ZONE=zone-of-your-instance
    
  2. Tambahkan kebijakan jadwal ke persistent data disk:

    gcloud beta compute disks add-resource-policies ${PG_INSTANCE_NAME}-data \
        --resource-policies $SNAPSHOT_SCHEDULE_NAME \
        --zone $ZONE
    
  3. Tambahkan kebijakan jadwal ke persistent WAL disk:

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

Menjalankan snapshot secara manual

(Opsional) Snapshot terjadwal terjadi dalam periode penjadwalan, sehingga snapshot tidak mungkin diambil langsung saat Anda membuat jadwal. Jika Anda tidak ingin menunggu snapshot terjadwal, Anda dapat menjalankan snapshot awal secara manual.

  1. Di Cloud Shell, tetapkan variabel lingkungan:

    export ZONE=zone-of-your-instance
    export PG_INSTANCE_NAME=instance-pg-pitr
    export REGION=${ZONE%-[a-z]}
    
  2. Buat snapshot dua persistent disk instance 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. Lihat snapshot yang Anda buat:

    gcloud compute snapshots list
    

    Outputnya mirip dengan yang berikut ini:

    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
    

Menjalankan PITR

PITR sering dilakukan untuk memulihkan data yang hilang akibat kesalahan langkah operasional atau terprogram.

Di bagian tutorial ini, Anda akan menjalankan update database untuk menyimulasikan hilangnya data dalam jumlah besar. Kemudian, Anda akan menyimulasikan respons panik, sebelum memulai pemulihan hingga waktu sebelum perintah yang salah dikeluarkan.

Memastikan bahwa PITR dapat dilakukan

Sebelum melakukan PITR, Anda harus memberikan cukup waktu untuk menjalankan hal-hal berikut:

  • Pencadangan biner (snapshot disk)
  • Pengarsipan WAL

Untuk tutorial ini, archive_timeout disetel ke nilai yang cukup rendah, yaitu 120 detik untuk memaksa rotasi file WAL yang sering. Anda juga harus menunggu hingga setidaknya satu snapshot disk terjadwal dijalankan, atau Anda harus membuat snapshot disk secara manual.

  1. Pastikan setidaknya satu snapshot telah diambil:

    1. Di konsol Google Cloud, buka halaman Snapshots.

      Buka halaman Snapshots

    2. Pastikan setidaknya ada dua snapshot—satu untuk volume data dan satu untuk volume WAL, misalnya, instance-pg-pitr--us-central1-a-20190805023535-i3hpw7kn.

  2. Periksa apakah file segmen diarsipkan ke Cloud Storage:

    1. Di konsol Google Cloud, buka halaman Browser Cloud Storage.

      Membuka halaman Browser Cloud Storage

    2. Klik archive-bucket.

      Bucket Cloud Storage yang berisi objek.

Merusak data

Untuk menyimulasikan hilangnya data dalam jumlah besar, buka shell command line ke database PostgreSQL, dan rusakkan data dalam tabel yang diisi oleh generator transaksi.

  1. Di Konsol Google Cloud, buka halaman Instance VM.

    Buka halaman Instance VM

  2. Untuk instance instance-pg-pitr, click SSH.

  3. Di terminal SSH, jalankan frontend berbasis terminal PostgreSQL di Docker container:

    docker exec -it postgres-db psql --dbname=pitr_demo
    
  4. Untuk mengubah baris dalam tabel pelanggan, kirimkan pernyataan DML SQL dengan salah ketik yang disengaja di shell PostgreSQL:

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

    Outputnya mirip dengan yang berikut ini:

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

    Error terjadi karena titik koma tambahan dimasukkan sebelum klausa WHERE. Semua baris dalam database telah diperbarui. Sekarang Anda dapat melakukan PITR untuk memulihkan baris dengan pernyataan salah yang telah dimodifikasi.

Menentukan waktu target pemulihan

Langkah pertama pada PITR adalah menentukan waktu target pemulihan. Waktu ini ditentukan dengan memeriksa data Anda untuk mengidentifikasi titik tertentu sebelum peristiwa kerusakan data.

  1. Di shell terminal instance instance-pg-pitr, dapatkan stempel waktu maksimum baris yang rusak:

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

    Outputnya mirip dengan yang berikut ini:

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

    Dalam database produksi, kueri untuk menentukan target pemulihan lebih kompleks, terutama jika tabel yang terpengaruh berukuran besar, dan kolom indikatif tidak diindeks.

  2. Salin hasilnya; Anda akan menggunakan nilai yang dikembalikan oleh kueri ini di langkah berikutnya.

Memulihkan database

Untuk tutorial ini, skrip pemulihan mengotomatiskan PITR. Sebaiknya Anda memiliki proses otomatis untuk memulihkan database dan menguji proses ini secara berkala.

  1. Di Cloud Shell, ubah direktori kerja saat ini ke lokasi skrip pemulihan:

    cd ~/gcs-postgresql-recovery-tutorial/bin
    
  2. Tetapkan variabel lingkungan yang diperlukan untuk skrip. Ganti YYYY-MM-DD HH:MM:SS.999999+00 dengan output kueri yang sebelumnya Anda salin.

    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. Jalankan skrip pemulihan:

    ./recover_to_point_in_time.sh
    

Memahami skrip pemulihan

Bagian ini memberikan beberapa detail tentang parameter input dan langkah-langkah yang dilakukan oleh skrip.

Skrip ini mengharuskan untuk menetapkan variabel lingkungan berikut:

  • PIT_RECOVERY_TARGET: waktu target pemulihan.
  • PROJECT_ID: project tempat PG_INSTANCE_NAME instance berada.
  • ZONE: zona tempat PG_INSTANCE_NAME instance berada.
  • PG_INSTANCE_NAME: instance tempat instance PostgreSQL produksi berjalan.
  • RECOVER_BUCKET: bucket Cloud Storage tempat file segmen WAL diarsipkan.
  • POSTGRES_PASSWORD: sandi yang digunakan untuk pengguna database PostgreSQL.

Skrip akan melakukan langkah-langkah berikut:

  1. Menentukan snapshot disk terbaru berdasarkan tanggal dan waktu target pemulihan.
  2. Membuat file cloud-init.yaml yang diberikan ke VM penyimpanan yang dioptimalkan untuk container yang menjalankan database PITR. File cloud-init.yaml membuat file konfigurasi dan menjalankan beberapa perintah sistem untuk membangun lingkungan berikut:

    • Container gcsfuse yang memasang bucket arsip file segmen WAL sebagai volume yang kemudian diekspos ke host dengan pemasangan Docker.
    • Container postgres-dbtempat mesin database menjalankan hal berikut:

      • Sistem file host tempat persistent disk dipasang sebagai volume.
      • Sistem file host tempat bucket Cloud Storage dipasang sebagai volume.
    • File pemulihan recovery.conf di direktori data PostgreSQL dengan informasi berikut:

      • Tanggal target.
      • Perintah restore perintah salin berparameter yang digunakan database untuk menyalin file segmen WAL sesuai kebutuhan dari sistem file arsip. %f adalah file segmen dan %p adalah jalur yang digunakan oleh database untuk memproses file selama pemulihan.
    • Setelan archive_ dikomentari dari file setelan postgresql.conf untuk menghindari kerusakan direktori arsip WAL.

  3. Memulai instance PITR dengan informasi berikut:

    • Nama yang dibuat dengan menggabungkan variabel lingkungan $PG_INSTANCE_NAME dan nilai alfanumerik dari variabel lingkungan $PIT_RECOVERY_TARGET.
    • Persistent disk yang dibuat dari snapshot disk yang diidentifikasi sebelumnya.

Berikut adalah contoh 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

Memvalidasi pemulihan

  1. Di Konsol Google Cloud, buka halaman Instance VM.

    Buka halaman Instance VM

  2. Untuk instance instance-pg-pitr-YYYYMMDDHHMMSS, klik SSH.

  3. Di terminal SSH, jalankan frontend berbasis terminal PostgreSQL di container Docker:

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

    Jika Anda mendapatkan error berikut, tunggu beberapa saat hingga container PostgreSQL dimulai, lalu jalankan kembali perintah:

    Error: No such container: postgres-db
    
  4. Periksa data di tabel pelanggan:

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

    Outputnya mirip dengan yang berikut ini:

       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
    

    Nama menunjukkan nilai yang dibuat oleh generator transaksi. Baris terakhir memiliki stempel waktu yang lebih awal dari target pemulihan (yang Anda berikan ke skrip pemulihan dalam variabel lingkungan). Bergantung pada jumlah data yang perlu dipulihkan, Anda mungkin harus menunggu beberapa saat sampai semua baris diperbarui.

Pembersihan

Cara termudah untuk menghilangkan penagihan adalah dengan menghapus project Google Cloud yang Anda buat untuk tutorial. Atau, Anda dapat menghapus resource satu per satu.

Menghapus project

  1. Di konsol Google Cloud, buka halaman Manage resource.

    Buka Manage resource

  2. Pada daftar project, pilih project yang ingin Anda hapus, lalu klik Delete.
  3. Pada dialog, ketik project ID, lalu klik Shut down untuk menghapus project.

Langkah berikutnya