ASP.NET ve SQL Server arasındaki bağlantı havuzu sorununu nasıl çözebilirim?


211

Son birkaç gün, web sitemizde bu hata mesajını çok fazla görüyoruz:

"Zaman aşımı süresi doldu. Havuzdan bağlantı alınmadan önce geçen zaman aşımı süresi. Bu, tüm havuzlanmış bağlantılar kullanımda olduğu ve maksimum havuz boyutuna ulaşıldığı için oluşmuş olabilir."

Bir süredir kodumuzda hiçbir şey değiştirmedik. Kapatmadım, ancak her şeyi iyi buldum açık bağlantıları kontrol etmek için kodu revize.

  • Bunu Nasıl Çözebilirim?

  • Bu havuzu düzenlemem gerekiyor mu?

  • Bu havuzun maksimum bağlantı sayısını nasıl düzenleyebilirim?

  • Yüksek trafikli bir web sitesi için önerilen değer nedir?


Güncelleme:

IIS'de bir şeyi düzenlemem gerekir mi?

Güncelleme:

Etkin bağlantı sayısının 15 ile 31 arasında herhangi bir yerde olduğunu ve SQL sunucusunda yapılandırılan izin verilen maksimum bağlantı sayısının 3200'den fazla bağlantı olduğunu, 31'in çok olduğunu veya ASP.NET yapılandırmasında bir şey düzenlemem gerektiğini buldum ?


Doğru hatırlamıyorsam, Maksimum Havuz Boyutu varsayılanı 100'dür. Çoğu Web sitesi ağır yük altında 50'den fazla bağlantı kullanmaz; sorgularınızın ne kadar sürede tamamlanacağına bağlıdır. Bağlantı Dizesi'nde kısa süreli düzeltme: bağlantı dizelerinizde daha yüksek bir değer ayarlamaya çalışın: "Maks. Havuz Boyutu = ..."
splattne

ne kadar? örneğin 200 yapsın?
Amr Elgarhy

3
Soruna neyin sebep olduğunu gerçekten aramanız gerektiğini düşünüyorum. Sorgularınız (veya bazıları) çok uzun sürüyor mu?
09:39

gerçek nedeni bu olabilir, yürütmek için çok zaman alıyor bir sorgu, ben arayacağım, teşekkürler
Amr Elgarhy

1
Umarım sorunu bulabilirsin. Bir öneri: SQL Server kullanıyorsanız, "SQL Profiler" i deneyin ve uzun sorguları arayın: sql-server-performance.com/articles/per/…
splattne

Yanıtlar:


218

Çoğu durumda bağlantı havuzu oluşturma sorunları "bağlantı sızıntıları" ile ilgilidir. Uygulamanız muhtemelen veritabanı bağlantılarını doğru ve tutarlı bir şekilde kapatmıyor. Bağlantıları açık bıraktığınızda, .NET çöp toplayıcısı Finalize()yöntemlerini çağırarak bunları kapatana kadar engellenmiş kalırlar .

Bağlantıyı gerçekten kapattığınızdan emin olmak istiyorsunuz . Arasındaki kod Örneğin aşağıdaki kod, bir bağlantı sızıntısına neden olur .Openve Closebir istisna atar:

var connection = new SqlConnection(connectionString);
connection.Open();
// some code
connection.Close();                

Doğru yol şu olurdu:

var connection = new SqlConnection(ConnectionString);
try
{
     connection.Open();
     someCall (connection);
}
finally
{
     connection.Close();                
}

veya

using (SqlConnection connection = new SqlConnection(connectionString))
{
     connection.Open();
     someCall(connection);
}

İşleviniz bir sınıf yönteminden bağlantı döndürdüğünde, yerel olarak önbelleğe aldığınızdan ve Closeyöntemini çağırdığınızdan emin olun . Bu kodu kullanarak bir bağlantıya sızacaksınız, örneğin:

var command = new OleDbCommand(someUpdateQuery, getConnection());
result = command.ExecuteNonQuery();
connection().Close(); 

