Bagaimana saya bisa memecahkan masalah kumpulan koneksi antara ASP.NET dan SQL Server?

211

Beberapa hari terakhir kami melihat pesan kesalahan ini terlalu banyak di situs web kami:

"Batas waktu habis. Periode batas waktu berlalu sebelum mendapatkan koneksi dari pool. Ini mungkin terjadi karena semua koneksi pooled digunakan dan ukuran max pool tercapai."

Kami belum mengubah apa pun dalam kode kami untuk sementara waktu. Saya merevisi kode untuk memeriksa koneksi terbuka yang tidak menutup, tetapi ternyata semuanya baik-baik saja.

  • Bagaimana saya bisa memecahkan masalah ini?

  • Apakah saya perlu mengedit kumpulan ini?

  • Bagaimana cara saya mengedit jumlah koneksi maksimal kumpulan ini?

  • Apa nilai yang disarankan untuk situs web traffic tinggi?


Memperbarui:

Apakah saya perlu mengedit sesuatu di IIS?

Memperbarui:

Saya menemukan bahwa jumlah koneksi aktif di mana saja dari 15 hingga 31, dan saya menemukan bahwa jumlah maksimum koneksi yang diizinkan yang dikonfigurasi dalam SQL server lebih dari 3200 koneksi, 31 terlalu banyak atau haruskah saya mengedit sesuatu dalam konfigurasi ASP.NET ?

Amr Elgarhy
sumber
Default Max Pool Size adalah 100 jika saya ingat dengan benar. Sebagian besar situs web tidak menggunakan lebih dari 50 koneksi di bawah beban berat - tergantung pada berapa lama permintaan Anda selesai. Jangka pendek memperbaiki di Connection String: mencoba untuk menetapkan nilai yang lebih tinggi dalam string koneksi Anda: "Max Renang Size = ..."
splattne
berapa banyak? buat 200 misalnya?
Amr Elgarhy
3
Saya pikir Anda harus benar-benar mencari apa yang menyebabkan masalah. Apakah pertanyaan Anda (atau beberapa dari mereka) berjalan sangat lama?
splattne
mungkin itulah alasan sebenarnya, permintaan yang membutuhkan banyak waktu untuk mengeksekusi, saya akan mencari di
dalamnya
1
Saya harap Anda dapat menemukan masalahnya. Saran: jika Anda menggunakan SQL Server, mencoba "SQL Profiler" dan mencari pertanyaan lama: sql-server-performance.com/articles/per/...
splattne

Jawaban:

218

Dalam kebanyakan kasus, masalah penyatuan koneksi terkait dengan "kebocoran koneksi." Aplikasi Anda mungkin tidak menutup koneksi basis datanya dengan benar dan konsisten. Ketika Anda membiarkan koneksi terbuka, mereka tetap diblokir sampai .NET sampah mengumpulkannya untuk Anda dengan memanggil Finalize()metode mereka .

Anda ingin memastikan bahwa Anda benar - benar menutup koneksi . Misalnya kode berikut akan menyebabkan kebocoran koneksi, jika kode antara .Opendan Closemelemparkan pengecualian:

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

Cara yang benar adalah ini:

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

atau

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

Ketika fungsi Anda mengembalikan koneksi dari metode kelas, pastikan Anda melakukan cache secara lokal dan memanggil Closemetode tersebut. Anda akan membocorkan koneksi menggunakan kode ini misalnya:

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

Sambungan kembali dari panggilan pertama ke getConnection()tidak ditutup. Alih-alih menutup koneksi Anda, baris ini membuat yang baru dan mencoba untuk menutupnya.

Jika Anda menggunakan SqlDataReaderatau OleDbDataReader, tutuplah. Meskipun menutup koneksi itu sendiri tampaknya melakukan trik, lakukan upaya ekstra untuk menutup objek pembaca data Anda secara eksplisit saat Anda menggunakannya.


