Supabase 'max clients reached in session mode' di Vercel, dan perbaikan yang malah memperburuknya
Error-nya (EMAXCONNSESSION) max clients reached in session mode - max clients are limited to pool_size: 15. API kami mulai mengembalikan error itu, sementara situs marketing tetap sehat sepenuhnya. Situs marketing memang tidak menyentuh Postgres. Itulah kenapa kegagalan jenis ini tidak disadari. Bagian yang terlihat baik adalah bagian yang tidak butuh database.
Berikut arti error itu, dua kesalahan kami saat memperbaikinya, dan connection string yang benar-benar jalan dari Vercel.
Dua pooler, dua port
Kenapa serverless menghabiskan session mode
Setiap instance fungsi yang hangat menahan pool kecilnya sendiri. Pool kami berisi tiga. Pool di session mode tidak pernah mengembalikan koneksi selama instance masih hangat. Lima instance hangat berarti lima belas koneksi, dan itu batasnya. Request keenam dari mana pun akan gagal.
Daemon armada yang mem-poll tiga endpoint setiap beberapa detik membuat instance tetap hangat sepanjang waktu. Tidak ada yang aneh di situ. Ini hanya aritmetika yang membuat session mode kalah.
Kesalahan pertama: memperbaiki lapisan yang salah lebih dulu
Perbaikan daruratnya adalah max: 1 per instance dan idle timeout dua puluh detik, masih di session mode. Itu berhasil. Instance yang diam mengembalikan slotnya, dan API pulih dalam hitungan menit. Lalu kami memindahkan connection string ke mode transaksi, dan itu langkah yang benar. Tapi kami membiarkan max: 1 tetap ada, dan itu salah.
Kesalahan kedua: pool berisi satu di mode transaksi
Di mode transaksi, satu koneksi per instance membuat setiap query di instance itu mengantre di satu jalur. Polling dari daemon ikut mengantre, request melewati batas waktu dua puluh detik, dan gejalanya berubah dari error 500 menjadi hang. Situs marketing tetap cepat. API berhenti menjawab sama sekali.
Mode transaksi mengembalikan koneksi setelah setiap transaksi, jadi ia butuh pool berukuran normal. Kami mengaturnya ke delapan, dan timeout pun berhenti.
Cara melihatnya sebelum terjadi
Pooler tidak memberi tahu apa pun sampai ia menolak Anda. Postgres sendiri akan memberi tahu, jika Anda bertanya.
select application_name, state, count(*) from pg_stat_activity where datname = 'postgres' group by 1, 2 order by 3 desc;
Jalankan itu di koneksi session saat aplikasi sedang menerima beban normal. Jika jumlahnya merayap mendekati batas dan sebagian besar barisnya idle, Anda tinggal satu menit sibuk lagi dari error itu. Di mode transaksi, query yang sama menunjukkan koneksi didaur ulang, bukan ditimbun.
Connection string yang benar-benar jalan
postgresql://postgres.<project-ref>:<password>@aws-0-<region>.pooler.supabase.com:6543/postgres
- Host-nya adalah pooler, bukan
db.<ref>.supabase.co. Dashboard Supabase mungkin menampilkan host langsung di bawah judul transaction pooler. Itu tetap host langsung. - Username-nya
postgres.<project-ref>di pooler.postgressaja hanya berlaku di host langsung. - Host langsung hanya IPv6, kecuali Anda membeli add-on IPv4. Ia punya record AAAA dan tidak punya record A. Fungsi Vercel tidak bisa menjangkaunya, dan port 6543 memang tidak terbuka di sana.
- Tidak perlu query string untuk postgres.js. Atur
prepare: false. Flag?pgbouncer=trueadalah konvensi Prisma. - Tetap jalankan migrasi di 5432. Drizzle dan tool sejenis butuh koneksi session. Arahkan aplikasi yang di-deploy ke 6543, dan env migrasi lokal Anda ke 5432.
$ dig +short A db.<project-ref>.supabase.co # (nothing) $ dig +short AAAA db.<project-ref>.supabase.co # 2600:1f18:... $ nc -z aws-0-us-east-1.pooler.supabase.com 6543 # succeeded
Ukuran pool, dalam satu tabel
Satu hal terakhir yang layak diketahui. Selama semua ini terjadi, daemon yang tidak bisa menjangkau API menyimpulkan bahwa setiap mesin yang ia kelola sudah mati. Ia bersiap melakukan power cycle. Ceritanya ada di bagaimana batas koneksi database hampir me-reboot Mac pelanggan saya.
Pertanyaan
- Port Supabase mana yang sebaiknya dipakai aplikasi di Vercel?
- 6543, pooler mode transaksi. Session mode di 5432 menahan satu koneksi server per klien dan membatasi proyek di 15. Serverless cepat menghabiskannya.
- Kenapa db.<project-ref>.supabase.co tidak bisa terhubung dari Vercel?
- Host langsung hanya punya alamat IPv6, kecuali Anda membayar add-on IPv4. Fungsi Vercel tidak bisa menjangkaunya lewat IPv6. Pakai host pooler, aws-0-<region>.pooler.supabase.com.
- Username apa yang dibutuhkan pooler?
- postgres.<project-ref>, dengan project ref ditambahkan di belakangnya. postgres saja hanya berlaku di host langsung.
- Apakah saya perlu ?pgbouncer=true di connection string?
- Untuk Prisma, ya. Untuk postgres.js, atur prepare: false di opsi klien. Mode transaksi tidak mendukung prepared statement.
- Berapa ukuran pool untuk tiap mode?
- Session mode: satu atau dua per instance dengan idle timeout yang pendek, karena batasnya lima belas. Mode transaksi: pool normal, lima sampai sepuluh, karena koneksi dikembalikan setelah setiap transaksi.
Hitung angka Anda sendiri dengan kalkulator atau sewa runner.