İlk çağrıdan geri dönen bağlantı getConnection()kapatılmıyor. Bağlantınızı kapatmak yerine, bu hat yeni bir hat oluşturur ve kapatmaya çalışır.

Eğer kullanırsanız SqlDataReaderveya OleDbDataReaderonları kapatın. Bağlantının kendisinin kapatılması hile yapıyor gibi görünse de, veri okuyucu nesnelerinizi kullandığınızda açıkça kapatmak için ekstra çaba sarf edin.


MSDN / SQL Magazine'den " Bağlantı Havuzu Neden Taşıyor? " Başlıklı bu makalede çok sayıda ayrıntı açıklanmakta ve bazı hata ayıklama stratejileri önerilmektedir:

  • Run sp_whoveya sp_who2. Bu sistem saklı yordamları, sysprocessessistem tablosundan tüm çalışma süreçlerinin durumunu ve bu bilgileri gösteren bilgileri döndürür . Genellikle, bağlantı başına bir sunucu işlem kimliği (SPID) görürsünüz. Bağlantınızı bağlantı dizesindeki Uygulama Adı bağımsız değişkenini kullanarak adlandırdıysanız, çalışan bağlantılarınızın bulunması kolay olacaktır.
  • TSQL_ReplayAçık bağlantıları izlemek için SQLProfiler şablonu ile SQL Server Profiler kullanın . Profiler'ı biliyorsanız, bu yöntem sp_who kullanarak yoklamaktan daha kolaydır.
  • Havuzları ve bağlantıları izlemek için Performans İzleyicisi'ni kullanın. Bu yöntemi bir anda tartışıyorum.
  • Koddaki performans sayaçlarını izleyin. Sayaçları ayıklamak için yordamlar kullanarak veya yeni .NET PerformanceCounter denetimlerini kullanarak bağlantı havuzunuzun sağlığını ve kurulan bağlantı sayısını izleyebilirsiniz.

4
Küçük bir düzeltme: GC hiçbir zaman bir nesnenin Dispose yöntemini çağırmaz, yalnızca sonlandırıcısını (varsa) çağırır. SqlConnection'ın bunu yapıp yapmadığından emin olmamakla birlikte, sonlandırıcı gerekirse Dispose için bir "geri dönüş" çağrısı yapabilir.
LukeH

1
Maksimum Havuz boyutunu 50 ayarlamamız gerektiğinde ve yalnızca birkaç kullanıcımız olduğunda performansta herhangi bir düşüş var mı?
mahesh sharma

37

.NET Framework v4.6.1 yüklendikten sonra, uzak bir veritabanına olan bağlantılarımız bu değişiklik nedeniyle zaman aşımına uğramaya başladı .

Düzeltmek için parametreyi TransparentNetworkIPResolutionbağlantı dizesine ekleyin ve false olarak ayarlayın :

Sunucu = myservername; Veritabanı = mydatabase; Trusted_Connection = True; TransparentNetworkIPResolution Yanlış =


Bu durumda sorun "Havuzdan bağlantı alınmadan önce geçen zaman aşımı süresi" dir. Bağlantı dizesi düzeltmeniz bunu çözdü mü yoksa ayrı bir el sıkışma sorunu muydu?
FBryant87

1
Hatırladığım kadarıyla, sorudakiyle aynı hata mesajı oldu. .NET Framework v4.6.1 sürümüne güncellendikten hemen sonra meydana geldi.
ajbeaven

Bu benim için de geçerliydi, Azure üzerinde çalıştırdığım bir Uygulama Hizmeti'nde, bir Azure SQL veritabanına bağlantı için benim için düzeltti. Dapper kullanıyordum ve bağlantıların doğru şekilde imha edildiğini, ancak yine de "havuzdan bir bağlantı almadan önce geçen zaman aşımı süresi" hata iletisini aldım. Ama artık yok, çok teşekkürler @ajbeaven
Steve Kennaird

13

Kullanımınız çok fazla artmadıkça, sadece bir iş birikimi olması olası görünmüyor. IMO, en olası seçenek, bir şeyin bağlantıları kullanması ve derhal serbest bırakmamasıdır. Eğer Are de emin kullandığınız sen usingher durumda? Veya (hangi mekanizma yoluyla) bağlantıları serbest bırakmak?


