DbContextPool on uusi ominaisuus, joka esiteltiin ASP.NET Core 2.1:ssä ja joka säästää DbContext-instanssin luomisen ylimääräistä kuormaa, mutta siihen on piilotettu pieni kuoppa. Äskettäin ASP.NET Core -projekti pyöri yhtäjaksoisesti jonkin aikaa, ja lokeihin ilmestyi virhe, jonka mukaan tietokanta-yhteyspooli saavutti suurimman määrän yhteyksiä:
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. osoitteessa System.Data.Common.ADP.ExceptionWithStackTrace(Exception e) Aluksi luulin, että kyseessä oli jokin koodi, joka sai DbContextin hävittämään sen oikein, mutta en löytänyt koodista mitään vihjeitä. Myöhemmin ei ollut mitään muuta epäiltävää, vain DbContextPool, joten yritin poistaa DbContextPoolin, mutta virhe katosi. Se johtui tosiaan DbContextPoolista, mutta mikä saa ihmiset ihmettelemään, on se, että DbContextPool on alun perin tarkoitettu säästämään DbContext-instanssien luomisen ylikuormaa, joten miten se voi kuluttaa enemmän tietokantayhteyksiä, ja tämän projektin kuormitus on hyvin pieni, miten se voi kuluttaa koko yhteyspoolin? Puhuin tästä oudosta ongelmasta viikoittaisessa kokouksessa tänään, ja sitten yhtäkkiä ajattelin, että jokainen DbContext-instanssi täyttää tietokantayhteyden (SqlConnection), ja kun DbContextPool ei ole käytössä, heti pyynnön päätyttyä vastaava DbContext-instanssi poistetaan ja tietokantayhteys palautetaan yhteyspooliin. Kun käytetään DbContextPoolia, DbContextia ei hävitetä, vaan se siirretään takaisin DbContextPooliin pyynnön päätyttyä, ja DbContext palautetaan omaan pooliinsa, mikä tarkoittaa, että sen vastaavaa tietokantayhteyttä ei palauteta siihen yhteyspooliin, johon se kuuluu. Jokainen DbContext DbContextPoolissa vastaa yhtä tietokantayhteyttä, ja jokaiselle lisäDbContextille DbContextPoolissa on yksi vähemmän tietokantayhteys. Kun molemmat poolit ovat eri kokoisia ja DbContextPool on suurempi kuin tietokantayhteyspooli, ongelma syntyy: DbContextPool täyttää DbContextin vapaasti pooliin oman poolinsa koon mukaan (sanotaan, että se on 128), jättäen tietokantayhteyspoolin koon huomiotta (olettaen että se on 100), ja yllä oleva virhe ilmenee, kun 101. DbContext täyttyy. Tämä projekti käyttää oletusasetuksia, aiheuttaako oletusasetus tämän ongelman?
Katsottaessa DbContextPoolin toteutuksen lähdekoodia, löytöpoolin oletuskokoraja on 128
Kun katsoo SqlConnentionin toteutuksen lähdekoodia, huomaat, että yhteyspoolien oletuskokoraja on 100
Oletusasetus laukaisee ongelman, mikä on oikeastaan pieni sudenkuoppa.
Syyn tietäen ratkaisu on yksinkertainen: aseta DbContextPoolin poolSize-arvo pienemmäksi kuin tietokanta-yhteyspoolin Max_Pool_Size
|