ERROR PostgreSQL: membatalkan pernyataan karena konflik dengan pemulihan

159

Saya mendapatkan kesalahan berikut saat menjalankan kueri di PostgreSQL db dalam mode siaga. Kueri yang menyebabkan kesalahan berfungsi dengan baik selama 1 bulan tetapi ketika Anda membuat kueri selama lebih dari 1 bulan menghasilkan kesalahan.

ERROR: canceling statement due to conflict with recovery
Detail: User query might have needed to see row versions that must be removed

Ada saran tentang cara mengatasinya? Terima kasih

AnApprentice
sumber
Temukan dokumen AWS yang menyebutkan kesalahan ini, itu juga memiliki solusinya aws.amazon.com/blogs/database/…
arunjos007

Jawaban:

96

Menjalankan kueri di server siaga panas agak rumit - ini bisa gagal, karena selama membuat kueri beberapa baris yang diperlukan mungkin diperbarui atau dihapus di primer. Karena primer tidak tahu bahwa kueri dimulai pada sekunder, ia mengira dapat membersihkan (vakum) versi lama dari barisnya. Kemudian sekunder harus memutar ulang pembersihan ini, dan harus membatalkan secara paksa semua kueri yang dapat menggunakan baris ini.

Kueri yang lebih lama akan lebih sering dibatalkan.

Anda dapat menyiasatinya dengan memulai transaksi baca berulang pada primer yang melakukan kueri dummy dan kemudian diam sementara kueri sebenarnya dijalankan pada kueri sekunder. Kehadirannya akan mencegah pengosongan versi baris lama pada primer.

Lebih lanjut tentang subjek ini dan solusi lainnya dijelaskan di bagian Siaga Panas - Menangani Konflik Kueri dalam dokumentasi.

Tometzky
sumber
11
Untuk pengguna PostgreSQL 9.1+: lihat jawaban eradman di bawah ini untuk solusi praktis.
Zoltán
5
Untuk pengguna PostgreSQL 9.1+: jawaban max-malysh jauh lebih waras. Jangan lakukan saran eradman kecuali Anda memahami risikonya.
Davos
102

Tidak perlu disentuh hot_standby_feedback. Seperti yang telah disebutkan orang lain, menyetelnya ke oncan bloat master. Bayangkan membuka transaksi pada seorang budak dan bukan menutupnya.

Sebaliknya, tetapkan max_standby_archive_delaydan max_standby_streaming_delayke beberapa nilai yang wajar:

# /etc/postgresql/10/main/postgresql.conf on a slave
max_standby_archive_delay = 900s
max_standby_streaming_delay = 900s

Dengan cara ini, kueri pada budak dengan durasi kurang dari 900 detik tidak akan dibatalkan. Jika beban kerja Anda membutuhkan kueri yang lebih lama, cukup setel opsi ini ke nilai yang lebih tinggi.

Max Malysh
sumber
1
Ini adalah solusi yang akhirnya kami gunakan. Sepertinya kompromi terbaik antara semua opsi yang disajikan di sini.
mohit6up
2
Ini jawaban terbaik. Perhatikan sesuai dokumen, ini bersifat kumulatif; jika Anda memiliki beberapa kueri pada replika yang menahan replikasi maka bisa jadi Anda mendapatkan 899 lalu kueri 2 detik lainnya dibatalkan. Yang terbaik adalah menerapkan beberapa mundur eksponensial dalam kode Anda. Selain itu, penundaan streaming berlaku saat replikasi sedang streaming. Jika replikasi tidak dapat mengikuti streaming, replikasi akan dipindahkan ke replikasi dari arsip. Jika Anda mereplikasi dari arsip Anda mungkin harus membiarkannya menyusul, max_standby_archive_delaymungkin perlu lebih kecil dari yang lain.
Davos
2
Ini masih solusi terbaik di sini. Perhatikan bahwa di Redshift, Anda dapat mengatur ini melalui pengaturan grup parameter, hanya itu harus dalam ms, yaitu 900s = 16 menit = 900000ms.
NullDev
Untuk mengupdatenya di GCP, juga dilakukan di ms cloud.google.com/sql/docs/postgres/…
howMuchCheeseIsTooMuchCheese
1
kami memiliki konfigurasi (master dan 2 node siaga panas) dan ketiga node tersebut memiliki pengaturan berikut: max_standby_archive_delay = 30s , max_standby_streaming_delay = 30s , ** hot_standby_feedback = off ** tetapi kami menghadapi kesalahan canceling statement due to conflict with recoverybahkan untuk kueri yang membutuhkan waktu 100ms-2000ms untuk menyelesaikan ( throughput selama uji beban ~ 120r / s) mengapa kueri yang berjalan singkat dibatalkan pada node siaga meskipun batas waktu ditetapkan selama 30 detik ...?
Erikas Neverdauskas
81