13

Bağlantıyı kapatmadan veya bir veri okuyucuyu kapatmadan önce kapatılmamış DataReader'ları ve yanıt. Yönlendirmelerini kontrol ettiniz mi? Bir yönlendirmeden önce onları kapatmazsanız bağlantılar açık kalır.


3
+1 - Veya DataReaders döndüren işlevler - Bağlantı, bunları oluşturduğunuz işlevin dışında asla kapanmayacaktır ...
splattne

1
Eğer fonksiyonunuz SqlDataReader döndürürse, bunu maksimum havuz boyutunu yükseltmekten daha iyi DataTable'a dönüştürmek daha iyidir
canlı aşk

10

Bu sorunla zaman zaman web sitemizde de karşılaşıyoruz. Bizim durumumuzdaki suçlu, istatistiklerimizin / dizinlerimizin güncelliğini yitirmesidir. Bu, daha önce hızlı çalışan bir sorgunun (sonunda) yavaşlamasına ve zaman aşımına uğramasına neden olur.

Sorgudan etkilenen tablolarda istatistikleri güncellemeyi ve / veya dizinleri yeniden oluşturmayı deneyin ve bunun işe yarayıp yaramadığını görün.


3
Bu bir sorgu zaman aşımına neden olabilir açıklamak düşünüyorum, ama bu bir bağlantı elde etmeye çalışırken neden bir zaman aşımı deneyimli açıklayacağını sanmıyorum.
DrGriff

1
Kötü bir dizinle sorguların daha uzun sürmesi ve aynı anda daha fazla bağlantı kullanılması olabilir.
LosManos

1
Bir db üzerinde sp_updatestats ile tüm istatistikleri güncelledikten sonra benim için çalıştı: EXEC sp_updatestats;
boateng

6

Bağlantı dizesini belirterek MinPoolSize=xyzve / veya belirterek minimum ve maksimum havuz boyutunu belirleyebilirsiniz MaxPoolSize=xyz. Ancak sorunun bu nedeni farklı olabilir.


3
Önerilen MaxPoolSize nedir?
Amr Elgarhy

2
Muhtemelen, en iyi yol olduğunu değil özel gereksinimleri vardır ve size iyi bir havuz boyutu bilmedikçe onu belirtmek için belirli durumda .
Mehrdad Afshari

1
Not: kontrol ettim ve db'ye aktif bağlantıların yaklaşık 22 canlı bir olduğunu öğrendim, bu çok mu?
Amr Elgarhy

Ben öyle düşünmüyorum. Varsayılan havuz boyutu sanırım 100 bağlantı. Ağ ve SQL sunucusundaki her bağlantının yüküne bağlıdır. Bunlar yoğun sorgular çalıştırıyorsa sorunlara neden olabilir. Ayrıca, yeni bir bağlantı başlatılırken ağ sorunları oluşabilir ve bu özel duruma neden olabilir.
Mehrdad Afshari

5

.NET uygulamalardan birinde 3. taraf veri katmanı kullanırken de bu sorunla karşılaştım. Sorun, katmanın bağlantıları düzgün şekilde kapatmamasıydı.

Katmanı attık ve kendimizi yarattık, bu da her zaman bağlantıları kapatıyor ve atıyor. O zamandan beri artık hatayı almıyoruz.


LLBL kullanıyoruz ve web sitesi 2 yıldan beri çalışıyor ve sadece son birkaç gün böyle davranmaya başladı.
Amr Elgarhy

5

Zaman aşımı problemini çözmek için de deneyebilirsiniz:

Web yapılandırmanıza httpRuntime eklemediyseniz, bunu <system.web>etikete ekleyin

<sytem.web>
     <httpRuntime maxRequestLength="20000" executionTimeout="999999"/>
</system.web>

ve