Artikel ini " Mengapa Connection Pool Overflow? " Dari MSDN / SQL Magazine menjelaskan banyak detail dan menyarankan beberapa strategi debugging:

  • Jalankan sp_whoatau sp_who2. Prosedur yang disimpan sistem ini mengembalikan informasi dari sysprocessestabel sistem yang menunjukkan status dan informasi tentang semua proses kerja. Secara umum, Anda akan melihat satu ID proses server (SPID) per koneksi. Jika Anda menamai koneksi Anda dengan menggunakan argumen Nama Aplikasi dalam string koneksi, koneksi kerja Anda akan mudah ditemukan.
  • Gunakan SQL Server Profiler dengan TSQL_Replaytemplat SQLProfiler untuk melacak koneksi terbuka. Jika Anda terbiasa dengan Profiler, metode ini lebih mudah daripada polling dengan menggunakan sp_who.
  • Gunakan Monitor Kinerja untuk memantau kumpulan dan koneksi. Saya membahas metode ini sebentar lagi.
  • Monitor penghitung kinerja dalam kode. Anda dapat memantau kesehatan kumpulan koneksi Anda dan jumlah koneksi yang dibuat dengan menggunakan rutinitas untuk mengekstrak penghitung atau dengan menggunakan kontrol .NET PerformanceCounter baru.
percikan
sumber
4
Koreksi kecil: GC tidak pernah memanggil metode Buang objek, hanya finalizernya (jika ada). Finalizer kemudian dapat melakukan panggilan "mundur" untuk Buang, jika perlu, meskipun saya tidak yakin apakah SqlConnection melakukannya.
LukeH
1
Apakah ada semacam penurunan kinerja saat kami harus menetapkan ukuran Max Pool 50 dan kami hanya memiliki sedikit pengguna.
mahesh sharma
37

Setelah menginstal .NET Framework v4.6.1 koneksi kami ke basis data jauh segera memulai penghentian karena perubahan ini .

Untuk memperbaikinya cukup tambahkan parameter TransparentNetworkIPResolutiondalam string koneksi dan setel ke false :

Server = myServerName; Database = myDataBase; Trusted_Connection = True; TransparentNetworkIPResolution = Salah

ajbeaven
sumber
Dalam hal ini masalahnya adalah "Periode waktu habis berlalu sebelum mendapatkan koneksi dari kumpulan". Apakah string koneksi Anda memperbaiki ini, atau apakah itu masalah handshaking yang terpisah?
FBryant87
1
Dari apa yang saya ingat itu adalah pesan kesalahan yang sama persis seperti dalam pertanyaan. Itu terjadi segera setelah memperbarui ke .NET Framework v4.6.1.
ajbeaven
Ini juga berlaku bagi saya, memperbaikinya untuk saya di Layanan Aplikasi yang saya jalankan di Azure, koneksi ke database Azure SQL. Saya menggunakan Dapper dan membuang koneksi dengan benar, namun masih mendapat periode "habis waktu sebelum mendapatkan koneksi dari pool" pesan kesalahan. Tapi tidak lebih, jadi terima kasih @ajbeaven
Steve Kennaird
13

Kecuali jika penggunaan Anda meningkat banyak, tampaknya tidak mungkin hanya ada tumpukan pekerjaan. IMO, opsi yang paling mungkin adalah sesuatu menggunakan koneksi dan tidak segera melepaskannya. Apakah Anda yakin menggunakan usingsemua kasus? Atau (melalui mekanisme apa pun) melepaskan koneksi?

Marc Gravell
sumber
13

Apakah Anda memeriksa DataReaders yang tidak ditutup dan response.redirects sebelum menutup koneksi atau datareader. Koneksi tetap terbuka saat Anda tidak menutupnya sebelum dialihkan.

Ivo
sumber
3
+1 - Atau fungsi yang mengembalikan DataReaders - Sambungan tidak akan pernah menutup di luar fungsi yang Anda buat ...
splattne
1
Jika fungsi Anda mengembalikan SqlDataReader, Anda lebih baik mengonversinya ke DataTable daripada menaikkan ukuran kumpulan maks
live-love
10

Kami juga menghadapi masalah ini dari waktu ke waktu di situs web kami. Pelakunya dalam kasus kami, adalah statistik / indeks kami semakin ketinggalan zaman. Ini menyebabkan permintaan yang sebelumnya berjalan cepat (akhirnya) menjadi lambat dan waktu habis.

