WAL-G: pencadangan dan pemulihan DBMS PostgreSQL

Sudah lama diketahui bahwa membuat cadangan ke dalam dump SQL (menggunakan hal_dump или pg_dumpal) bukanlah ide yang bagus. Untuk membuat cadangan DBMS PostgreSQL, lebih baik menggunakan perintah pg_basebackup, yang membuat salinan biner log WAL. Tetapi ketika Anda mulai mempelajari seluruh proses pembuatan salinan dan pemulihan, Anda akan memahami bahwa Anda perlu menulis setidaknya beberapa sepeda roda tiga agar ini berfungsi dan tidak membuat Anda kesakitan baik di atas maupun di bawah. Untuk meringankan penderitaan, WAL-G dikembangkan.

WAL-G adalah alat yang ditulis dalam Go untuk membuat cadangan dan memulihkan database PostgreSQL (dan yang terbaru MySQL/MariaDB, MongoDB dan FoundationDB). Ini mendukung bekerja dengan penyimpanan Amazon S3 (dan analognya, misalnya, Yandex Object Storage), serta Google Cloud Storage, Azure Storage, Swift Object Storage dan hanya dengan sistem file. Keseluruhan pengaturannya dilakukan dengan langkah-langkah sederhana, namun karena artikel tentangnya tersebar di Internet, tidak ada panduan lengkap yang mencakup semua langkah dari awal hingga akhir (ada beberapa postingan di Habré, tetapi banyak poin yang terlewat di sana).

WAL-G: pencadangan dan pemulihan DBMS PostgreSQL

Artikel ini ditulis terutama untuk mensistematisasikan pengetahuan saya. Saya bukan seorang DBA dan saya dapat mengekspresikan diri saya dalam bahasa awam di suatu tempat, jadi segala koreksi dipersilakan!

Secara terpisah, saya perhatikan bahwa semua yang di bawah ini relevan dan diuji untuk PostgreSQL 12.3 di Ubuntu 18.04, semua perintah harus dijalankan sebagai pengguna yang memiliki hak istimewa.

Instalasi

Pada saat artikel ini ditulis, versi stabil WAL-G adalah v0.2.15 (Maret 2020). Inilah yang akan kita gunakan (tetapi jika Anda ingin membuatnya sendiri dari cabang master, maka repositori github memiliki semua instruksi untuk ini). Untuk mengunduh dan menginstal, Anda perlu melakukan:

#!/bin/bash

curl -L "https://github.com/wal-g/wal-g/releases/download/v0.2.15/wal-g.linux-amd64.tar.gz" -o "wal-g.linux-amd64.tar.gz"
tar -xzf wal-g.linux-amd64.tar.gz
mv wal-g /usr/local/bin/

Setelah ini, Anda perlu mengkonfigurasi WAL-G terlebih dahulu, lalu PostgreSQL itu sendiri.

Menyiapkan WAL-G

Sebagai contoh penyimpanan cadangan, Amazon S3 akan digunakan (karena lebih dekat dengan server saya dan penggunaannya sangat murah). Untuk menggunakannya, Anda memerlukan "ember s3" dan kunci akses.

Semua artikel sebelumnya tentang WAL-G menggunakan konfigurasi menggunakan variabel lingkungan, tetapi dengan rilis ini pengaturannya dapat ditemukan File .walg.json di direktori home pengguna postgres. Untuk membuatnya, jalankan skrip bash berikut:

#!/bin/bash

cat > /var/lib/postgresql/.walg.json << EOF
{
    "WALG_S3_PREFIX": "s3://your_bucket/path",
    "AWS_ACCESS_KEY_ID": "key_id",
    "AWS_SECRET_ACCESS_KEY": "secret_key",
    "WALG_COMPRESSION_METHOD": "brotli",
    "WALG_DELTA_MAX_STEPS": "5",
    "PGDATA": "/var/lib/postgresql/12/main",
    "PGHOST": "/var/run/postgresql/.s.PGSQL.5432"
}
EOF
# обязательно меняем владельца файла:
chown postgres: /var/lib/postgresql/.walg.json

