Knex: Koneksi terputus secara tidak terduga (Postgresql / AWS Lambda)

Dibuat pada 23 Jan 2020  ·  68Komentar  ·  Sumber: knex/knex

Lingkungan

Versi Knex: 0.20.8
Basis data + versi: Postgres 9.5.14
OS: AWS Lambda - Node 12.x

Baru-baru ini, saya melihat peningkatan dalam kesalahan connection terminated unexpectedly . Saya tidak dapat menemukan pola yang terlihat pada saat ini tetapi tidak seperti #3523, tampaknya tidak terjadi setelah aktivitas yang lama. Saya melihat contoh yang berjarak beberapa menit dalam beberapa kasus.

Saya menambahkan beberapa logging ke metode Knex afterCreate dan saya melihat dua kesalahan:

  1. Kesalahan connection terminated unexpectedly
  2. Dan Error [ERR_STREAM_DESTROYED]: Cannot call write after a stream was destroyed - ini tampaknya terjadi pada permintaan pertama atau kedua setelah melihat kesalahan connection terminated unexpectedly .

Saya telah mencoba sejumlah konfigurasi dengan Knex pooling:

  1. { pool: { min: 1, max: 1 } }
  2. { pool: { min: 0 }
  3. { pool: { min: 1 } }

Saya juga mencoba mengatur { pool: { idleTimeoutMillis: 300000 } } sesuai #3523.

Informasi tambahan:

  • Saya mendefinisikan instance Knex saya di luar penangan AWS saya, jadi kumpulan harus digunakan kembali per wadah.
  • Saya menggunakan yang berikut ini untuk fungsi afterCreate saya -- Saya tidak yakin apakah ada cara yang lebih baik untuk mendapatkan kesalahan yang mendasarinya?
function afterCreate(connection, done) {
  connection.on('error', (err) => {
    console.log('POSTGRES CONNECTION ERROR');
    console.error(err)
  });
  done()
}

Hargai bantuan apa pun! Ini membuatku gila :)

PEMBARUAN: satu-satunya perubahan yang saya buat adalah memigrasikan fungsi lambda ke Node 12 dari Node 8 karena AWS menghapus dukungan untuk 8. Sayangnya, sepertinya saya tidak bisa kembali. Fungsi saya yang lain dalam produksi ada di Node 8 dan tidak melihat masalah apa pun

MASALAH DITEMUKAN: untuk alasan apa pun, kembali ke Node 8.x memperbaiki masalah. Masih belum pasti tentang penyebab yang mendasarinya.

Komentar yang paling membantu

Setelah menggali lebih dalam, sepertinya tidak mungkin menggunakan pernyataan yang disiapkan dengan segala jenis penyatuan transaksi di postgres. Dua jenis utama penyatuan adalah penyatuan sesi dan penyatuan transaksi. Penyatuan transaksi tampaknya yang paling umum kinerjanya. Pengumpulan transaksi adalah apa yang digunakan Proxy RDS. node-postgres atau pg tampaknya tidak kompatibel dengan semua jenis penyatuan transaksi jika menggunakan pernyataan yang disiapkan, dan Knex saya yakin selalu menggunakan pernyataan yang disiapkan. Diskusi yang saya mulai ini mungkin lebih baik dipindahkan ke repo pg. Saya akan meninggalkan beberapa tautan di sini:

Semua 68 komentar

sudahkah Anda mencoba mengaitkan beberapa logging ke:

knex.on('query', ...)
knex.on('query-success', ...)
knex.on('query-error', ...)
knex.on('error', ...)

Anda juga dapat memasang kait tarn.js untuk menampilkan apa yang dilakukan kumpulan saat terjadi kesalahan. Contoh tarn ditemukan dari knex.client.pool

@elhigu Saya belum, tapi saya akan mencobanya. Aneh bahwa ini tampaknya hanya terjadi dengan Node 10/12. Terima kasih untuk tipsnya!

Saya memiliki perilaku yang sama dengan MySQL.

@FreddyJD ah, senang mengetahui bahwa saya bukan satu-satunya.

Seperti yang saya sebutkan di atas, kembali ke Node 8.x memecahkan masalah. Karena itu, saya harus menggunakan runtime Node 8 khusus di Lambda karena secara resmi sudah tidak digunakan lagi sehingga fungsi tidak dapat lagi dibuat atau diperbarui ke Node 8.

Sudahkah Anda menemukan bahwa Node 8 menyelesaikan masalah?

Saya juga mengalami masalah yang sama dengan Postgres

@jamesdixon Kami telah membaca tentang pengaturan context.callbackWaitsForEmptyEventLoop = false; , sehingga fungsi dimatikan ketika loop acara selesai. Saya harus menunggu sampai kami merilisnya.

Saya menemukan masalah di Node10.X

@FreddyJD dalam produksi yang kami gunakan

context.callbackWaitsForEmptyEventLoop = false;

dan masalahnya masih ada
Saya baru saja membuat rilis baru tempat saya bekerja dan menghapus baris itu, kami harus menunggu beberapa jam untuk memantau karena masalah terjadi secara acak

