PostgreSQL hadir dengan kemampuan untuk melakukan pencadangan tambahan dan pemulihan tepat waktu. Baca terus untuk mempelajari lebih lanjut tentang pengaturan dan prosedur untuk mencapai ini.
Ini Dimulai Dengan File WAL
WAL singkatan dari Write Ahead Log . WAL digunakan di hampir semua sistem RDBMS modern untuk menyediakan transaksi yang tahan lama dan atomik.
Perubahan pada data yang terkandung dalam cluster database PostgreSQL yang dikelola oleh satu proses server PostgreSQL hanya dimungkinkan melalui transaksi. Modifikasi yang dilakukan pada data dengan transaksi dicatat sebagai urutan berurutan dari catatan WAL . Catatan ini ditulis ke dalam file dengan panjang tetap yang disebut file segmen WAL , atau cukup file WAL .
File WAL tinggal di $PGDATA/pg_wal
, di mana $PGDATA
adalah direktori data untuk cluster database. Pada instalasi Debian default misalnya, direktori file WAL untuk cluster utama adalah /var/lib/postgresql/10/main/pg_wal
. Berikut tampilannya:
# pwd
/var/lib/postgresql/10/main/pg_wal
# ls -l
total 278532
-rw------- 1 postgres postgres 16777216 May 7 08:48 00000001000000000000000B
-rw------- 1 postgres postgres 16777216 May 7 10:08 00000001000000000000000C
-rw------- 1 postgres postgres 16777216 May 7 10:08 00000001000000000000000D
-rw------- 1 postgres postgres 16777216 May 7 10:08 00000001000000000000000E
-rw------- 1 postgres postgres 16777216 May 7 10:08 00000001000000000000000F
-rw------- 1 postgres postgres 16777216 May 7 10:08 000000010000000000000010
-rw------- 1 postgres postgres 16777216 May 7 10:08 000000010000000000000011
-rw------- 1 postgres postgres 16777216 May 7 10:08 000000010000000000000012
-rw------- 1 postgres postgres 16777216 May 7 10:08 000000010000000000000013
-rw------- 1 postgres postgres 16777216 May 7 10:08 000000010000000000000014
-rw------- 1 postgres postgres 16777216 May 7 10:08 000000010000000000000015
-rw------- 1 postgres postgres 16777216 May 7 10:08 000000010000000000000016
-rw------- 1 postgres postgres 16777216 May 7 10:08 000000010000000000000017
-rw------- 1 postgres postgres 16777216 May 16 20:52 000000010000000000000018
-rw------- 1 postgres postgres 16777216 May 16 20:56 000000010000000000000019
-rw------- 1 postgres postgres 16777216 May 26 08:52 00000001000000000000001A
-rw------- 1 postgres postgres 16777216 Jun 2 09:59 00000001000000000000001B
drwx------ 2 postgres postgres 4096 Mar 30 10:06 archive_status
File WAL dihasilkan secara bertahap, secara berurutan, mulai dari pembuatan cluster. Mereka terus dihasilkan selama modifikasi terjadi pada cluster. Mekanisme file WAL sangat penting untuk kerja PostgreSQL, dan tidak dapat dimatikan.
Setelah perubahan pertama kali ditulis sebagai catatan WAL, perubahan tersebut harus diterapkan pada representasi data itu sendiri pada disk. Proses ini disebutpemeriksaan , dan terjadi di latar belakang secara otomatis (bisa juga dipaksakan secara manual). Titik sampai pemeriksaan dilakukan disebuttitik REDO . Pos pemeriksaan juga merupakan bagian penting dari arsitektur Postgres dan tidak dapat dimatikan.
Retensi File WAL
Dalam operasi normal server PostgreSQL, file WAL akan terus ditulis ke dalam pg_wal
direktori. Tapi mengapa mereka ada di sekitar?
Salah satu alasannya adalah pemulihan kerusakan. Jika server PostgreSQL mogok dan dimulai ulang, ia mulai menerapkan perubahan dari catatan WAL ke dalam file data (pos pemeriksaan) sejak titik REDO terakhir. Ini menjamin bahwa file data konsisten dengan transaksi terakhir yang diselesaikan.
Alasan lain terkait dengan replikasi streaming. Replikasi streaming bekerja dengan mengirimkan catatan WAL ke siaga server, yang menyimpan ini secara lokal dan melakukan pos pemeriksaan. Siaga dapat tertinggal dari server tempat mereka mereplikasi (disebut utama ). Misalnya, jika primer telah menghasilkan 100 catatan WAL dan standby telah menerima dan menerapkan 80 yang pertama, yang terbaru20 harus tersedia sehingga standby dapat menerima dan menerapkan dari record 81 dan seterusnya.
Tapi pasti file WAL yang sangat lama bisa dihapus kan? Ya. PostgreSQL dapat diinstruksikan untuk menyimpan file WAL terbaru dan menghapus yang lama. Ada tiga opsi konfigurasi yang relevan:
- wal_keep_segments - menetapkan jumlah minimum file WAL terbaru untuk disimpan di direktori file WAL
- max_wal_size - menentukan ukuran total maksimum file WAL di direktori file WAL. Jika ini terlampaui, yang lebih lama akan dihapus. Namun, mungkin ada alasan (termasuk nilai tinggi untuk
wal_keep_segments
) yang dapat mencegah pengaturan ini dihormati. - min_wal_size - menentukan ukuran total minimum untuk file WAL. Selama ukuran sebenarnya tetap di bawah nilai ini, tidak ada file yang akan dihapus.
Dalam kehidupan nyata tidak mungkin, atau diperlukan, untuk menyimpan semua file WAL sebelumnya di bawah pg_wal
direktori.
Arsip Berkas WAL
Nilai sebenarnya dari file WAL adalah bahwa mereka adalah aliran perubahan yang dapat direkam dan diputar ulang untuk mendapatkan replika yang konsisten dari cluster PostgreSQL. PostgreSQL menyediakan cara untuk menyalin (atau "mengarsipkan") setiap file WAL setelah mendapatkannya dibuat – archive_command opsi konfigurasi.
Opsi ini menentukan string perintah shell yang dipanggil setelah setiap file WAL dibuat. Berikut beberapa contohnya:
# Copy the file to a safe location (like a mounted NFS volume)
archive_command = 'cp %p /mnt/nfs/%f'
# Not overwriting files is a good practice
archive_command = 'test ! -f /mnt/nfs/%f && cp %p /mnt/nfs/%f'
# Copy to S3 bucket
archive_command = 's3cmd put %p s3://BUCKET/path/%f'
# Copy to Google Cloud bucket
archive_command = 'gsutil cp %p gs://BUCKET/path/%f'
# An external script
archive_command = '/opt/scripts/archive_wal %p'
Ada 2 opsi lain juga, yang harus diset:
# this must be "on" to enable WAL archiving
archive_mode = on
# has to be "replica" (default) or "logical" for WAL archiving
wal_level = replica
Kompresi WAL
Anda dapat mengompres file WAL sebelum menyalinnya ke lokasi penyimpanan jangka panjang/aman. Namun, ada opsi yang disebut wal_compression . Mengaktifkan ini akan menyebabkan PostgreSQL mengompresi catatan WAL individual di dalam file WAL. File WAL itu sendiri akan berukuran sama (biasanya 16 MB), tetapi akan berisi urutan catatan terkompresi daripada catatan biasa.
Pengarsipan Berkelanjutan
Pengarsipan WAL juga disebut pengarsipan berkelanjutan dan berlaku,pencadangan tambahan .
Sebelum memulai proses pencadangan inkremental ini, diperlukan pencadangan lengkap. Ini menetapkan dasar di mana file WAL dapat dipulihkan secara bertahap. Cadangan lengkap dapat dilakukan dengan:
- mematikan proses server Postgres dan menyalin direktori data cluster (sambil mempertahankan izin), atau
- menggunakan
pg_basebackup
di server Postgres yang sedang berjalan.
Pemulihan Titik-Dalam-Waktu (PITR)
PITR mengacu pada kemampuan PostgreSQL untuk memulai dari pemulihan cadangan penuh, kemudian secara bertahap mengambil dan menerapkan file WAL yang diarsipkan hingga stempel waktu yang ditentukan.
Untuk melakukan ini, kita harus membuat file bernama “recovery.conf” di direktori data kluster yang dipulihkan dan memulai server Postgres untuk direktori data tersebut. File recovery.conf berisi stempel waktu target, dan terlihat seperti ini:
restore_command = 'cp /tmp/demo/archive/%f "%p"'
recovery_target_time = '2019-06-04 14:10:00'
restore_command menentukan cara mengambil file WAL yang diperlukan oleh PostgreSQL. Ini adalah kebalikan dari archive_command. waktu_target_pemulihan menentukan waktu sampai kita membutuhkan perubahan.
Saat proses server PostgreSQL dimulai dan menemukan recovery.conf filedalam direktori data, itu dimulai dalam mode khusus yang disebut "mode pemulihan".Ketika dalam mode pemulihan, koneksi klien ditolak. Postgres mengambil file WAL dan menerapkannya hingga target pemulihan (dalam hal ini, berubah hingga stempel waktu yang ditentukan) tercapai. Ketika target tercapai, server secara default menjeda pemutaran ulang WAL (tindakan lain dimungkinkan). Pada titik ini, Anda seharusnya memeriksa status pemulihan dan jika semuanya terlihat baik-baik saja, batalkan jeda untuk keluar dari mode pemulihan dan melanjutkan operasi normal.
Menggabungkan Semuanya
Semua itu adalah sekumpulan teori dan teks, mari kita coba untuk melihat bagaimana semuanya bekerja dalam praktik.
Pertama mari kita inisialisasi cluster baru:
/tmp/demo$ pg_ctl -D clus1 initdb
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.
The database cluster will be initialized with locale "C.UTF-8".
The default database encoding has accordingly been set to "UTF8".
The default text search configuration will be set to "english".
Data page checksums are disabled.
creating directory clus1 ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok
WARNING: enabling "trust" authentication for local connections
You can change this by editing pg_hba.conf or using the option -A, or
--auth-local and --auth-host, the next time you run initdb.
Success. You can now start the database server using:
/usr/lib/postgresql/10/bin/pg_ctl -D clus1 -l logfile start
Kami juga akan membuat direktori yang akan berfungsi sebagai lokasi penyimpanan aman kami. Sebut ini "arsip".
/tmp/demo$ mkdir archive
/tmp/demo$ ls -l
total 8
drwxr-xr-x 2 postgres postgres 4096 Jun 4 14:02 archive
drwx------ 19 postgres postgres 4096 Jun 4 14:02 clus1
Kita perlu mengonfigurasi pengaturan arsip yang telah kita bahas sebelumnya, sebelum kita dapat memulai server. Jadi mari tambahkan berikut ini di akhirclus1/postgres.conf
:
port = 6000
wal_level = logical
archive_mode = on
archive_command = 'cp %p /tmp/demo/archive/%f'
archive_timeout = 60
Perintah arsip kami hanya menyalin file WAL ke direktori arsip yang kami buat sebelumnya.
Kami juga telah menambahkan archive_timeout pengaturan. Biasanya, file WAL dibuat hanya jika ada cukup catatan WAL untuk mengisi file WAL 16 MB. Ini berarti bahwa untuk server dengan sedikit penulisan, Anda mungkin harus menunggu lama untuk membuat file WAL. Pengaturan archive_timeout memberi tahu Postgres bahwa itu harus buat file aWAL setiap beberapa detik, terlepas dari apakah file tersebut penuh atau tidak.
Di sini kami telah mengatur ini menjadi 60 (detik), tetapi ini hanya untuk demo! Anda biasanya tidak akan pernah ingin serendah ini.
Mari kita juga membuat salinan "clus1". Ini setara dengan cadangan penuh.
/tmp/demo$ cp -Rp clus1 clus2
/tmp/demo$ ls -l
total 12
drwxr-xr-x 2 postgres postgres 4096 Jun 4 14:02 archive
drwx------ 19 postgres postgres 4096 Jun 4 14:03 clus1
drwx------ 19 postgres postgres 4096 Jun 4 14:03 clus2
Sekarang kita dapat memulai cluster:
/tmp/demo$ pg_ctl -D clus1 -l log1 start
waiting for server to start.... done
server started
Mari tambahkan beberapa data.
/tmp/demo$ psql -h /var/run/postgresql -p 6000 postgres
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.
postgres=# create database demo;
CREATE DATABASE
postgres=# \c demo
You are now connected to database "demo" as user "postgres".
demo=# create table tbl1 (col1 int);
CREATE TABLE
demo=# insert into tbl1 (col1) select generate_series(1, 10000);
INSERT 0 10000
demo=# select count(*) from tbl1;
count
-------
10000
(1 row)
demo=# select now();
now
-------------------------------
2019-06-04 14:05:05.657871+00
(1 row)
demo=# \q
Perhatikan bahwa waktu sekarang adalah 14:05. Mari kita periksa apakah perintah arsip kita berfungsi:
/tmp/demo$ ls -l archive/
total 16384
-rw------- 1 postgres postgres 16777216 Jun 4 14:04 000000010000000000000001
Ya, kami memiliki satu file arsip tunggal. Perubahan terakhir kami adalah pada pukul 14:05, mari kita tunggu beberapa menit lalu buat beberapa perubahan lagi.
/tmp/demo$ psql -h /var/run/postgresql -p 6000 demo
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.
demo=# select now();
now
-------------------------------
2019-06-04 14:16:06.093859+00
(1 row)
demo=# select count(*) from tbl1;
count
-------
10000
(1 row)
demo=# insert into tbl1 (col1) select generate_series(1, 100);
INSERT 0 100
demo=# select count(*) from tbl1;
count
-------
10100
(1 row)
demo=# \q
Jadi sekarang kami telah menambahkan 100 baris lagi, pada 14:16. Mari kita hentikan servernya:
/tmp/demo$ pg_ctl -D clus1 stop
waiting for server to shut down.... done
server stopped
/tmp/demo$
dan periksa arsip kami lagi:
/tmp/demo$ ls -l archive/
total 65536
-rw------- 1 postgres postgres 16777216 Jun 4 14:04 000000010000000000000001
-rw------- 1 postgres postgres 16777216 Jun 4 14:05 000000010000000000000002
-rw------- 1 postgres postgres 16777216 Jun 4 14:09 000000010000000000000003
-rw------- 1 postgres postgres 16777216 Jun 4 14:16 000000010000000000000004
Kelihatan bagus. Sekarang kami akan mencoba melakukan pemulihan PITR dari clus2 hingga waktu 14:10.
Pertama mari kita edit postgres.conf clus2 dan tambahkan baris ini di akhir:
port = 6001
archive_mode = off
Untuk memutar ulang file WAL, kita harus meletakkan server PostgreSQL untuk clus2 (yang belum kita mulai) ke mode pemulihan. Untuk melakukan ini, buat file bernama “recovery.conf” di clus2:
/tmp/demo$ cat clus2/recovery.conf
restore_command = 'cp /tmp/demo/archive/%f "%p"'
recovery_target_time = '2019-06-04 14:10:00'
Ini berisi restore_command yang melakukan kebalikan dari archive_command sebelumnya , yaitu menyalin file yang diminta dari direktori arsip ke direktori pg_wal.
Kami juga telah menyetel waktu_target_pemulihan hingga 14:10.
Sekarang kita mulai clus2:
/tmp/demo$ pg_ctl -D clus2 -l log2 start
waiting for server to start.... done
server started
Untuk melihat apa yang terjadi, mari kita periksa file log:
/tmp/demo$ cat log2
2019-06-04 14:19:10.862 UTC [10513] LOG: listening on IPv4 address "127.0.0.1", port 6001
2019-06-04 14:19:10.864 UTC [10513] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.6001"
2019-06-04 14:19:10.883 UTC [10514] LOG: database system was shut down at 2019-06-04 14:02:31 UTC
2019-06-04 14:19:10.883 UTC [10514] LOG: starting point-in-time recovery to 2019-06-04 14:10:00+00
2019-06-04 14:19:10.903 UTC [10514] LOG: restored log file "000000010000000000000001" from archive
2019-06-04 14:19:10.930 UTC [10514] LOG: consistent recovery state reached at 0/16383E8
2019-06-04 14:19:10.930 UTC [10514] LOG: redo starts at 0/16383E8
2019-06-04 14:19:10.931 UTC [10513] LOG: database system is ready to accept read only connections
2019-06-04 14:19:11.037 UTC [10514] LOG: restored log file "000000010000000000000002" from archive
2019-06-04 14:19:11.079 UTC [10514] LOG: restored log file "000000010000000000000003" from archive
2019-06-04 14:19:11.122 UTC [10514] LOG: restored log file "000000010000000000000004" from archive
2019-06-04 14:19:11.141 UTC [10514] LOG: recovery stopping before commit of transaction 559, time 2019-06-04 14:16:24.875517+00
2019-06-04 14:19:11.141 UTC [10514] LOG: recovery has paused
2019-06-04 14:19:11.141 UTC [10514] HINT: Execute pg_wal_replay_resume() to continue.
Pemulihannya cepat (dalam kehidupan nyata, mungkin perlu berjam-jam atau berhari-hari) dan log menyatakan bahwa itu telah berhenti sebelum transaksi tertentu (yang memiliki stempel waktu> 14:10). Ia juga mengatakan bahwa pemulihan dijeda dan harus dilanjutkan secara manual.
Mari kita periksa datanya:
/tmp/demo$ psql -h /var/run/postgresql -p 6001 demo
psql (10.8 (Ubuntu 10.8-0ubuntu0.18.04.1))
Type "help" for help.
demo=# select count(*) from tbl1;
count
-------
10000
(1 row)
Kami melihat bahwa hanya ada 10.000 baris. Pada 14:16, kami telah menambahkan 100 lagi, yang belum muncul di tabel.
Ini terlihat bagus, jadi mari kita lanjutkan:
demo=# select pg_wal_replay_resume();
pg_wal_replay_resume
----------------------
(1 row)
File log sekarang melaporkan bahwa pemulihan telah selesai dan operasi normal dipulihkan:
2019-06-04 14:20:26.219 UTC [10514] LOG: redo done at 0/4002160
2019-06-04 14:20:26.219 UTC [10514] LOG: last completed transaction was at log time 2019-06-04 14:05:28.813325+00
cp: cannot stat '/tmp/demo/archive/00000002.history': No such file or directory
2019-06-04 14:20:26.228 UTC [10514] LOG: selected new timeline ID: 2
2019-06-04 14:20:26.272 UTC [10514] LOG: archive recovery complete
cp: cannot stat '/tmp/demo/archive/00000001.history': No such file or directory
2019-06-04 14:20:26.388 UTC [10513] LOG: database system is ready to accept connections
Dan kami telah berhasil memulihkan cluster hingga waktu yang ditentukan!
Bacaan Lebih Lanjut
Berikut adalah beberapa titik awal untuk menemukan lebih banyak tentang pengarsipan WAL, mode pemulihan, dan PITR:
- Dokumen:Konfigurasi Pemulihan
- Dokumen:Pengarsipan Berkelanjutan dan PITR
- Bab 9 dari buku “Internal PostgreSQL”
- Alat:WAL-E,WAL-G, Barman