Bağlantı dizenizi şu şekilde değiştirin;

 <add name="connstring" connectionString="Data Source=DSourceName;Initial Catalog=DBName;Integrated Security=True;Max Pool Size=50000;Pooling=True;" providerName="System.Data.SqlClient" />

Son kullanımda

    try
    {...} 
    catch
    {...} 
    finaly
    {
     connection.close();
    }

3

Bu, esas olarak uygulamada kapalı olmayan bağlantıdan kaynaklanmaktadır. Bağlantı dizesinde "MinPoolSize" ve "MaxPoolSize" kullanın.


3

Benim durumumda, DataReader nesnesini kapatmıyordum.

        using (SqlCommand dbCmd = new SqlCommand("*StoredProcedureName*"))
        using (dbCmd.Connection = new SqlConnection(WebConfigurationAccess.ConnectionString))
            {
            dbCmd.CommandType = CommandType.StoredProcedure;

            //Add parametres
            dbCmd.Parameters.Add(new SqlParameter("@ID", SqlDbType.Int)).Value = ID;
.....
.....
            dbCmd.Connection.Open();
            var dr = dbCmd.ExecuteReader(); //created a Data reader here
            dr.Close();    //gotta close the data reader
            //dbCmd.Connection.Close(); //don't need this as 'using' statement should take care of this in its implicit dispose method.
            }

2

Basit bir (..) {..} kullanmanın mümkün olmadığı karmaşık eski kod üzerinde çalışıyorsanız - benim gibi - bu SO sorusuna gönderdiğim kod snippet'ini belirlemek için Bir bağlantı potansiyel olarak sızdığında bağlantı oluşturmanın çağrı yığını (ayarlanan bir zaman aşımından sonra kapatılmaz). Bu, sızıntıların nedenini tespit etmeyi oldukça kolaylaştırır.


2

Sql bağlantısını çok fazla başlatmayın. Bir veya iki bağlantı açın ve sonraki tüm sql işlemleri için kullanın.

DisposeBağlantılar yapılırken bile istisna atılmış gibi görünüyor .


2

Gönderilen çözümlere ek olarak ....

Her biri ortak bir GetRS'yi birden çok kez çağıran 1000 sayfalık eski kodla uğraşırken, sorunu düzeltmenin başka bir yolu:

Varolan bir ortak DLL'de CommandBehavior.CloseConnection seçeneğini ekledik :

    static public IDataReader GetRS(String Sql)
    {
        SqlConnection dbconn = new SqlConnection(DB.GetDBConn());
        dbconn.Open();
        SqlCommand cmd = new SqlCommand(Sql, dbconn);
        return cmd.ExecuteReader(CommandBehavior.CloseConnection);   
    }

Ardından her sayfada, veri okuyucuyu kapattığınız sürece bağlantı da otomatik olarak kapanır, böylece bağlantı sızıntıları önlenir.

    IDataReader rs = CommonDLL.GetRS("select * from table");
    while (rs.Read())
    {
        // do something
    }
    rs.Close();   // this also closes the connection

2

Ben sadece aynı sorunu vardı ve kaynağı bulmama neyin yardımcı olduğunu paylaşmak istedim: Uygulama adını bağlantı dizenize ekleyin ve sonra SQL Server'a açık bağlantı motitor

select st.text,
    es.*, 
    ec.*
from sys.dm_exec_sessions as es
    inner join sys.dm_exec_connections as ec on es.session_id = ec.session_id
    cross apply sys.dm_exec_sql_text(ec.most_recent_sql_handle) st
where es.program_name = '<your app name here>'

1

Bu sorun benim kod vardı. Ben hata aşağıda geldi bazı örnek kod yapıştıracaktır. Havuzdan bağlantı alınmadan önce geçen zaman aşımı süresi. Bu, tüm havuzlanmış bağlantılar kullanımda olduğu ve maksimum havuz boyutuna ulaşıldığı için olmuş olabilir.

 String query = "insert into STATION2(ID,CITY,STATE,LAT_N,LONG_W) values('" + a1 + "','" + b1 + "','" + c1 + "','" + d1 + "','" + f1 + "')";
    //,'" + d1 + "','" + f1 + "','" + g1 + "'

    SqlConnection con = new SqlConnection(mycon);
    con.Open();
    SqlCommand cmd = new SqlCommand();
    cmd.CommandText = query;
    cmd.Connection = con;
    cmd.ExecuteNonQuery();
    **con.Close();**