@FreddyJD @mouhannad-sh fungsi kami juga menjalankan context.callbackWaitsForEmptyEventLoop = false; dalam produksi tetapi seperti yang disebutkan, masalah tidak muncul hingga Node 10+. Saya kira hal yang menarik adalah ini terjadi untuk MySQL dan Postgres. Kemungkinan besar itu adalah masalah yang terkait dengan Knex?

mungkin, kami telah melihat kesalahan yang sama terjadi lagi setelah menghapus baris itu

ada solusi? mendesak bagi kami. Terima kasih

@592da kami akhirnya menggunakan runtime Node 8 khusus, yang berhasil untuk kami. Tidak ideal, tetapi kami tidak memiliki waktu atau sumber daya untuk menggali lebih dalam masalah ini -- kami hanya perlu beberapa hal untuk bekerja :)

Halo! Saya akan mencoba untuk menyelidiki ini di hari berikutnya atau lebih. (Maaf -- saat ini saya membantu dengan permintaan penggabungan yang besar. Saya ingin menyelesaikannya sebelum membuat perubahan tambahan pada kode)

@jamesdixon : Bisakah Anda memberikan jejak tumpukan penuh untuk "Connection terminated unexpectedly" yang Anda amati?

Berdasarkan penyelidikan awal saya, sepertinya paket "pg" kemungkinan besar melempar kesalahan ini (sebagai lawan dari "knex" membuangnya). Kesalahan tampaknya terjadi ketika:

  1. Sesuatu telah menutup koneksi level rendah dengan server PG, tapi
  2. Pustaka "pg" belum mengharapkan koneksi ini berakhir. (yaitu: ada kelas Client tingkat yang lebih tinggi yang seharusnya memulai pemutusan koneksi. Itu melempar kesalahan "Connection terminated unexpectedly" ketika ia melihat bahwa _something else_ mengakhiri koneksi)

Sejauh yang saya tahu, "knex" hanya berinteraksi dengan kelas "pg" library Client library. Ini menunjukkan (tetapi tidak membuktikan) bahwa sesuatu yang lain mungkin mematikan koneksi tingkat yang lebih rendah.

Karena penasaran: apakah package-lock.json proyek Anda berubah ketika Anda memutakhirkan dari node 8 -> node 12 ? Jika demikian: apakah versi perpustakaan "pg" berubah?

@briandamaged Anda benar pada jejak tumpukan yang menunjuk ke klien pg . Sepertinya orang lain membuka masalah serupa di sini: https://github.com/brianc/node-postgres/issues/2112

Error: select * from "appointment" where "id" = $1 limit $2 - Connection terminated unexpectedly
at Connection.con.once (/var/task/node_modules/pg/lib/client.js line 255 col 8)
: new Error('Connection terminated unexpectedly')
at Object.onceWrapper (events.js line 313 col 29)
at emitNone (events.js line 106 col 12)
at Connection.emit (events.js line 208 col 6)
at Socket.<anonymous> (/var/task/node_modules/pg/lib/connection.js line 78 col 9)
self.emit('end')
at emitOne (events.js line 116 col 12)
at Socket.emit (events.js line 211 col 6)
at TCP._handle.close [as _onclose] (net.js line 561 col 11)

Biarkan saya memeriksa pertanyaan Anda tentang package-lock.json .

@FreddyJD

Saya memiliki perilaku yang sama dengan MySQL.

Bisakah Anda memberikan pesan kesalahan / stacktrace lengkap? Saya menduga Anda mengamati kesalahan "Connection ENDED unexpectedly" kata-kata serupa, yang mungkin menunjuk ke masalah terpisah.

@FreddyJD

(Untuk memperjelas: kesalahan "Connection terminated unexpectedly" tidak dihasilkan oleh Knex. Namun, Knex menghasilkan kesalahan 'Connection ended unexpectedly' melalui jalur kontrol terpisah)

Di sisi "pg" : sepertinya ada bug di perpustakaan "pg" itu sendiri. Akibatnya, perpustakaan pg tidak menyadari bahwa koneksi Client telah berakhir sampai setelah mencoba menggunakannya lagi. Ini kemudian menghasilkan kesalahan "Connection terminated unexpectedly" .

Menariknya: setelah kesalahan ini terjadi, masalahnya akan "diperbaiki" di sisi pg . Setelah itu, knex mendeteksi bahwa koneksi klien telah berakhir, mengeluarkan peringatan "Connection ended unexpectedly" , dan memperbaiki kumpulan koneksinya.

Pembaruan cepat lainnya di bagian depan ini:

Saat ini, sepertinya "pg" dan "knex" memiliki bug yang sama dalam implementasi kumpulan masing-masing. Khususnya: tidak ada implementasi kumpulan yang tampaknya memvalidasi ulang koneksi sebelum menyerahkannya kepada pemanggil. Ini memberikan kesempatan untuk koneksi ke yang ditutup secara diam-diam saat mereka duduk diam di dalam kolam.

