WAL di PostgreSQL: 3. Pos pemeriksaan

Kami telah membiasakan diri dengan perangkat cache buffer , salah satu objek utama dalam memori bersama, dan menyadari bahwa untuk memulihkan dari kegagalan ketika konten RAM hilang, Anda perlu menyimpan log prarekam .

Masalah yang belum terselesaikan yang kami hentikan pada waktu terakhir adalah tidak diketahui pada titik mana Anda dapat mulai memutar log selama pemulihan. Mulai dari awal, seperti yang disarankan Raja dari Alice , tidak akan berfungsi: tidak mungkin untuk menyimpan semua entri jurnal dari permulaan server - ini berpotensi jumlah yang besar, dan waktu pemulihan yang sangat besar yang sama. Kami membutuhkan titik maju yang bertahap untuk memulai pemulihan (dan, karenanya, kami dapat menghapus semua entri jurnal sebelumnya dengan aman). Ini adalah titik kontrol yang akan dibahas hari ini.

Titik kontrol


Properti apa yang harus dimiliki titik kontrol? Kita harus yakin bahwa semua entri jurnal, mulai dari pos pemeriksaan, akan diterapkan ke halaman yang ditulis ke disk. Jika tidak demikian, selama pemulihan kita bisa membaca dari disk versi yang terlalu lama dari halaman dan menerapkan entri jurnal untuk itu, dan dengan demikian secara permanen merusak data.

Bagaimana cara mendapatkan breakpoint? Opsi termudah adalah menangguhkan sistem secara berkala dan menyiram semua halaman kotor buffer dan cache lainnya ke disk. (Perhatikan bahwa halaman hanya ditulis, tetapi tidak dikeluarkan dari cache.) Poin-poin seperti itu akan memenuhi syarat, tetapi, tentu saja, tidak ada yang mau bekerja dengan sistem yang terus membeku untuk waktu yang tidak terbatas, tetapi sangat signifikan.

Oleh karena itu, dalam praktiknya, semuanya agak lebih rumit: titik kontrol dari titik berubah menjadi segmen. Pertama kita mulai breakpoint. Setelah itu, tanpa mengganggu pekerjaan dan, jika mungkin, tanpa membuat beban puncak, kami perlahan-lahan membuang buffer kotor pada disk.



Ketika semua buffer yang kotor pada awal pos pemeriksaan ditulis, pos pemeriksaan dianggap lengkap . Sekarang (tetapi tidak lebih awal) kita dapat menggunakan titik awal sebagai titik dari mana Anda dapat memulai pemulihan. Dan jurnal yang masuk hingga saat ini tidak lagi kita perlukan.



Pos pemeriksaan ditangani oleh proses pos pemeriksaan latar belakang khusus.

Durasi buffer kotor ditentukan oleh nilai parameter checkpoint_completion_target . Ini menunjukkan berapa banyak waktu antara dua titik kontrol yang berdekatan rekaman akan berlangsung. Nilai default adalah 0,5 (seperti pada gambar di atas), yaitu, rekaman membutuhkan setengah waktu antara titik kontrol. Biasanya, nilainya ditingkatkan hingga 1,0 untuk keseragaman yang lebih besar.

Mari kita pertimbangkan secara lebih rinci apa yang terjadi ketika titik kontrol dijalankan.

Proses pos pemeriksaan pertama flushes buffer status transaksi (XACT) ke disk. Karena ada beberapa dari mereka (total 128), mereka dicatat segera.

Kemudian pekerjaan utama dimulai - menulis halaman kotor dari cache buffer. Seperti yang sudah kami katakan, tidak mungkin untuk mengatur ulang semua halaman sekaligus, karena ukuran cache buffer bisa signifikan. Oleh karena itu, pertama, semua halaman yang kotor ditandai dalam cache buffer di header dengan flag khusus.