Bağlantıyı her seferinde kapatmak istiyorsunuz. Bundan önce bize bu nedenle yakın bağlantı hata vermedi. Yakın ifade ekledikten sonra ben bu hatayı geldi


0

Kodunuzda bağlantılar sızdırıldı. Bunları kapattığınızı onaylamak için kullanarak kullanmayı deneyebilirsiniz.

 Using (SqlConnection sqlconnection1 = new SqlConnection(“Server=.\\SQLEXPRESS ;Integrated security=sspi;connection timeout=5”)) {
                          sqlconnection1.Open();
                          SqlCommand sqlcommand1 = sqlconnection1.CreateCommand();
                          sqlcommand1.CommandText = raiserror (‘This is a fake exception’, 17,1)”;
                          sqlcommand1.ExecuteNonQuery();  //this throws a SqlException every time it is called.
                          sqlconnection1.Close(); //Still never gets called.
              } // Here sqlconnection1.Dispose is _guaranteed_

https://blogs.msdn.microsoft.com/angelsb/2004/08/25/connection-pooling-and-the-timeout-expired-exception-faq/


0

Bu sorunla daha önce karşılaştım. Güvenlik duvarıyla ilgili bir sorun haline geldi. Güvenlik duvarına yeni bir kural ekledim. 1433SQL sunucusunun sunucuya bağlanabilmesi için bağlantı noktasını açmak zorunda kaldım .


0

Bunu kullan:

finally
{
    connection.Close();
    connection.Dispose();
    SqlConnection.ClearPool();
}

12
Belki amacını kaçırıyorum SqlConnection.ClearPool, ama şu anki bağlantınızın tekrar bağlantı havuzuna bırakılmasını engelleyen doe? Bağlantı havuzu fikrinin daha hızlı bağlantılara izin vermek olduğunu düşündüm. Bağlantıyı havuzun her bitiminde mutlaka bırakmak, havuzdan yedek bir tane çekmek yerine HER ZAMAN yeni bir bağlantının kurulması gerektiği anlamına gelir. Lütfen bu tekniğin nasıl ve neden faydalı olduğunu açıklayınız.
Dib

0

Evet, yapılandırmayı değiştirmenin bir yolu var. Özel bir sunucu üzerindeyseniz ve yalnızca daha fazla SQL bağlantısına ihtiyacınız varsa, aşağıdaki yönergeleri izleyerek her iki bağlantı dizesindeki "maksimum havuz boyutu" girdilerini güncelleştirebilirsiniz:

  1. Uzak Masaüstü'nü kullanarak sunucunuza giriş yapın
  2. Bilgisayarım'ı açın (Windows - E) ve C: \ inetpub \ vhosts [domain] \ httpdocs
  3. Web.config dosyasına çift tıklayın. Dosya yapısı uzantıları gizleyecek şekilde ayarlanmışsa, bu yalnızca web olarak listelenebilir. Bu, Visual Basic veya benzeri bir düzenleyiciyi açar.
  4. Bağlantı Dizelerinizi bulun, bunlar aşağıdaki örneklere benzer:

    "add name =" SiteSqlServer "connectionString =" sunucu = (yerel); veritabanı = dbname; uid = dbuser; pwd = dbpassword; pooling = true; bağlantı ömrü = 120; maksimum havuz boyutu = 25; ""

5.Maksimum havuz boyutu = X değerini gerekli havuz boyutuna değiştirin.

  1. Web.config dosyanızı kaydedin ve kapatın.


0

Benim durumumda, yüzlerce Sql bağlantısı açmaya devam eden sonsuz döngü (veritabanından değer almaya çalışan bir get özelliğinden) vardı.

Sorunu yeniden oluşturmak için şunu deneyin:

while (true)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        someCall(connection);
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.