Jadi, beberapa langkah jangka pendek:

  1. Tim "pg" saat ini mencoba memverifikasi perbaikan yang diusulkan . Jika itu berhasil, maka
  2. Mereka akan memfaktorkan ulang perbaikan dan membuat beberapa detail tersedia di API yang dapat diakses publik. (yaitu: daripada harus memeriksa detail internal dari beberapa objek yang sangat bersarang)
  3. Setelah itu, "knex" dapat ditingkatkan untuk memanfaatkan API yang menghadap publik ini dan memperbaiki masalah dalam penyatuan koneksi PG-nya.

cc: @brianc

Saya telah menyarankan bahwa masalahnya sebenarnya adalah beberapa server proxy di infra jaringan lambda AWS, yang akan bertindak seperti koneksi baik-baik saja sampai beberapa permintaan nyata dikirim melaluinya. Mungkin implementasi postgres AWS hanya berfungsi berbeda

Bagaimanapun, alangkah baiknya jika driver pg dapat mengenali koneksi yang terputus secara internal dan mengeluarkan kesalahan atau mengakhiri acara untuk instance klien itu. Kemudian knex bisa berlangganan itu dan mengatur semuanya sehingga koneksi yang terputus akan dibuang dari kumpulan selama validasi.

@elhigu : Setuju -- ada kemungkinan besar bahwa itu adalah bagian dari infrastruktur jaringan yang membuang koneksi secara diam-diam. Harapannya, ada cara untuk mendeteksi kondisi ini. Jika demikian, maka implementasi kumpulan dapat memverifikasi bahwa koneksi masih valid sebelum menyerahkannya kepada pemanggil.

Apakah kalian punya pemikiran tentang mengapa ini akan hadir dengan Node 10 / 12 tetapi tidak dengan Node 8?

Hal pertama yang terlintas dalam pikiran adalah perubahan logika EventEmitter antara Node 8 dan Node 10.

Saya mencoba menggunakan runtime kustom nodejs versi 8 untuk lambda, dan masih terjadi masalah.
@kibertoad @jamesdixon @briandamaged

Ada kemungkinan besar bahwa itu adalah bagian dari infrastruktur jaringan yang membuang koneksi secara diam-diam. Harapannya, ada cara untuk mendeteksi kondisi ini. Jika demikian, maka implementasi kumpulan dapat memverifikasi bahwa koneksi masih valid sebelum menyerahkannya kepada pemanggil.

Saya pikir ini adalah intinya. AWS membekukan Lambda untuk penggunaan nanti, yang mencakup penunjuk memori (variabel dan semacamnya) yang telah dibuat dalam lingkup global ( posting ini di Medium merangkumnya) .
Saya akan menganggap ini termasuk klien yang dikumpulkan, yang tidak pernah mendapat kesempatan untuk bereaksi terhadap penutupan Soket.

Dari dokumentasi AWS :

Setelah fungsi Lambda dijalankan, AWS Lambda mempertahankan konteks eksekusi selama beberapa waktu untuk mengantisipasi pemanggilan fungsi Lambda lainnya. Akibatnya, layanan membekukan konteks eksekusi setelah fungsi Lambda selesai, dan mencairkan konteks untuk digunakan kembali, jika AWS Lambda memilih untuk menggunakan kembali konteks saat fungsi Lambda dipanggil lagi. Pendekatan penggunaan kembali konteks eksekusi ini memiliki implikasi berikut: Objek yang dideklarasikan di luar metode pengendali fungsi tetap diinisialisasi, memberikan optimasi tambahan saat fungsi dipanggil kembali. Misalnya, jika fungsi Lambda Anda membuat koneksi database, alih-alih membangun kembali koneksi, koneksi asli akan digunakan dalam pemanggilan berikutnya. Kami menyarankan untuk menambahkan logika dalam kode Anda untuk memeriksa apakah ada koneksi sebelum membuatnya.

@jamesdixon ini telah ada selama AWS lambda dengan pg telah ada.

@michaelseibt

AWS membekukan Lambda untuk penggunaan nanti, yang mencakup penunjuk memori (variabel dan semacamnya) yang telah dibuat dalam lingkup global (postingan di Medium ini merangkumnya).
Saya akan menganggap ini termasuk klien yang dikumpulkan, yang tidak pernah mendapat kesempatan untuk bereaksi terhadap penutupan Soket.

Saya rasa itu tidak cukup untuk membuat knex / pg bertindak seperti itu. Padahal skenario ini mudah untuk diuji. Menambahkan misalnya penundaan 1 detik dalam memulai fungsi lambda sebelum mendapatkan koneksi dari kumpulan akan memberi knex/pg/node eventloop cukup waktu untuk memperhatikan bahwa koneksi terputus sebelum diambil dari kumpulan.

Kami menyarankan untuk menambahkan logika dalam kode Anda untuk memeriksa apakah ada koneksi sebelum membuatnya.

Knex memiliki logika bawaan seperti ini.

Knex memiliki logika bawaan seperti ini.

