A DbContextPool egy új funkció, amelyet ASP.NET Core 2.1-ben vezettek be, és amely megtakarítja a DbContext instance létrehozásának többletköltségeit, de egy kis gödör rejtőzik benne. Nemrégiben egy ASP.NET Core projekt folyamatosan futott egy ideig, majd a naplókban hiba jelent meg, hogy az adatbázis kapcsolati pool elérte a maximális kapcsolatszámot:
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. a System.Data.Common.ADP.ExceptionWithStackTrace(Exception e) címen Eleinte azt hittem, valami kód okozta a DbContext helyes eltüntetését, de nem találtam semmilyen nyomot a kódban. Később igazából nem volt más kételkednivaló, csak a DbContextPool, így megpróbáltam eltávolítani a DbContextPool-ot, de a hiba eltűnt. Valóban a DbContextPool okozta, de ami elgondolkodtatja az embereket, hogy a DbContextPool eredetileg a DbContext instance-ok létrehozásának többletterhelését akarja megtakarítani, szóval hogyan fogyaszthat több adatbázis-kapcsolatot, miközben a projekt terhelése nagyon alacsony, hogyan foghatja el az egész kapcsolati poolt? Erről a furcsa problémáról beszéltem ma a heti értekezleten, majd hirtelen arra gondoltam, hogy minden DbContext példány egy adatbázis-kapcsolatot (SqlConnection) foglal el, és amikor a DbContextPool nincs engedélyezve, amint a kérés véget ér, a megfelelő DbContext példány megszabadul, és az adatbázis-kapcsolat visszakerül a kapcsolati oldalba. A DbContextPool használatakor a DbContext nem kerül eldobásra, hanem a kérés vége után visszakerül a DbContextPoolba, és a DbContext visszakerül a saját oldalába, ami azt jelenti, hogy a megfelelő adatbázis-kapcsolat nem kerül vissza abba a kapcsolati oldalba, amelyhez tartozik. Minden DbContext a DbContextPoolban egy adatbázis-kapcsolatnak felel meg, és minden további DbContext esetén a DbContextPoolban egy adatbázis-kapcsolat kevesebb lesz az adatbázis-kapcsoló poolban. Ha a két pool különböző méretű, és a DbContextPool nagyobb, mint az adatbázis kapcsolati pool, akkor felmerül a probléma, a DbContextPool szabadon tölti ki a DbContext-et a poolba a saját poolja mérete szerint (tegyük fel, hogy 128), figyelmen kívül hagyva az adatbázis-kapcsolat pool méretét (feltételezve, hogy 100), és a fenti hiba akkor következik be, amikor a 101. DbContext megtöltődik. Ez a projekt alapértelmezett beállításokat használ, az alapértelmezett beállítás indítja ki ezt a problémát?
A DbContextPool megvalósítási forráskódját nézve a felfedező pool alapértelmezett méretkorlátja 128
Ha megnézzük a SqlConnention megvalósítási forráskódját, azt találhatod, hogy a kapcsolati poolok alapértelmezett méretkorlátja 100
Az alapértelmezett beállítás indítja el a problémát, ami igazából egy apró buktató.
Ismerve az okot, a megoldás egyszerű: állítsuk be a DbContextPool poolSize-ét kevesebbre, mint az adatbázis kapcsolati pool Max_Pool_Size
|