Izinkan saya menjelaskan sedikit tentang semua parameter:

  • WALG_S3_PREFIX – jalur ke bucket S3 tempat cadangan akan diunggah (Anda bisa ke root atau ke folder);
  • AWS_ACCESS_KEY_ID – kunci akses di S3 (dalam hal pemulihan di server pengujian, kunci ini harus memiliki Kebijakan ReadOnly! Hal ini dijelaskan secara lebih rinci di bagian pemulihan.);
  • AWS_SECRET_ACCESS_KEY – kunci rahasia dalam penyimpanan S3;
  • WALG_COMPRESSION_METHOD – metode kompresi, lebih baik menggunakan Brotli (karena ini adalah titik tengah antara ukuran akhir dan kecepatan kompresi/dekompresi);
  • WALG_DELTA_MAX_STEPS – jumlah “delta” sebelum membuat cadangan penuh (menghemat waktu dan ukuran data yang diunduh, namun dapat sedikit memperlambat proses pemulihan, jadi tidak disarankan untuk menggunakan nilai yang besar);
  • PGDATA – jalur ke direktori dengan data database Anda (Anda dapat mengetahuinya dengan menjalankan perintah pg_lscluster);
  • PGHOST – menghubungkan ke database, dengan cadangan lokal lebih baik dilakukan melalui unix-socket seperti pada contoh ini.

Parameter lain dapat ditemukan di dokumentasi: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Konfigurasi PostgreSQL

Agar pengarsip di dalam database dapat mengunggah log WAL ke cloud dan memulihkannya (jika perlu), Anda perlu mengatur beberapa parameter dalam file konfigurasi /etc/postgresql/12/main/postgresql.conf. Hanya sebagai permulaan kamu perlu memastikannyabahwa tidak ada pengaturan di bawah ini yang diatur ke nilai lain, sehingga ketika konfigurasi dimuat ulang, DBMS tidak mengalami crash. Anda dapat menambahkan parameter ini menggunakan:

#!/bin/bash

echo "wal_level=replica" >> /etc/postgresql/12/main/postgresql.conf
echo "archive_mode=on" >> /etc/postgresql/12/main/postgresql.conf
echo "archive_command='/usr/local/bin/wal-g wal-push "%p" >> /var/log/postgresql/archive_command.log 2>&1' " >> /etc/postgresql/12/main/postgresql.conf
echo “archive_timeout=60” >> /etc/postgresql/12/main/postgresql.conf
echo "restore_command='/usr/local/bin/wal-g wal-fetch "%f" "%p" >> /var/log/postgresql/restore_command.log 2>&1' " >> /etc/postgresql/12/main/postgresql.conf

# перезагружаем конфиг через отправку SIGHUP сигнала всем процессам БД
killall -s HUP postgres

Deskripsi parameter yang akan diatur:

  • tingkat_wal – berapa banyak informasi yang harus ditulis di log WAL, “replika” – tulis semuanya;
  • mode_arsip – aktifkan pengunduhan log WAL menggunakan perintah dari parameter arsip_perintah;
  • arsip_perintah – perintah untuk mengarsipkan log WAL yang telah selesai;
  • waktu_arsip habis – pengarsipan log dilakukan hanya setelah selesai, tetapi jika server Anda mengubah/menambahkan sedikit data ke database, maka masuk akal untuk menetapkan batas di sini dalam hitungan detik, setelah itu perintah pengarsipan akan dipanggil secara paksa (Saya menulis secara intensif ke database setiap detik, jadi saya memutuskan untuk tidak menyetel parameter ini dalam produksi);
  • pulihkan_perintah – perintah untuk memulihkan log WAL dari cadangan akan digunakan jika “cadangan penuh” (cadangan dasar) tidak memiliki perubahan terbaru dalam database.

Anda dapat membaca lebih lanjut tentang semua parameter ini dalam terjemahan dokumentasi resmi: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Menyiapkan jadwal cadangan

Suka atau tidak, cara paling mudah untuk menjalankannya adalah cron. Inilah yang akan kami konfigurasikan untuk membuat cadangan. Mari kita mulai dengan perintah untuk membuat cadangan penuh: di wal-g ini adalah argumen peluncuran dorongan cadangan. Namun pertama-tama, lebih baik menjalankan perintah ini secara manual dari pengguna postgres untuk memastikan semuanya baik-baik saja (dan tidak ada kesalahan akses):

#!/bin/bash

su - postgres -c '/usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main'

Argumen peluncuran menunjukkan jalur ke direktori data - Saya ingatkan Anda bahwa Anda dapat mengetahuinya dengan menjalankannya pg_lscluster.

Jika semuanya berjalan tanpa kesalahan dan data dimuat ke penyimpanan S3, Anda dapat mengonfigurasi peluncuran berkala di crontab:

#!/bin/bash

echo "15 4 * * *    /usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main >> /var/log/postgresql/walg_backup.log 2>&1" >> /var/spool/cron/crontabs/postgres
# задаем владельца и выставляем правильные права файлу
chown postgres: /var/spool/cron/crontabs/postgres
chmod 600 /var/spool/cron/crontabs/postgres

Dalam contoh ini, proses pencadangan dimulai setiap hari pada pukul 4.

Menghapus cadangan lama

Kemungkinan besar, Anda tidak perlu menyimpan semua cadangan dari era Mesozoikum, jadi akan berguna untuk “membersihkan” penyimpanan Anda secara berkala (baik “cadangan penuh” dan log WAL). Kami akan melakukan ini semua melalui tugas cron:

#!/bin/bash

echo "30 6 * * *    /usr/local/bin/wal-g delete before FIND_FULL $(date -d '-10 days' '+%FT%TZ') --confirm >> /var/log/postgresql/walg_delete.log 2>&1" >> /var/spool/cron/crontabs/postgres
# ещё раз задаем владельца и выставляем правильные права файлу (хоть это обычно это и не нужно повторно делать)
chown postgres: /var/spool/cron/crontabs/postgres
chmod 600 /var/spool/cron/crontabs/postgres

Cron akan menjalankan tugas ini setiap hari pada pukul 6:30 pagi, menghapus semuanya (cadangan penuh, delta, dan WAL) kecuali salinan selama 10 hari terakhir, tetapi menyisakan setidaknya satu cadangan untuk tanggal yang ditentukan sehingga titik mana pun setelah tanggal dimasukkan dalam PITR.

Memulihkan dari cadangan

Bukan rahasia lagi bahwa kunci database yang sehat adalah pemulihan berkala dan verifikasi integritas data di dalamnya. Saya akan memberi tahu Anda cara memulihkan menggunakan WAL-G di bagian ini, dan kita akan membicarakan pemeriksaannya nanti.

Ini harus dicatat secara terpisah bahwa untuk memulihkan di lingkungan pengujian (segala sesuatu yang bukan produksi) Anda perlu menggunakan akun Read Only di S3 agar tidak menimpa cadangan secara tidak sengaja. Dalam kasus WAL-G, Anda perlu mengatur hak berikut untuk pengguna S3 di Kebijakan Grup (Efek: Izinkan): s3:DapatkanObjek, s3:ListBucket, s3:DapatkanBucketLocation. Dan tentunya jangan lupa untuk mengaturnya archive_mode=mati di file pengaturan postgresql.conf, sehingga database pengujian Anda tidak ingin dicadangkan secara diam-diam.

Pemulihan dilakukan dengan sedikit gerakan tangan menghapus semua data PostgreSQL (termasuk pengguna), jadi harap berhati-hati saat menjalankan perintah berikut.

#!/bin/bash

# если есть балансировщик подключений (например, pgbouncer), то вначале отключаем его, чтобы он не нарыгал ошибок в лог
service pgbouncer stop
# если есть демон, который перезапускает упавшие процессы (например, monit), то останавливаем в нём процесс мониторинга базы (у меня это pgsql12)
monit stop pgsql12
# или останавливаем мониторинг полностью
service monit stop
# останавливаем саму базу данных
service postgresql stop
# удаляем все данные из текущей базы (!!!); лучше предварительно сделать их копию, если есть свободное место на диске
rm -rf /var/lib/postgresql/12/main
# скачиваем резервную копию и разархивируем её
su - postgres -c '/usr/local/bin/wal-g backup-fetch /var/lib/postgresql/12/main LATEST'
# помещаем рядом с базой специальный файл-сигнал для восстановления (см. https://postgrespro.ru/docs/postgresql/12/runtime-config-wal#RUNTIME-CONFIG-WAL-ARCHIVE-RECOVERY ), он обязательно должен быть создан от пользователя postgres
su - postgres -c 'touch /var/lib/postgresql/12/main/recovery.signal'
# запускаем базу данных, чтобы она инициировала процесс восстановления
service postgresql start

Bagi yang ingin mengecek proses recovery, telah disiapkan sedikit bash magic di bawah ini, sehingga jika terjadi masalah dalam recovery, script akan crash dengan kode keluar yang bukan nol. Dalam contoh ini, 120 pemeriksaan dilakukan dengan batas waktu 5 detik (total 10 menit untuk pemulihan) untuk mengetahui apakah file sinyal telah dihapus (ini berarti pemulihan berhasil):