Dan kemudian proses pos pemeriksaan secara bertahap melewati semua buffer dan menyiram yang ditandai ke disk. Ingat bahwa halaman tidak dikeluarkan dari cache, tetapi hanya ditulis ke disk, jadi Anda tidak perlu memperhatikan jumlah panggilan ke buffer atau untuk memperbaikinya.

Buffer berlabel juga dapat ditulis oleh proses server - tergantung pada siapa yang mendapatkan buffer terlebih dahulu. Bagaimanapun, flag yang ditetapkan sebelumnya dihapus saat merekam, jadi (untuk tujuan pos pemeriksaan) buffer akan ditulis hanya sekali.

Secara alami, selama pelaksanaan pos pemeriksaan, halaman-halaman terus berubah dalam cache buffer. Tetapi buffer kotor baru tidak ditandai dan proses pos pemeriksaan tidak boleh menulisnya.



Di akhir pekerjaannya, proses menciptakan entri jurnal untuk akhir pos pemeriksaan. Catatan ini berisi LSN dari awal pekerjaan titik kontrol. Karena titik kontrol tidak menulis apa pun ke log di awal kerjanya, LSN ini dapat berisi catatan log apa pun.

Selain itu, file $ PGDATA / global / pg_control memperbarui indikasi pos pemeriksaan terakhir yang dilewati . Sebelum pos pemeriksaan selesai, pg_control menunjuk ke pos pemeriksaan sebelumnya.



Untuk melihat pekerjaan pos pemeriksaan, buat beberapa tabel - halamannya akan menuju ke cache buffer dan akan menjadi kotor:

=> CREATE TABLE chkpt AS SELECT * FROM generate_series(1,10000) AS g(n); => CREATE EXTENSION pg_buffercache; => SELECT count(*) FROM pg_buffercache WHERE isdirty; 
  count ------- 78 (1 row) 

Ingat posisi saat ini di log:

 => SELECT pg_current_wal_insert_lsn(); 
  pg_current_wal_insert_lsn --------------------------- 0/3514A048 (1 row) 

Sekarang kami akan menjalankan pos pemeriksaan secara manual dan memastikan bahwa tidak ada halaman kotor di cache (seperti yang kami katakan, halaman kotor baru dapat muncul, tetapi dalam kasus kami tidak ada perubahan dalam proses pelaksanaan pemeriksaan pos):

 => CHECKPOINT; => SELECT count(*) FROM pg_buffercache WHERE isdirty; 
  count ------- 0 (1 row) 

Mari kita lihat bagaimana pos pemeriksaan tercermin dalam log:

 => SELECT pg_current_wal_insert_lsn(); 
  pg_current_wal_insert_lsn --------------------------- 0/3514A0E4 (1 row) 

 postgres$ /usr/lib/postgresql/11/bin/pg_waldump -p /var/lib/postgresql/11/main/pg_wal -s 0/3514A048 -e 0/3514A0E4 
 rmgr: Standby len (rec/tot): 50/ 50, tx: 0, lsn: 0/3514A048, prev 0/35149CEC, desc: RUNNING_XACTS nextXid 101105 latestCompletedXid 101104 oldestRunningXid 101105 
 rmgr: XLOG len (rec/tot): 102/ 102, tx: 0, lsn: 0/3514A07C, prev 0/3514A048, desc: CHECKPOINT_ONLINE redo 0/3514A048; tli 1; prev tli 1; fpw true; xid 0:101105; oid 74081; multi 1; offset 0; oldest xid 561 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 101105; online 

Di sini kita melihat dua entri. Yang terakhir adalah catatan melewati titik kontrol (CHECKPOINT_ONLINE). LSN pada awal pos pemeriksaan ditunjukkan setelah kata redo, dan posisi ini sesuai dengan entri jurnal, yang merupakan yang terakhir pada awal pos pemeriksaan.

Kami akan menemukan informasi yang sama di file kontrol:

 postgres$ /usr/lib/postgresql/11/bin/pg_controldata -D /var/lib/postgresql/11/main | egrep 'Latest.*location' 
 Latest checkpoint location: 0/3514A07C Latest checkpoint's REDO location: 0/3514A048 