@elhigu : Sudah built-in, tetapi implementasi dasar masih bergantung pada Event tertentu yang dipecat. Peristiwa ini melampirkan bidang __knex__disposed ke objek connection untuk menunjukkan bahwa koneksi telah ditutup. Bidang ini kemudian diperiksa oleh pool sebelum menyerahkan connection .

Jadi, saya yakin inilah alasan mengapa beberapa pengguna akhir masih melihat masalah ini di knex . Jika Peristiwa tidak dipicu/ditangani dengan cukup cepat, maka koneksi dapat lolos dari celah.

Untungnya, knex juga menyediakan hook sehingga setiap Dialect dapat menambahkan logika validasi connection . Untuk Client_PG , metode ini saat ini hanya mengembalikan true . Jika tim pg menambahkan metode publik untuk memeriksa status Client , maka kita dapat memperbarui kait Client_PG untuk menanyakan status ini.

(Maaf jika itu membingungkan. Baik proyek knex dan pg menggunakan istilah Client untuk merujuk pada hal yang sedikit berbeda. A pg Client adalah knex connection .)

Atau, kita dapat meminta knex membuka tudung pada objek pg Client dan mencari tahu sendiri. Namun, ini akan menggabungkan knex dengan implementasi pg , yang akan menjadi masalah di masa mendatang.

@jamesdixon ini telah ada selama AWS lambda dengan pg telah ada.

@elhigu Saya tidak yakin apa yang Anda maksud secara khusus? Pasti ada perubahan perilaku antara Node 8 dan Node 10/12 bahkan jika internal yang mendasari di Knex/pg tetap sama.

@592da Saya tidak yakin mengapa menggunakan runtime Node 8 tidak bekerja untuk Anda. Itu menyelesaikan masalah segera untuk saya. Bisakah Anda memverifikasi bahwa di konsol AWS bahwa fungsi Anda pasti diatur untuk menggunakan runtime Node 8 Anda?

Wow -- GitHub benar-benar bermasalah akhir-akhir ini! HTTP 500 tanggapan di semua tempat!

Anyhoo - masalah mendasar tampaknya adalah bahwa implementasi kumpulan knex dan pg mengandalkan Acara untuk mendeteksi/mengusir koneksi tertutup. Tapi, jika Acara ini tidak ditangani tepat waktu, maka kumpulan dapat menyerahkan koneksi tertutup.

@kibertoad menyebutkan bahwa ada perubahan pada kelas EventEmitter antara node 8 dan node 10 . Saya tidak tahu detail perubahan ini, tetapi perubahan tersebut berpotensi memengaruhi urutan pemrosesan Acara. Jika demikian, maka ini juga dapat menjelaskan mengapa beberapa pengguna akhir tidak mengamati masalah di node 8 .

@elhigu Saya tidak yakin apa yang Anda maksud secara khusus? Pasti ada perubahan perilaku antara Node 8 dan Node 10/12 bahkan jika internal yang mendasari di Knex/pg tetap sama.

Maksud saya, saya ingat bahwa ada laporan yang belum terselesaikan tentang knex yang tidak berfungsi dengan baik dengan AWS lambda sebelum masalah ini. Tetapi sekarang saya mencari mereka sepertinya tentang transaksi yang menggantung https://github.com/knex/knex/issues/2445

Jadi saya berdiri dikoreksi. Ini mungkin tidak terkait dengan masalah ini.

@briandamaged

@elhigu : Sudah built-in, tetapi implementasi dasar masih bergantung pada Event tertentu yang dipecat. Peristiwa ini melampirkan bidang __knex__disposed ke objek koneksi untuk menunjukkan bahwa koneksi telah ditutup. Bidang ini kemudian diperiksa oleh kumpulan sebelum menyerahkan koneksi.

Benar. Itu sebabnya saya menyarankan agar menambahkan penundaan sebelum kueri dibuat dapat memungkinkan loop peristiwa simpul memiliki waktu untuk mengenali bahwa koneksi telah berakhir/sudah terputus ketika masih berada di kumpulan.

Meskipun saya tidak tahu bagaimana soket TCP node mengenali ini. Jika itu terjadi dengan fitur keealive soket TCP sepertinya penundaan harus sangat besar sampai ia menyadarinya. https://stackoverflow.com/questions/18614176/why-nodejs-keepalive-does-not-seem-to-work-as-expected

Jadi saya kira jika ini berfungsi dengan Node 8 pasti ada cara lain untuk memperhatikannya.

Jadi, saya percaya inilah alasan mengapa beberapa pengguna akhir masih melihat masalah ini di knex. Jika Peristiwa tidak dipicu/ditangani dengan cukup cepat, maka koneksi dapat lolos dari celah.
Untungnya, knex juga menyediakan pengait sehingga setiap Dialek dapat menambahkan logika validasi koneksinya sendiri. Untuk Client_PG, metode ini saat ini baru saja mengembalikan nilai true. Jika tim pg menambahkan metode publik untuk memeriksa status Klien, maka kami dapat memperbarui kait Client_PG untuk menanyakan status ini.
Atau, kita bisa meminta knex membuka kap pada objek pg Client dan mencari tahu sendiri. Tapi, ini akan berpasangan dengan implementasi pg saat ini, yang akan bermasalah di masa depan.

