DbContextPool adalah fitur baru yang diperkenalkan di ASP.NET Core 2.1 yang menghemat overhead pembuatan instance DbContext, tetapi ada lubang kecil yang tersembunyi di dalamnya. Baru-baru ini, proyek ASP.NET Core berjalan terus menerus selama jangka waktu tertentu dan kemudian muncul kesalahan di log bahwa kumpulan koneksi database mencapai jumlah koneksi maksimum:
System.InvalidOperationException: Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached. di System.Data.Common.ADP.ExceptionWithStackTrace(Pengecualian e) Awalnya, saya pikir itu adalah beberapa kode yang menyebabkan DbContext dibuang dengan benar, tetapi saya tidak menemukan petunjuk apa pun dalam kode tersebut. Kemudian, tidak ada lagi yang perlu diragukan, hanya DbContextPool, jadi saya mencoba menghapus DbContextPool, tetapi kesalahan itu menghilang. Hal ini memang disebabkan oleh DbContextPool, tetapi yang membuat orang bertanya-tanya adalah bahwa DbContextPool awalnya dimaksudkan untuk menghemat overhead pembuatan instance DbContext, jadi bagaimana cara mengkonsumsi lebih banyak koneksi database, dan beban proyek ini sangat rendah, bagaimana cara menghabiskan seluruh kumpulan koneksi? Saya berbicara tentang masalah aneh ini pada rapat mingguan hari ini, dan kemudian saya tiba-tiba berpikir bahwa setiap instans DbContext akan menempati koneksi database (SqlConnection), dan ketika DbContextPool tidak diaktifkan, segera setelah permintaan berakhir, instans DbContext yang sesuai akan dibuang, dan koneksi database akan dimasukkan kembali ke kumpulan koneksi. Saat menggunakan DbContextPool, DbContext tidak akan dibuang tetapi akan ditempatkan kembali ke DbContextPool setelah permintaan berakhir, dan DbContext akan ditempatkan kembali ke kumpulannya sendiri, yang berarti bahwa koneksi database yang sesuai tidak akan dikembalikan ke kumpulan koneksi tempat permintaan itu berada. Setiap DbContext di DbContextPool sesuai dengan koneksi database, dan untuk setiap DbContext tambahan di DbContextPool, akan ada satu koneksi database lebih sedikit di kumpulan koneksi database. Ketika kedua kumpulan memiliki ukuran yang berbeda dan DbContextPool lebih besar dari kumpulan koneksi database, masalah muncul, DbContextPool dengan bebas mengisi DbContext ke dalam kumpulan sesuai dengan ukuran kumpulannya sendiri (katakanlah 128), mengabaikan ukuran kumpulan koneksi database (dengan asumsi 100), dan kesalahan di atas akan terjadi ketika DbContext ke-101 terisi. Proyek ini menggunakan pengaturan default, apakah pengaturan default memicu masalah ini?
Melihat kode sumber implementasi DbContextPool, batas ukuran default untuk kumpulan penemuan adalah 128
Melihat kode sumber implementasi SqlConnention, Anda akan menemukan bahwa batas ukuran default untuk kumpulan koneksi adalah 100
Pengaturan default akan memicu masalah, yang sebenarnya merupakan jebakan kecil.
Mengetahui alasannya, solusinya sederhana, atur poolSize DbContextPool ke kurang dari Max_Pool_Size kumpulan koneksi database
|