Tidak perlu memulai transaksi menganggur pada master. Di postgresql-9.1 cara paling langsung untuk menyelesaikan masalah ini adalah dengan mengatur

hot_standby_feedback = on

Ini akan membuat master mengetahui kueri yang berjalan lama. Dari dokumen :

Opsi pertama adalah menyetel parameter hot_standby_feedback, yang mencegah VACUUM menghapus baris yang baru saja mati sehingga konflik pembersihan tidak terjadi.

Mengapa ini bukan default? Parameter ini ditambahkan setelah implementasi awal dan ini satu-satunya cara standby dapat mempengaruhi master.

eradman
sumber
12
Parameter ini harus disetel dalam keadaan siaga.
Steve Kehlet
3
Ada beberapa kerugian untuk master dalam hal ini Hot-Standby-Feedback
Evgeny Liskovets
51

Seperti yang dinyatakan disini tentang hot_standby_feedback = on:

Nah, kerugiannya adalah bahwa standby dapat membuat master gembung, yang mungkin mengejutkan bagi sebagian orang juga

Dan di sini :

Dengan pengaturan max_standby_streaming_delay apa? Saya lebih suka default ke -1 daripada default hot_standby_feedback aktif. Dengan begitu, apa yang Anda lakukan saat standby hanya mempengaruhi standby


Jadi saya menambahkan

max_standby_streaming_delay = -1

Dan tidak ada lagi pg_dumpkesalahan untuk kami, atau master bloat :)

Untuk instance AWS RDS, periksa http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.html

Gilles Quenot
sumber
1
@ lennard, ini berhasil untuk saya. Saya menambahkan konfigurasi ini pada postgresql.conf budak, lalu memulai ulang budak tersebut.
Ardee Aram
13
Anda bisa mendapatkan lag replika tanpa batas dengan cara ini, tentu saja. Dan jika Anda menggunakan slot replikasi untuk menghubungkan replika ke master, hal itu dapat mengakibatkan retensi xlog yang berlebihan pada master, jadi ini hanya dapat dijalankan jika Anda menggunakan pengarsipan WAL.
Craig Ringer
7
Bagaimana mengatur ini di AWS RDS?
Kris MP
1
@KrisMP Gunakan psl
Yehonatan
4
@KrisMP dalam grup parameter - docs.s.amazon.com/AmazonRDS/latest/UserGuide/…
r3m0t
14

Data tabel di server budak siaga panas diubah saat kueri yang berjalan lama sedang berjalan. Solusi (PostgreSQL 9.1+) untuk memastikan data tabel tidak diubah adalah dengan menangguhkan replikasi dan melanjutkan setelah kueri:

select pg_xlog_replay_pause(); -- suspend
select * from foo; -- your query
select pg_xlog_replay_resume(); --resume
David Jaspers
sumber
1
Ini membutuhkan hak pengguna super. Jadi, ini mungkin bukan solusi dalam beberapa kasus.
Joao Baltazar
2
Di PostgreSQL 10, xlogdiganti dengan wal, jadi Anda ingin memanggil pg_wal_replay_pause()dan pg_wal_replay_resume().
womble
5

Mungkin sudah terlambat untuk jawabannya tetapi kami menghadapi masalah yang sama pada produksi. Sebelumnya kami hanya memiliki satu RDS dan karena jumlah pengguna meningkat di sisi aplikasi, kami memutuskan untuk menambahkan Replika Baca untuknya. Replika baca berfungsi dengan baik pada pementasan tetapi begitu kami pindah ke produksi, kami mulai mendapatkan kesalahan yang sama.

Jadi kami menyelesaikan ini dengan mengaktifkan properti hot_standby_feedback di properti Postgres. Kami merujuk tautan berikut