@brianc selalu sangat membantu dengan menyediakan API yang diperlukan untuk mencegahnya. Jika masalahnya benar-benar dapat dikenali di dalam driver pg, saya yakin kami mendapatkan beberapa cara resmi untuk memeriksanya :)

Saya hanya berharap akan ada cara untuk memeriksanya dari objek koneksi, tanpa perlu membuat kueri tambahan. Menambahkan kueri dummy sebelum mendapatkan koneksi dari kumpulan tidak akan menjadi perilaku default yang sesuai karena menambahkan terlalu banyak overhead. Padahal itu bisa diganti dalam konfigurasi pool ketika knex digunakan dengan lambda.

Tarn.js juga saat ini tidak mendukung fungsi validasi async (saya mulai menulis dukungan untuk itu, tetapi belum selesai, diperlukan perubahan yang cukup besar untuk memungkinkannya).

@elhigu : ketika saya mengatakan "kueri", maksud saya "kueri metode predikat yang kembali secara sinkron". Saya sebenarnya sedang dalam proses menerapkan cabang eksperimental di knex untuk ini. Jika eksperimen berhasil, maka tim pg dapat mengintegrasikan konsep / mengekspos API publik untuknya.

(Sayangnya, saya menghadapi hambatan kecil saat ini. Tampaknya beberapa tes unit Postgres mencoba menyambung ke port yang salah. Saya tidak yakin mengapa perbaikan ini tiba-tiba mengungkap masalah itu)

Jika tim pg menambahkan metode publik untuk memeriksa status Klien, maka kami dapat memperbarui kait Client_PG untuk menanyakan status ini.

Saya dapat menambahkan ini - apakah Anda akan membuka masalah pada node-postgres & menguraikan apa yang Anda ingin metode ini untuk memeriksa? Kami dapat menguraikan detailnya di sana.

@brianc : Ah -- ini adalah hal yang sama yang kita bahas dalam PR ini:

https://github.com/brianc/node-postgres/pull/2121

Secara khusus, saya membuat build eksperimental yang akan menggunakan properti stream.readable dan stream.writable . (Dan mungkin beberapa lainnya). Setelah ini siap, saya berharap @jamesdixon dapat mencobanya pada instance Lambda-nya dan melihat apakah masalahnya tetap ada.

Ah -- ini hal yang sama yang kita bahas dalam PR ini:

oh oke kita bisa menggunakan PR itu saya kira untuk melanjutkan diskusi. Saya akan menindaklanjuti di sana.

@jamesdixon : Saya telah membuat build Knex eksperimental di sini:

https://github.com/briandamaged/knex/tree/experiment/aws-disconnections

Apakah mungkin bagi Anda untuk mencoba membuat ulang masalah menggunakan build ini? Jika berhasil, maka ini akan membantu kami menemukan solusi yang lebih permanen. Terima kasih!

cc: @brianc @elhigu

Ya! Saya harus kembali ke komputer saya dalam beberapa jam.

🙏
Pada 27 Februari 2020, 10:50 -0700, Brian Lauber [email protected] , menulis:

@jamesdixon : Saya telah membuat build Knex eksperimental di sini:
https://github.com/briandamaged/knex/tree/experiment/aws-disconnections
Apakah mungkin bagi Anda untuk mencoba membuat ulang masalah menggunakan build ini? Jika berhasil, maka ini akan membantu kami menemukan solusi yang lebih permanen. Terima kasih!
cc: @brianc @elhigu

Anda menerima ini karena Anda disebutkan.
Balas email ini secara langsung, lihat di GitHub, atau berhenti berlangganan.

@briandamaged Saya telah memperbarui Lambda saya dengan cabang ini tetapi mungkin perlu beberapa saat untuk benar-benar menentukan apakah masalah masih ada.

@jamesdixon : Sounz bagus!

Berdasarkan diskusi saat ini, saya tidak terlalu yakin bahwa eksperimen ini akan berhasil. Tapi, kita mungkin akan terkejut. 🙏

@jamesdixon :

biasanya perbaikan semacam ini berfungsi hingga fitur dirilis dan kemudian muncul lagi

@briandamaged belum. Saya perlu mendorong beberapa "volume" melalui lambda yang dimaksud untuk melihat apakah masalah dipicu. Saya harus menjalankan beberapa pengujian besok yang seharusnya berhasil. Mohon maaf atas keterlambatannya.

Jika ada orang lain yang ingin mencobanya, alangkah baiknya jika ada konfirmasi tambahan apakah berhasil atau tidak 👍

@briandamaged maaf atas keterlambatannya. Saya akhirnya mendorong versi baru ini ke pekerjaan Lambda saya yang menangani pengiriman email dan sayangnya, masalah muncul dalam beberapa menit

@jamesdixon - Ah, sial. Yah, saya rasa itu menjawab pertanyaan _that_!