Coba perbarui statistik dan / atau bangun kembali indeks pada tabel yang dipengaruhi oleh kueri dan lihat apakah itu membantu.

Alex Czarto
sumber
3
Saya pikir ini akan menjelaskan mengapa permintaan bisa time out, tapi saya tidak berpikir ini akan menjelaskan mengapa time out dialami saat mencoba untuk mendapatkan koneksi.
DrGriff
1
Bisa jadi dengan indeks yang buruk kueri membutuhkan waktu lebih lama dan lebih banyak koneksi digunakan pada saat yang sama.
LosManos
1
Bekerja untuk saya setelah memperbarui semua statistik dengan sp_updatestats pada db: EXEC sp_updatestats;
boateng
6

Anda dapat menentukan ukuran kumpulan minimum dan maksimum dengan menentukan MinPoolSize=xyzdan / atau MaxPoolSize=xyzdalam string koneksi. Namun penyebab masalah ini bisa saja berbeda.

Mehrdad Afshari
sumber
3
Apa MaxPoolSize yang disarankan?
Amr Elgarhy
2
Mungkin, cara terbaik untuk pergi adalah tidak menentukannya kecuali jika Anda memiliki persyaratan khusus dan Anda tahu ukuran kolam yang baik untuk kasus spesifik Anda .
Mehrdad Afshari
1
Catatan: saya memeriksa dan saya menemukan bahwa koneksi aktif ke db saya sekitar 22 live satu, apakah itu terlalu banyak?
Amr Elgarhy
Saya kira tidak. Ukuran kolam standar adalah 100 koneksi saya pikir. Itu tergantung pada beban setiap koneksi di jaringan dan SQL server. Jika itu menjalankan kueri berat, itu dapat menyebabkan masalah. Juga, masalah jaringan mungkin terjadi ketika memulai koneksi baru dan dapat menyebabkan pengecualian itu.
Mehrdad Afshari
5

Saya juga mengalami masalah ini, ketika menggunakan beberapa lapisan data pihak ke-3 di salah satu aplikasi .NET saya. Masalahnya adalah bahwa layer tidak menutup koneksi dengan benar.

Kami membuang lapisan dan membuat sendiri, yang selalu menutup dan membuang koneksi. Sejak itu kami tidak mendapatkan kesalahan lagi.

Wim Haanstra
sumber
Kami menggunakan LLBL dan situs web ini berjalan dari 2 tahun dan hanya beberapa hari terakhir mulai bertindak seperti ini.
Amr Elgarhy
5

Anda dapat mencobanya juga, untuk memecahkan masalah batas waktu:

Jika Anda tidak menambahkan httpRuntime ke konfigurasi web Anda, tambahkan itu di <system.web>tag

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

dan

Ubah string koneksi Anda seperti ini;

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

Terakhir digunakan

    try
    {...} 
    catch
    {...} 
    finaly
    {
     connection.close();
    }
Ka_Ya
sumber
3

Hal ini terutama disebabkan oleh koneksi yang belum ditutup dalam aplikasi. Gunakan "MinPoolSize" dan "MaxPoolSize" di string koneksi.

subramanian.m
sumber
3

Dalam kasus saya, saya tidak menutup objek DataReader.

        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.
            }
DevelopZen
sumber
2

Jika Anda bekerja pada kode lawas yang kompleks di mana penggunaan sederhana (..) {..} tidak mungkin - seperti saya sebelumnya - Anda mungkin ingin memeriksa cuplikan kode yang saya poskan dalam pertanyaan SO ini untuk cara menentukan panggilan tumpukan penciptaan koneksi ketika koneksi berpotensi bocor (tidak ditutup setelah batas waktu yang ditentukan). Ini membuatnya cukup mudah untuk menemukan penyebab kebocoran.

LOAS
sumber
2

Jangan instantiate koneksi sql terlalu banyak. Buka satu atau dua koneksi dan gunakan untuk semua operasi sql berikutnya.

Tampaknya bahkan ketika Disposekoneksi terkecuali dilemparkan.