https://aws.amazon.com/blogs/database/best-practices-for-amazon-rds-postgresql-replication/

Saya harap ini akan membantu.

Tushar.k
sumber
3

Saya akan menambahkan beberapa info dan referensi terbaru ke jawaban bagus @ max-malysh di atas.

Singkatnya, jika Anda melakukan sesuatu pada tuannya, itu perlu direplikasi pada budak. Postgres menggunakan catatan WAL untuk ini, yang dikirim setelah setiap tindakan yang dicatat pada master ke budak. Budak kemudian mengeksekusi aksi tersebut dan keduanya kembali sinkron. Dalam salah satu dari beberapa skenario, Anda bisa mengalami konflik pada budak dengan apa yang masuk dari master dalam tindakan WAL. Di sebagian besar dari mereka, ada transaksi yang terjadi pada budak yang bertentangan dengan apa yang ingin diubah oleh tindakan WAL. Dalam hal ini, Anda memiliki dua opsi:

  1. Tunda penerapan tindakan WAL sebentar, biarkan budak menyelesaikan transaksi yang bertentangan, lalu terapkan tindakan tersebut.
  2. Batalkan permintaan yang bertentangan pada budak.

Kami prihatin dengan # 1, dan dua nilai:

  • max_standby_archive_delay - ini adalah penundaan yang digunakan setelah pemutusan hubungan yang lama antara master dan slave, saat data sedang dibaca dari arsip WAL, yang bukan merupakan data terkini.
  • max_standby_streaming_delay - penundaan digunakan untuk membatalkan kueri ketika entri WAL diterima melalui replikasi streaming.

Umumnya, jika server Anda dimaksudkan untuk replikasi ketersediaan tinggi, Anda ingin mempersingkat nomor ini. Pengaturan default 30000(milidetik jika tidak ada unit yang diberikan) sudah cukup untuk ini. Namun, jika Anda ingin menyiapkan sesuatu seperti arsip, pelaporan- atau replika baca yang mungkin memiliki kueri yang berjalan sangat lama, Anda dapat menyetelnya ke sesuatu yang lebih tinggi untuk menghindari kueri yang dibatalkan. 900sPengaturan yang direkomendasikan di atas sepertinya merupakan titik awal yang baik. Saya tidak setuju dengan dokumen resmi tentang menetapkan nilai tak terbatas -1sebagai ide yang bagus - yang dapat menutupi beberapa kode buggy dan menyebabkan banyak masalah.

Satu-satunya peringatan tentang kueri yang berjalan lama dan menyetel nilai-nilai ini lebih tinggi adalah bahwa kueri lain yang berjalan pada budak secara paralel dengan kueri yang berjalan lama yang menyebabkan tindakan WAL ditunda akan melihat data lama sampai kueri yang panjang selesai. Pengembang perlu memahami ini dan membuat serialisasi kueri yang seharusnya tidak berjalan secara bersamaan.

Untuk penjelasan lengkap tentang bagaimana max_standby_archive_delaydan max_standby_streaming_delaybekerja dan mengapa, buka di sini .

Artif3x
sumber
2

Demikian juga, berikut peringatan ke-2 untuk elaborasi @ Artif3x dari jawaban bagus @ max-malysh, keduanya di atas.

Dengan aplikasi transaksi yang tertunda dari master, pengikut akan memiliki tampilan data yang lebih lama dan basi. Oleh karena itu, sementara menyediakan waktu untuk kueri pada pengikut untuk menyelesaikan dengan menyetel max_standby_archive_delay dan max_standby_streaming_delay masuk akal, ingatlah kedua peringatan berikut:

Jika nilai pengikut untuk cadangan menjadi terlalu banyak konflik dengan kueri hosting, satu solusi akan menjadi beberapa pengikut, masing-masing dioptimalkan untuk satu atau yang lain.

Juga, perhatikan bahwa beberapa kueri berturut-turut dapat menyebabkan penerapan entri wal terus tertunda. Jadi saat memilih nilai baru, ini bukan hanya waktu untuk satu kueri, tetapi jendela pemindahan yang dimulai setiap kali kueri yang bentrok dimulai, dan berakhir saat entri wal akhirnya diterapkan.

bob
sumber