Jadi, saya mulai berpikir bahwa kita mungkin perlu mengambil pendekatan yang berbeda secara fundamental untuk memecahkan masalah ini. Tampaknya beberapa asumsi knex saat ini tentang penyatuan/retensi koneksi mungkin tidak kompatibel dengan Lambda.

Dalam waktu dekat, Anda dapat mencoba memindahkan logika penyiapan/penghancuran kolam Anda ke pengendali Lambda, seperti yang disebutkan dalam komentar ini:

https://github.com/brianc/node-postgres/issues/2112#issuecomment -592459198

Agaknya, ini akan membatasi masa pakai setiap kumpulan (dan dengan demikian koneksinya) ke satu transaksi Lambda.

Halo semuanya,

Apakah ada yang mencoba proxy RDS Lambda dengan Knex?

https://aws.amazon.com/blogs/compute/using-amazon-rds-proxy-with-aws-lambda/

Apakah menurut Anda ini dapat membantu mengurangi masalah dengan connection terminated unexpectedly ?

Saya pikir saya mungkin mengalami masalah dengan Knex dan RDS Lambda Proxy. Semua atau sebagian besar koneksi database saya disematkan, dan saya pikir itu karena pernyataan yang disiapkan. Apakah Knex menggunakan pernyataan yang disiapkan atau protokol kueri yang diperluas untuk semua kueri secara default? Apakah ada cara untuk mematikannya?

Knex membuat pernyataan baru yang disiapkan pada setiap kueri. Itu tidak bisa dimatikan. Protokol kueri yang diperluas, saya kira tergantung bagaimana Anda mengatur konfigurasi driver. Knex tidak tahu apa-apa tentang itu.

@lastmjs Saya cukup yakin saya melihat masalah ini beberapa waktu lalu dan memperbarui ke versi terbaru pg memperbaikinya 👍

@chrisjhoughton Saya sudah menggunakan 8.2.1 dari pg , sekarang saya memperbarui 8.3.3 . Berapa lama Anda pikir Anda melihat ini? Saya akan segera menguji

@lastmjs buruk, kami masih melihatnya. V masalah kecil sekalipun.

@chrisjhoughton Anda mengatakan itu masalah kecil bagi Anda? Dokumentasi Proxy RDS mengatakan bahwa protokol kueri yang diperluas menyebabkan penyematan sesi ... tidakkah semua atau hampir semua kueri berparameter menggunakan protokol kueri yang diperluas? Jika Anda memiliki masalah kecil dengan ini, saya tidak yakin mengapa saya mengalami masalah besar.

Kami belum mengalihkan aplikasi Sequelize kami ke proxy RDS, tetapi kami melihatnya di aplikasi lain menggunakan proxy RDS dengan Knex (yang juga menggunakan pg ) yang menyebabkan setiap permintaan gagal. Memperbarui pg dan knex ke versi terbaru memperbaikinya. Maaf saya belum bisa membantu di bagian Sequelize - meskipun kami berencana untuk segera beralih ke proxy RDS.

Setelah menggali lebih dalam, sepertinya tidak mungkin menggunakan pernyataan yang disiapkan dengan segala jenis penyatuan transaksi di postgres. Dua jenis utama penyatuan adalah penyatuan sesi dan penyatuan transaksi. Penyatuan transaksi tampaknya yang paling umum kinerjanya. Pengumpulan transaksi adalah apa yang digunakan Proxy RDS. node-postgres atau pg tampaknya tidak kompatibel dengan semua jenis penyatuan transaksi jika menggunakan pernyataan yang disiapkan, dan Knex saya yakin selalu menggunakan pernyataan yang disiapkan. Diskusi yang saya mulai ini mungkin lebih baik dipindahkan ke repo pg. Saya akan meninggalkan beberapa tautan di sini:

Hai semuanya, saya juga mengalami perilaku ini dengan pengaturan Postgres + NLB

Jika saya mengerti dengan benar ini bukan hanya masalah Lambda tetapi hanya koneksi yang terputus secara umum. NLB memiliki perilaku yang rusak ini, itu hanya akan habis waktu setelah menganggur selama 350-an, SILEN TANPA memberi tahu klien. Pada titik ini, knex/pg tidak tahu koneksi sudah ditutup, jadi ketika permintaan berikutnya masuk, knex/pg akan mencoba terhubung dengan koneksi sebelumnya, kemudian menyadari koneksi sudah terputus, dan akan membuat koneksi terputus tiba-tiba kesalahan . Blog ini merangkum perilaku ini dengan jelas.

Langkah-langkah untuk mereproduksi:

  1. Letakkan NLB di depan server Postgres Anda
  2. Hubungkan skrip Anda ke NLB alih-alih ke server Postgres secara langsung
  3. Buat satu permintaan/kueri sukses, untuk memicu kumpulan
  4. Tunggu selama 350+ detik
  5. Buat permintaan/permintaan lagi, Anda akan melihat koneksi terputus secara tak terduga.

Oh dalam kasus saya, psql juga menghadapi masalah yang sama, yang seharusnya tidak menjadi masalah untuk alat interaktif seperti psql. Tetapi untuk knex/pg, harapan saya adalah mencoba lagi secara internal ketika menyadari koneksi sudah putus.