Pemulihan


Sekarang kami siap untuk mengklarifikasi algoritma pemulihan yang diuraikan dalam artikel sebelumnya.

Jika server macet, saat berikutnya dimulai, proses startup mendeteksi ini dengan melihat file pg_control dan melihat status selain "mematikan". Dalam hal ini, pemulihan otomatis dilakukan.

Pertama, proses pemulihan akan membaca dari pg_control yang sama dengan posisi awal dari titik kontrol. (Untuk kelengkapan, kami perhatikan bahwa jika file backup_label ada, maka catatan titik kontrol dibaca darinya - ini diperlukan untuk memulihkan dari cadangan, tetapi ini adalah topik untuk siklus terpisah.)

Kemudian dia akan membaca majalah, mulai dari posisi yang ditemukan, secara berurutan menerapkan entri jurnal ke halaman (jika perlu, seperti yang kita bahas terakhir kali ).

Sebagai kesimpulan, semua tabel non-jurnal ditimpa menggunakan gambar dalam file init.

Pada titik ini, proses startup berakhir, dan proses checkpointer segera mengeksekusi checkpoint untuk memperbaiki keadaan yang dipulihkan pada disk.

Anda dapat mensimulasikan kegagalan dengan menghentikan server secara paksa dalam mode langsung.

 student$ sudo pg_ctlcluster 11 main stop -m immediate --skip-systemctl-redirect 

( --skip-systemctl-redirect diperlukan di sini karena menggunakan PostgreSQL yang diinstal di Ubuntu dari paket. Ia dikontrol oleh perintah pg_ctlcluster, yang sebenarnya memanggil systemctl, dan ia sudah memanggil pg_ctl. Dengan semua pembungkus ini, nama mode hilang di sepanjang jalan, dan --skip-systemctl-redirect memungkinkan Anda melakukannya tanpa systemctl dan menyimpan informasi penting.)

Periksa status cluster:

 postgres$ /usr/lib/postgresql/11/bin/pg_controldata -D /var/lib/postgresql/11/main | grep state 
 Database cluster state: in production 

Saat startup, PostgreSQL memahami bahwa telah terjadi kegagalan dan diperlukan pemulihan.

 student$ sudo pg_ctlcluster 11 main start 

 postgres$ tail -n 7 /var/log/postgresql/postgresql-11-main.log 
 2019-07-17 15:27:49.441 MSK [8865] LOG: database system was interrupted; last known up at 2019-07-17 15:27:48 MSK 2019-07-17 15:27:49.801 MSK [8865] LOG: database system was not properly shut down; automatic recovery in progress 2019-07-17 15:27:49.804 MSK [8865] LOG: redo starts at 0/3514A048 2019-07-17 15:27:49.804 MSK [8865] LOG: invalid record length at 0/3514A0E4: wanted 24, got 0 2019-07-17 15:27:49.804 MSK [8865] LOG: redo done at 0/3514A07C 2019-07-17 15:27:49.824 MSK [8864] LOG: database system is ready to accept connections 2019-07-17 15:27:50.409 MSK [8872] [unknown]@[unknown] LOG: incomplete startup packet 

Kebutuhan untuk pemulihan dicatat dalam log pesan: sistem basis data tidak dimatikan dengan benar; pemulihan otomatis sedang berlangsung . Kemudian, entri jurnal mulai diputar dari posisi yang ditandai "redo dimulai pada" dan lanjutkan hingga entri jurnal berikutnya dapat diambil. Ini menyelesaikan pemulihan di posisi "redo done at" dan DBMS mulai bekerja dengan klien ( sistem database siap menerima koneksi ).

Dan apa yang terjadi selama shutdown server normal? Untuk membersihkan halaman yang kotor ke disk, PostgreSQL memutus semua klien dan kemudian menjalankan pos pemeriksaan terakhir.