#!/bin/bash

CHECK_RECOVERY_SIGNAL_ITER=0
while [ ${CHECK_RECOVERY_SIGNAL_ITER} -le 120 ]
do
    if [ ! -f "/var/lib/postgresql/12/main/recovery.signal" ]
    then
        echo "recovery.signal removed"
        break
    fi
    sleep 5
    ((CHECK_RECOVERY_SIGNAL_ITER+1))
done

# если после всех проверок файл всё равно существует, то падаем с ошибкой
if [ -f "/var/lib/postgresql/12/main/recovery.signal" ]
then
    echo "recovery.signal still exists!"
    exit 17
fi

Setelah pemulihan berhasil, jangan lupa untuk memulai kembali semua proses (pgbouncer/monit, dll).

Memeriksa data setelah pemulihan

Sangat penting untuk memeriksa integritas database setelah restorasi, sehingga situasi dengan cadangan yang rusak/bengkok tidak muncul. Dan lebih baik melakukan ini dengan setiap arsip yang dibuat, tetapi di mana dan bagaimana hanya bergantung pada imajinasi Anda (Anda dapat meningkatkan server individual setiap jam atau menjalankan pemeriksaan di CI). Namun minimal perlu dilakukan pengecekan data dan indeks pada database.

Untuk memeriksa data, cukup menjalankannya melalui dump, tetapi lebih baik saat membuat database Anda mengaktifkan checksum (checksum data):

#!/bin/bash

if ! su - postgres -c 'pg_dumpall > /dev/null'
then
    echo 'pg_dumpall failed'
    exit 125
fi

Untuk memeriksa indeks - ada modul amcheck, mari kita ambil kueri sqlnya tes WAL-G dan membangun sedikit logika di sekitarnya:

#!/bin/bash

# добавляем sql-запрос для проверки в файл во временной директории
cat > /tmp/amcheck.sql << EOF
CREATE EXTENSION IF NOT EXISTS amcheck;
SELECT bt_index_check(c.oid), c.relname, c.relpages
FROM pg_index i
JOIN pg_opclass op ON i.indclass[0] = op.oid
JOIN pg_am am ON op.opcmethod = am.oid
JOIN pg_class c ON i.indexrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE am.amname = 'btree'
AND c.relpersistence != 't'
AND i.indisready AND i.indisvalid;
EOF
chown postgres: /tmp/amcheck.sql

# добавляем скрипт для запуска проверок всех доступных баз в кластере
# (обратите внимание что переменные и запуск команд – экранированы)
cat > /tmp/run_amcheck.sh << EOF
for DBNAME in $(su - postgres -c 'psql -q -A -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;" ')
do
    echo "Database: ${DBNAME}"
    su - postgres -c "psql -f /tmp/amcheck.sql -v 'ON_ERROR_STOP=1' ${DBNAME}" && EXIT_STATUS=$? || EXIT_STATUS=$?
    if [ "${EXIT_STATUS}" -ne 0 ]
    then
        echo "amcheck failed on DB: ${DBNAME}"
        exit 125
    fi
done
EOF
chmod +x /tmp/run_amcheck.sh

# запускаем скрипт
/tmp/run_amcheck.sh > /tmp/amcheck.log

# для проверки что всё прошло успешно можно проверить exit code или grep’нуть ошибку
if grep 'amcheck failed' "/tmp/amcheck.log"
then
    echo 'amcheck failed: '
    cat /tmp/amcheck.log
    exit 125
fi

Meringkas

Saya ingin mengucapkan terima kasih kepada Andrey Borodin atas bantuannya dalam mempersiapkan publikasi dan terima kasih khusus atas kontribusinya terhadap pengembangan WAL-G!

Ini menyimpulkan catatan ini. Saya harap saya dapat menyampaikan kemudahan pengaturan dan potensi besar penggunaan alat ini di perusahaan Anda. Saya mendengar banyak tentang WAL-G, tapi tidak pernah punya cukup waktu untuk duduk dan memikirkannya. Dan setelah saya terapkan di rumah, keluarlah artikel ini dari saya.

Secara terpisah, perlu dicatat bahwa WAL-G juga dapat bekerja dengan DBMS berikut:

Sumber: www.habr.com

Tambah komentar