Apakah ada batas waktu untuk koneksi PostgreSQL yang menganggur?

98
1 S postgres  5038   876  0  80   0 - 11962 sk_wai 09:57 ?        00:00:00 postgres: postgres my_app ::1(45035) idle                                                                                 
1 S postgres  9796   876  0  80   0 - 11964 sk_wai 11:01 ?        00:00:00 postgres: postgres my_app ::1(43084) idle             

Saya melihat banyak dari mereka. Kami mencoba memperbaiki kebocoran koneksi kami. Namun sementara itu, kami ingin menyetel waktu tunggu untuk koneksi yang tidak aktif ini, mungkin maks hingga 5 menit.

pengguna1012451
sumber
bagaimana Anda menghubungkan ke DB? socketTimeout mungkin yang Anda cari.
Doon
Kami memiliki aplikasi web Pylons warisan ini, dan kami menggunakan SQLAlchemy tetapi tampaknya kami tidak menggunakannya dengan benar. Saya tidak ingat. Kami mencoba memperbaiki kebocoran tersebut. socketTimeoutdari doc sepertinya ini menutup koneksi ke DB, seluruhnya. Saya mencoba menutup setiap idle, dan penghitung dimulai segera setelah koneksi dibuat.
pengguna1012451
@ user1012451 Ketika Anda mengatakan "tutup setiap idle" - maksud Anda menghentikan <IDLE> in transactionsesi, membiarkan sesi berjalan tetapi dalam <IDLE>status? Dengan kata lain, hentikan transaksi tetapi tidak sesinya? (Suara negatif: pertanyaan tidak jelas)
Craig Ringer
@CraigRinger setelah beberapa saat, kami mencapai koneksi klien maksimal. Untuk mengatasinya, kita harus memulai ulang webapp, yang memaksa untuk memulai ulang postgresql juga. Itu menghapus semua koneksi. Ketika kami melihat ini idleselamanya, kami bertanya apakah kami dapat mengatur waktu tunggu pada setiap koneksi / sesi (sejujurnya saya tidak tahu terminologi yang benar, maaf). Jika transaksi memerlukan waktu 5 menit untuk aplikasi web normal, pasti ada sesuatu yang salah ....
user1012451

Jawaban:

120

Sepertinya Anda mengalami kebocoran koneksi dalam aplikasi Anda karena gagal menutup koneksi yang dikumpulkan . Anda tidak hanya mengalami masalah dengan <idle> in transactionsesi, tetapi dengan terlalu banyak koneksi secara keseluruhan.

Membunuh koneksi bukanlah jawaban yang tepat untuk itu, tetapi ini adalah solusi sementara yang OK-ish.

Daripada memulai kembali PostgreSQL untuk mem-boot semua koneksi lain dari database PostgreSQL, lihat: Bagaimana cara melepaskan semua pengguna lain dari database postgres? dan Bagaimana cara menjatuhkan database PostgreSQL jika ada koneksi aktif ke sana? . Yang terakhir menunjukkan kueri yang lebih baik.

Untuk mengatur waktu tunggu, seperti yang disarankan @Doon, lihat Bagaimana cara menutup koneksi yang tidak aktif di PostgreSQL secara otomatis? , yang menyarankan Anda untuk menggunakan PgBouncer sebagai proxy untuk PostgreSQL dan mengelola koneksi yang tidak aktif. Ini adalah ide yang sangat bagus jika Anda memiliki aplikasi buggy yang tetap saja membocorkan koneksi; Saya sangat menyarankan mengonfigurasi PgBouncer.

Sebuah keepalive TCP tidak akan melakukan pekerjaan di sini, karena aplikasi masih terhubung dan hidup, itu hanya tidak seharusnya.

Di PostgreSQL 9.2 dan yang lebih baru, Anda dapat menggunakan state_changekolom stempel waktu baru dan statebidang pg_stat_activityuntuk mengimplementasikan mesin penuai koneksi idle. Minta cron job menjalankan sesuatu seperti ini:

SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE datname = 'regress'
      AND pid <> pg_backend_pid()
      AND state = 'idle'
      AND state_change < current_timestamp - INTERVAL '5' MINUTE;

Dalam versi yang lebih lama Anda perlu mengimplementasikan skema rumit yang melacak kapan koneksi menganggur. Jangan ganggu; gunakan saja pgbouncer.

Craig Ringer
sumber
4
Bagus, tetapi itu akan membunuh backend PgAdmin lainnya. Gunakan kondisi tambahan application_name = ''
Andrew Selivanov
1
Bisakah saya menjalankan pg_terminate_backend jika saya menggunakan pgbouncer?
Henley Chiu
@HenleyChiu Saya tidak mengerti mengapa tidak, meskipun saya belum memeriksanya secara khusus.
Craig Ringer
1
Menjalankan ini tampaknya telah mematikan proses pengirim WAL saya
Joseph Persie
@CraigRinger bahkan koneksi psql dianggap sebagai koneksi idle. Dan mengapa seseorang harus menutup koneksi idle di tempat pertama. Saya memiliki kode yang berjalan lama yang membuat koneksi dengan pg melakukan beberapa operasi dml dan kemudian menunggu pesan melalui antrian dan kemudian melakukan beberapa operasi dml. Sekarang selama periode itu yaitu saat menunggu antrian (untuk pesan) seperti disebutkan di atas bahkan kemudian hubungannya dengan postges idle. mengapa saya harus menutupnya.
Viren
73

Di PostgreSQL 9.6, ada opsi baru idle_in_transaction_session_timeoutyang akan menyelesaikan apa yang Anda gambarkan. Anda dapat mengaturnya menggunakan SETperintah, misalnya:

SET SESSION idle_in_transaction_session_timeout = '5min';
shosti
sumber
1
Ini menyebalkan harus menanyakan sesuatu yang sangat sederhana tetapi saya baru mengenal database secara umum - Bisakah Anda memberikan contoh yang sangat mendasar tentang bagaimana menggunakan fungsi ini?
sg
Adakah yang seperti ini di versi PostgreSQL sebelumnya ??
sdsc81
Tidak, sesuatu yang mirip dengan jawaban lain diperlukan untuk versi sebelumnya.
shosti
Apakah Anda perlu mengatur parameter ini pada setiap restart database? Atau setelah Anda melakukannya sekali Anda bisa melupakan? Terima kasih
fresko
5
SET SESSIONhanya untuk sesi saat ini (ini akan kembali ke default setelah Anda membuka koneksi baru). Anda juga dapat menyetel parameter konfigurasi pada tingkat database menggunakan misalnya ALTER DATABASE SET idle_in_transaction_session_timeout = '5min', atau menggunakan file konfigurasi (lihat postgresql.org/docs/current/static/config-setting.html ).
shosti
22

Di PostgreSQL 9.1, koneksi idle dengan kueri berikut. Ini membantu saya untuk menangkal situasi yang memerlukan restart database. Ini sebagian besar terjadi dengan koneksi JDBC dibuka dan tidak ditutup dengan benar.

SELECT
   pg_terminate_backend(procpid)
FROM
   pg_stat_activity
WHERE
   current_query = '<IDLE>'
AND
   now() - query_start > '00:10:00';
sramay
sumber
1
pg_terminate_backend ada sejak 8.4
Andrew Banks
8

jika Anda menggunakan postgresql 9.6+, maka di postgresql.conf Anda dapat mengatur

idle_in_transaction_session_timeout = 30000 (mdet)

Bertrand David
sumber
0

Solusi yang memungkinkan untuk mengaktifkan batas waktu sesi database tanpa tugas terjadwal eksternal adalah dengan menggunakan ekstensi pg_timeout yang telah saya kembangkan .

pifor
sumber