Ingat posisi saat ini di log:

 => SELECT pg_current_wal_insert_lsn(); 
  pg_current_wal_insert_lsn --------------------------- 0/3514A14C (1 row) 

Sekarang hentikan server dengan lembut:

 student$ sudo pg_ctlcluster 11 main stop 

Periksa status cluster:

 postgres$ /usr/lib/postgresql/11/bin/pg_controldata -D /var/lib/postgresql/11/main | grep state 
 Database cluster state: shut down 

Dan dalam log kami menemukan satu-satunya catatan tentang titik kontrol akhir (CHECKPOINT_SHUTDOWN):

 postgres$ /usr/lib/postgresql/11/bin/pg_waldump -p /var/lib/postgresql/11/main/pg_wal -s 0/3514A14C 
 rmgr: XLOG len (rec/tot): 102/ 102, tx: 0, lsn: 0/3514A14C, prev 0/3514A0E4, desc: CHECKPOINT_SHUTDOWN redo 0/3514A14C; tli 1; prev tli 1; fpw true; xid 0:101105; oid 74081; multi 1; offset 0; oldest xid 561 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 0; shutdown 
 pg_waldump: FATAL: error in WAL record at 0/3514A14C: invalid record length at 0/3514A1B4: wanted 24, got 0 

(Dalam pesan fatal yang mengerikan, pg_waldump hanya ingin mengatakan bahwa dia membaca sampai akhir majalah.)

Jalankan instance lagi.

 student$ sudo pg_ctlcluster 11 main start 

Rekaman latar belakang


Seperti yang kami ketahui, pos pemeriksaan adalah salah satu proses yang menulis halaman kotor dari cache buffer ke disk. Tapi bukan satu-satunya.

Jika backend perlu mendorong halaman keluar dari buffer dan halaman itu kotor, ia harus menulisnya ke disk sendiri. Ini adalah situasi yang buruk, mengarah ke harapan - itu jauh lebih baik ketika perekaman terjadi secara tidak sinkron di latar belakang.

Oleh karena itu, selain proses pos pemeriksaan , ada juga proses perekaman latar belakang (penulis latar belakang, penulis naskah, atau penulis adil). Proses ini menggunakan algoritma pencarian buffer yang sama dengan mekanisme preemption. Pada dasarnya ada dua perbedaan.

  1. Itu tidak menggunakan pointer ke "korban berikutnya", tetapi miliknya sendiri. Dia bisa berada di depan pointer ke "korban", tetapi tidak pernah tertinggal di belakangnya.
  2. Saat melintasi buffer, penghitung hit tidak berkurang.

Buffer ditulis yang secara bersamaan:

  • mengandung data yang diubah (kotor),
  • tidak diperbaiki (jumlah pin = 0),
  • memiliki nol hit (jumlah penggunaan = 0).

Dengan demikian, proses perekaman latar belakang, seolah-olah, berjalan di depan crowding out dan menemukan buffer yang kemungkinan akan segera keluar. Idealnya, karena ini, proses layanan harus menemukan bahwa buffer yang mereka pilih dapat digunakan tanpa berhenti menulis.

Kustomisasi


Proses pos pemeriksaan biasanya dikonfigurasi untuk alasan berikut.

Pertama, Anda perlu memutuskan berapa banyak file log yang dapat kami simpan (dan waktu pemulihan apa yang cocok untuk kami). Semakin besar, semakin baik, tetapi karena alasan yang jelas nilai ini akan terbatas.

Selanjutnya, kita dapat menghitung berapa lama volume ini akan dihasilkan di bawah beban normal. Kami telah mempertimbangkan bagaimana melakukan ini (kita perlu mengingat posisi dalam jurnal dan mengurangi satu dari yang lain).