sumber
2

Selain solusi yang diposting ....

Dalam menangani 1000 halaman kode warisan, masing-masing memanggil GetRS yang umum beberapa kali, berikut ini cara lain untuk memperbaiki masalah ini:

Dalam DLL umum yang ada, kami menambahkan opsi CommandBehavior.CloseConnection :

    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);   
    }

Kemudian di setiap halaman, selama Anda menutup pembaca data, koneksi juga secara otomatis ditutup sehingga kebocoran koneksi dicegah.

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

Saya baru saja mengalami masalah yang sama dan ingin berbagi apa yang membantu saya menemukan sumber: Tambahkan nama Aplikasi ke string koneksi Anda dan kemudian motitor koneksi terbuka ke SQL Server

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>'
Manfred Wippel
sumber
1

Masalah ini saya miliki dalam kode saya. Saya akan menempelkan beberapa contoh kode yang saya miliki di bawah kesalahan. Periode waktu habis berlalu sebelum mendapatkan koneksi dari kolam. Ini mungkin terjadi karena semua koneksi gabungan digunakan dan ukuran max pool tercapai.

 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();**

Anda ingin menutup koneksi setiap saat. Sebelum itu saya tidak menghubungkan kami karena ini saya mendapat kesalahan. Setelah menambahkan pernyataan tutup saya telah mengatasi kesalahan ini

Aravindhan R
sumber
0

Anda telah membocorkan koneksi pada kode Anda. Anda dapat mencoba menggunakan menggunakan untuk menyatakan bahwa Anda menutupnya.

 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/

EduLopez
sumber
0

Masalah ini pernah saya temui sebelumnya. Itu akhirnya menjadi masalah dengan firewall. Saya baru saja menambahkan aturan ke firewall. Saya harus membuka port 1433agar server SQL dapat terhubung ke server.

Feisal Aswad
sumber
0

Gunakan ini:

finally
{
    connection.Close();
    connection.Dispose();
    SqlConnection.ClearPool();
}
Jeno M
sumber
12
Mungkin saya kehilangan intinya SqlConnection.ClearPool, tetapi apakah itu hanya mencegah koneksi Anda saat ini dilepaskan kembali ke kolam koneksi? Saya pikir ide koneksi pool adalah untuk memungkinkan koneksi yang lebih cepat. Tentunya melepaskan koneksi dari kolam setiap kali selesai dengan berarti koneksi BARU perlu dibuat SETIAP SAAT diperlukan, alih-alih menarik yang cadangan dari kolam? Tolong jelaskan bagaimana dan mengapa teknik ini berguna.
Dib
0

Ya, Ada cara untuk mengubah konfigurasi. Jika Anda menggunakan dedicated server dan hanya membutuhkan lebih banyak koneksi SQL, Anda dapat memperbarui entri "max pool size" di kedua string koneksi dengan mengikuti instruksi ini:

  1. Masuk ke server Anda menggunakan Remote Desktop
  2. Buka Komputer Saya (Windows - E) dan buka C: \ inetpub \ vhosts [domain] \ httpdocs
  3. Klik dua kali pada file web.config. Ini mungkin hanya terdaftar sebagai web jika struktur file diatur untuk menyembunyikan ekstensi. Ini akan membuka Visual Basic atau editor serupa.
  4. Temukan String Koneksi Anda, ini akan terlihat mirip dengan contoh di bawah ini:

    "add name =" SiteSqlServer "connectionString =" server = (lokal); database = dbname; uid = dbuser; pwd = dbpassword; pooling = true; seumur hidup koneksi = 120; ukuran kumpulan pool = 25; ""

5. Ubah ukuran kolam maks = nilai X ke ukuran kolam yang diperlukan.

  1. Simpan dan tutup file web.config Anda.
Srusti Thakkar
sumber
0

Dalam kasus saya, saya memiliki infinite loop (dari get Property yang mencoba mendapatkan nilai dari database) yang terus membuka ratusan koneksi Sql.

Untuk mereproduksi masalah coba ini:

while (true)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        someCall(connection);
    }
}
stomy
sumber