Tetapi untuk knex/pg, harapan saya adalah mencoba lagi secara internal ketika menyadari koneksi sudah putus.

Ini tidak dapat bekerja dengan kuat misalnya karena transaksi. Anda harus mengonfigurasi kumpulan Anda untuk memiliki koneksi min: 0 dan mengatur idleTimeoutMillis menjadi seperti 300000ms sehingga kumpulan akan membuang koneksi sebelum server melakukannya.

Tetapi untuk knex/pg, harapan saya adalah mencoba lagi secara internal ketika menyadari koneksi sudah putus.

Ini tidak dapat bekerja dengan kuat misalnya karena transaksi. Anda harus mengonfigurasi kumpulan Anda untuk memiliki koneksi min: 0 dan mengatur idleTimeoutMillis menjadi seperti 300000ms sehingga kumpulan akan membuang koneksi sebelum server melakukannya.

Ya, saya membaca tentang min: 0 dan idleTimeoutMillis di halaman edisi lain, mencobanya, tetapi sejauh ini tidak berhasil, kesalahan yang sama masih terjadi. Jadi saya masih mencoba untuk mencari tahu ini.

@jamesdixon
@rendyfebry

Coba ini:
pool.min: 0
pool.idleTimeoutMillis: < whatever your server value for closing idle client connections is
Memicu pemeriksaan koneksi idle di pool di awal handler Anda
knex.context.client.pool.check()

@EmilIvanov @elhigu

Lupa memperbarui, ya set idleTimeoutMillis < NLB timeout + min: 0 bekerja pada versi Knex yang lebih baru.

Masalah saya adalah, saya menggunakan Knex yang sangat lama yang masih menggunakan generic-pool alih-alih tarn , dan idleTimeoutMillis sebenarnya milik tarn . Jadi saya baru saja memperbarui Knex saya, dan itu berhasil.

Kami telah mencoba untuk men-debug situasi yang sama ini dengan catatan dari ini bersama dengan masalah lain yang dirujuk. Tidak yakin apakah ini membantu, tetapi kami hanya melihat batas waktu koneksi terjadi ketika kami menempatkan lambda di dalam VPC. Akses ke database melalui VPC benar dan semua permintaan berhasil, tetapi setelah beberapa waktu, Connection terminated unexpectedly terjadi. Kami mencoba minimal 1 AZ di VPC sehingga hanya 1 proses yang muncul, tetapi proses itu tidak akan menahan koneksi dengan cara yang sama ketika hanya ditempatkan di subnet publik.

Saya dapat menghentikan 'Koneksi terputus secara tidak terduga' di Lambda Node.js 12.x/Knex 0.19.5/Aurora PostgreSQL dengan menambahkan opsi konstruktor knex :

acquireConnectionTimeout: 5000,
pool: {
  min: 0,
  max: 10,
  createTimeoutMillis: 8000,
  acquireTimeoutMillis: 8000,
  idleTimeoutMillis: 8000,
  reapIntervalMillis: 1000,
  createRetryIntervalMillis: 100,
  propagateCreateError: false
}

Tolong jangan set propagateCreateError: false itu akan membuat knex berperilaku buruk.

https://github.com/knex/knex/issues/3455#issuecomment -535554401
https://github.com/knex/knex/issues/3447#issuecomment -535577333
https://github.com/knex/knex/issues/3362#issuecomment -513288860
https://github.com/knex/knex/issues/3310#issuecomment-506105627

Saya berpikir bahwa mungkin kita harus mengatur knex untuk membuat kesalahan jika seseorang melakukan itu.

@elhigu terima kasih, saya mendapat saran dari posting blog ini: https://deniapps.com/blog/setup-aws-lambda-to-use-amazon-rds-proxy

@maxogden Saya minta maaf karena memberikan informasi yang salah. Saya percaya bahwa saya bermaksud menetapkan nilai itu menjadi true . Saya menyebutkan pengaturan di banyak tempat termasuk yang ini , dan semuanya disetel ke true , kecuali yang Anda gunakan. Tapi seperti yang dikatakan @elhigu , pengaturan progapateCreateError tidak boleh disentuh, jadi saya telah menghapusnya dari semua contoh konfigurasi di blog saya.

@elhigu , hanya ingin tahu, mengapa tidak menetapkan nilai ini menjadi hanya-baca di perpustakaan Anda jika Anda tidak suka pengguna menyentuhnya?

@elhigu , hanya ingin tahu, mengapa tidak menetapkan nilai ini menjadi hanya-baca di perpustakaan Anda jika Anda tidak suka pengguna menyentuhnya?

Kami hanya tidak ingin menyentuh konfigurasi kumpulan yang diteruskan secara langsung ke tarn.js . Misalnya seseorang dapat mengganti panggilan balik membuat/menghancurkan dengan yang rusak jika diinginkan. Juga ada beberapa kasus di mana sebenarnya seseorang ingin mengatur parameter itu false , tetapi orang perlu tahu persis apa yang dilakukan dalam kasus itu.