Waktu ini akan menjadi interval kami yang biasa di antara titik kontrol. Kami menulisnya di parameter checkpoint_timeout . Nilai default 5 menit jelas terlalu kecil, biasanya waktunya meningkat, katakanlah, setengah jam. Saya ulangi: semakin jarang Anda mampu membayar tonggak, semakin baik - ini mengurangi biaya overhead.

Namun, ada kemungkinan (dan bahkan kemungkinan) bahwa kadang-kadang beban akan lebih tinggi dari biasanya, dan terlalu banyak entri jurnal akan dihasilkan pada waktu yang ditentukan dalam parameter. Dalam hal ini, saya ingin melakukan titik kontrol lebih sering. Untuk melakukan ini, dalam parameter max_wal_size kami menentukan jumlah yang valid dalam titik kontrol yang sama. Jika volume aktual diperoleh lebih banyak, server memulai pos pemeriksaan yang tidak terjadwal.

Dengan demikian, sebagian besar titik kontrol terjadi pada jadwal: satu kali per unit waktu checkpoint_timeout . Tetapi dengan peningkatan beban, titik kontrol dipanggil lebih sering ketika volume max_wal_size tercapai .

Penting untuk dipahami bahwa parameter max_wal_size sama sekali tidak menentukan jumlah maksimum yang dapat ditempati file log pada disk.

  • Untuk memulihkan dari kegagalan, Anda perlu menyimpan file dari saat pos pemeriksaan terakhir dilewati, ditambah file yang terakumulasi selama pengoperasian pos pemeriksaan saat ini. Oleh karena itu, total volume dapat diperkirakan secara kasar sebagai
    (1 + checkpoint_completion_target ) × max_wal_size .
  • Sebelum versi 11, PostgreSQL juga menyimpan file untuk pos pemeriksaan dua tahun, jadi hingga versi 10 dalam rumus di atas, Anda harus menetapkan 2 bukannya 1.
  • Parameter max_wal_size hanya harapan, tetapi bukan batas keras. Itu mungkin berubah lebih.
  • Server tidak memiliki hak untuk menghapus file log yang belum ditransfer melalui slot replikasi dan yang belum diarsipkan selama pengarsipan terus menerus. Jika fungsi ini digunakan, pemantauan konstan diperlukan, karena mudah meluap memori server.

Untuk melengkapi gambar, Anda dapat mengatur tidak hanya volume maksimum, tetapi juga minimum: parameter min_wal_size . Arti pengaturan ini adalah bahwa server tidak menghapus file saat mereka masuk volume ke dalam min_wal_size , tetapi cukup mengubah nama mereka dan menggunakannya lagi. Ini menghemat sedikit dengan terus-menerus membuat dan menghapus file.

Proses perekaman latar belakang masuk akal untuk dikonfigurasikan setelah pos pemeriksaan dikonfigurasi. Bersama-sama, proses ini harus memiliki waktu untuk menulis buffer kotor sebelum mereka diperlukan oleh proses pemeliharaan.

Proses perekaman latar belakang berjalan dalam siklus paling banyak halaman bgwriter_lru_maxpages , tertidur di antara siklus pada bgwriter_delay .

Jumlah halaman yang akan dicatat dalam satu siklus kerja ditentukan oleh jumlah rata-rata buffer yang diminta oleh proses servis dari putaran terakhir (menggunakan rata-rata bergerak untuk memuluskan ketidakrataan antar putaran, tetapi tidak tergantung pada sejarah yang panjang). Jumlah buffer yang dihitung dikalikan dengan koefisien bgwriter_lru_multiplier (tetapi dalam hal apa pun itu tidak akan melebihi bgwriter_lru_maxpages ).

Nilai default: bgwriter_delay = 200ms (kemungkinan besar terlalu banyak, kebocoran banyak air dalam 1/5 detik), bgwriter_lru_maxpages = 100, bgwriter_lru_multiplier = 2.0 (kami mencoba menanggapi permintaan lebih cepat dari jadwal).