Oke menghapus progapateCreateError mengembalikan kesalahan Connection terminated unexpectedly dalam produksi Lambda. Perbaikan peretasan saya adalah melakukan kueri pengujian pada setiap doa lambda

const knexTestQuery = async () => {
  try {
    // do a test query to make sure the knex connection pool is ready to go after lambda unfreeze
    knex('events').select('*').first()
  } catch (err) {
    // log but otherwise ignore errors here
    logger.warn('test query error', err.message)
  }
}

Saya percaya masalahnya adalah ketika lambda berubah dari keadaan beku menjadi dicairkan dan kemudian mencoba melakukan kueri, ia memiliki peluang untuk mengambil klien yang buruk dari kumpulan pg (catatan: instance knex hanya dibuat pada waktu alokasi fungsi lambda , tetapi suatu fungsi dapat dibekukan dan dicairkan beberapa kali dalam siklus hidup instance fungsi). Melakukan kueri pengujian ini akan menangkap klien yang buruk dan menyebabkan kumpulan untuk menyembuhkan dirinya sendiri sebelum kueri saya yang sebenarnya berjalan. Saya memiliki masalah yang sama dengan ioredis , tetapi ioredis menyediakan API untuk menghubungkan dan memutuskan, jadi pada setiap doa lambda saya mulai dengan redis.connect() dan pada akhirnya saya lakukan redis.disconnect() . Saya tidak tahu cara memutuskan dan menyambungkan kembali instance knex tanpa merusak dan membuatnya kembali, jadi saya melakukan metode kueri uji peretasan

putuskan dan sambungkan kembali instance knex tanpa merusak dan membuat ulang

await knex.destroy();
knex.init();

harus menjatuhkan koneksi lama dan menginisialisasi ulang kumpulan. Ini adalah misteri mengapa pg tidak mendapatkan peristiwa koneksi terputus selama tidur.

Kami mungkin juga menambahkan opsi ke kumpulan untuk memaksa siklus panen berjalan, yang dapat menghapus semua koneksi lama dari kumpulan: https://github.com/Vincit/tarn.js/issues/56

ada berita tentang ini? Saya memiliki 3 lingkungan dengan kode yang sama di AWS...akun yang berbeda. Tiba-tiba saya mulai menerimanya di salah satu dari mereka. Tidak di yang lain.

Lingkungan

Versi Knex: 0.20.8
Basis data + versi: Postgres 9.5.14
OS: AWS Lambda - Node 12.x

Baru-baru ini, saya melihat peningkatan dalam kesalahan connection terminated unexpectedly . Saya tidak dapat menemukan pola yang terlihat pada saat ini tetapi tidak seperti #3523, tampaknya tidak terjadi setelah aktivitas yang lama. Saya melihat contoh yang berjarak beberapa menit dalam beberapa kasus.

Saya menambahkan beberapa logging ke metode Knex afterCreate dan saya melihat dua kesalahan:

  1. Kesalahan connection terminated unexpectedly
  2. Dan Error [ERR_STREAM_DESTROYED]: Cannot call write after a stream was destroyed - ini tampaknya terjadi pada permintaan pertama atau kedua setelah melihat kesalahan connection terminated unexpectedly .

Saya telah mencoba sejumlah konfigurasi dengan Knex pooling:

  1. { pool: { min: 1, max: 1 } }
  2. { pool: { min: 0 }
  3. { pool: { min: 1 } }

Saya juga mencoba mengatur { pool: { idleTimeoutMillis: 300000 } } sesuai #3523.

Informasi tambahan:

  • Saya mendefinisikan instance Knex saya di luar penangan AWS saya, jadi kumpulan harus digunakan kembali per wadah.
  • Saya menggunakan yang berikut ini untuk fungsi afterCreate saya -- Saya tidak yakin apakah ada cara yang lebih baik untuk mendapatkan kesalahan yang mendasarinya?
function afterCreate(connection, done) {
  connection.on('error', (err) => {
    console.log('POSTGRES CONNECTION ERROR');
    console.error(err)
  });
  done()
}

Hargai bantuan apa pun! Ini membuatku gila :)

PEMBARUAN: satu-satunya perubahan yang saya buat adalah memigrasikan fungsi lambda ke Node 12 dari Node 8 karena AWS menghapus dukungan untuk 8. Sayangnya, sepertinya saya tidak bisa kembali. Fungsi saya yang lain dalam produksi ada di Node 8 dan tidak melihat masalah apa pun

MASALAH DITEMUKAN: untuk alasan apa pun, kembali ke Node 8.x memperbaiki masalah. Masih belum pasti tentang penyebab yang mendasarinya.

Saya menurunkan versi ke node 8.x dan tidak berhasil

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

arconus picture arconus  ·  3Komentar

koskimas picture koskimas  ·  3Komentar

fsebbah picture fsebbah  ·  3Komentar

mattgrande picture mattgrande  ·  3Komentar

legomind picture legomind  ·  3Komentar