Jika proses tidak mendeteksi buffer kotor sama sekali (yaitu, tidak ada yang terjadi dalam sistem), itu "hibernate" dari mana itu menyimpulkan bahwa proses server mengakses buffer. Setelah itu, proses bangun dan kembali berfungsi dengan cara biasa.

Pemantauan


Pengaturan titik kontrol dan latar belakang dapat dan harus disesuaikan, menerima umpan balik dari pemantauan.

Parameter checkpoint_warning menampilkan peringatan jika checkpoint yang disebabkan oleh luberan ukuran file log terlalu sering dijalankan. Nilai default-nya adalah 30 detik, dan harus sesuai dengan nilai checkpoint_timeout .

Parameter log_checkpoints (dinonaktifkan secara default) memungkinkan menerima informasi tentang pos pemeriksaan yang dieksekusi di log pesan server. Hidupkan.

 => ALTER SYSTEM SET log_checkpoints = on; => SELECT pg_reload_conf(); 

Sekarang ubah sesuatu dalam data dan jalankan pos pemeriksaan.

 => UPDATE chkpt SET n = n + 1; => CHECKPOINT; 

Di log pesan, kita akan melihat sesuatu seperti ini:

 postgres$ tail -n 2 /var/log/postgresql/postgresql-11-main.log 
 2019-07-17 15:27:55.248 MSK [8962] LOG: checkpoint starting: immediate force wait 2019-07-17 15:27:55.274 MSK [8962] LOG: checkpoint complete: wrote 79 buffers (0.5%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.001 s, sync=0.013 s, total=0.025 s; sync files=2, longest=0.011 s, average=0.006 s; distance=1645 kB, estimate=1645 kB 

Di sini Anda dapat melihat berapa banyak buffer yang ditulis, bagaimana komposisi file log berubah setelah titik kontrol, berapa lama titik kontrol dan jarak (dalam byte) antara titik kontrol yang berdekatan.

Tapi, mungkin, informasi yang paling berguna adalah statistik pekerjaan pos pemeriksaan dan proses perekaman latar belakang dalam tampilan pg_stat_bgwriter. Tampilan adalah satu untuk dua, karena begitu kedua tugas dilakukan oleh satu proses; lalu fungsinya dibagi, dan pandangan tetap ada.

 => SELECT * FROM pg_stat_bgwriter \gx 
 -[ RECORD 1 ]---------+------------------------------ checkpoints_timed | 0 checkpoints_req | 1 checkpoint_write_time | 1 checkpoint_sync_time | 13 buffers_checkpoint | 79 buffers_clean | 0 maxwritten_clean | 0 buffers_backend | 42 buffers_backend_fsync | 0 buffers_alloc | 363 stats_reset | 2019-07-17 15:27:49.826414+03 

Di sini, antara lain, kami melihat jumlah titik kontrol selesai:

  • checkpoints_timed - sesuai dengan jadwal (setelah mencapai checkpoint_timeout),
  • checkpoints_req - sesuai permintaan (termasuk saat mencapai max_wal_size).

Nilai checkpoint_req yang besar (dibandingkan dengan checkpoints_timed) menunjukkan bahwa titik kontrol terjadi lebih sering daripada yang diharapkan.

Informasi penting tentang jumlah halaman yang direkam:

  • buffers_checkpoint - proses pemeriksaan,
  • buffers_backend - dengan melayani proses,
  • buffers_clean - proses perekaman latar belakang.

Pada sistem yang disetel dengan baik, nilai buffers_backend harus secara substansial kurang dari jumlah buffers_checkpoint dan buffers_clean.

Juga, maxwritten_clean berguna untuk mengatur perekaman latar belakang - angka ini menunjukkan berapa kali proses perekaman latar belakang berhenti bekerja karena melebihi bgwriter_lru_maxpages .

Anda dapat mengatur ulang akumulasi statistik menggunakan panggilan berikut:

 => SELECT pg_stat_reset_shared('bgwriter'); 

Untuk dilanjutkan .

Source: https://habr.com/ru/post/id460423/


All Articles