ASP.NET과 SQL Server 간의 연결 풀 문제를 어떻게 해결할 수 있습니까?


211

지난 며칠 동안 웹 사이트에이 오류 메시지가 너무 많이 나타납니다.

"시간 초과가 만료되었습니다. 풀에서 연결을 가져 오기 전에 시간이 초과되었습니다. 풀링 된 모든 연결이 사용 중이고 최대 풀 크기에 도달했기 때문에 발생했을 수 있습니다."

우리는 한동안 코드에서 아무것도 변경하지 않았습니다. 닫히지 않은 열린 연결을 확인하기 위해 코드를 수정했지만 모든 것이 정상임을 알았습니다.

  • 이 문제를 어떻게 해결할 수 있습니까?

  • 이 풀을 편집해야합니까?

  • 이 풀의 최대 연결 수를 어떻게 편집합니까?

  • 트래픽이 많은 웹 사이트에 권장되는 값은 무엇입니까?


최신 정보:

IIS에서 무언가를 편집해야합니까?

최신 정보:

활성 연결 수는 15 ~ 31 사이이며 SQL Server에 구성된 최대 허용 연결 수가 3200 개를 초과하거나 31이 너무 많거나 ASP.NET 구성에서 무언가를 편집해야한다는 것을 알았습니다. ?


올바르게 기억하면 최대 풀 크기 기본값은 100입니다. 대부분의 웹 사이트는로드가 많은 경우 50 개 이상의 연결을 사용하지 않습니다. 쿼리를 완료하는 데 걸리는 시간에 따라 다릅니다. 연결 문자열의 단기 수정 : 연결 문자열에서 더 높은 값을 설정하십시오. "Max Pool Size = ..."
splattne

얼마예요? 예를 들어 200으로 만드시겠습니까?
Amr Elgarhy

3
문제의 원인을 실제로 검색해야한다고 생각합니다. 쿼리 (또는 일부)가 너무 오래 실행되고 있습니까?
splattne

그 이유는 실제 이유, 실행하는 데 많은 시간이 걸리는 검색어입니다. 감사합니다.
Amr Elgarhy

1
문제를 찾을 수 있기를 바랍니다. 제안 : SQL Server를 사용하는 경우 "SQL 프로파일 러"를 시도하고 긴 쿼리를 찾으십시오. sql-server-performance.com/articles/per/…
splattne

답변:


218

대부분의 경우 연결 풀링 문제는 "연결 누출"과 관련이 있습니다. 응용 프로그램이 데이터베이스 연결을 정확하고 일관되게 닫지 않을 수 있습니다. 연결을 열린 상태로두면 .NET 가비지 수집기가 해당 Finalize()메서드 를 호출하여 연결을 닫을 때까지 차단 된 상태로 유지됩니다 .

연결을 실제로 닫고 있는지 확인하려고 합니다 . 코드의 경우, 예를 들어 다음의 코드는, 연결 누수가 발생할 .Open그리고 Close예외를 발생 :

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

올바른 방법은 다음과 같습니다.

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

또는

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

함수 가 클래스 메서드에서 연결을 반환 하면 로컬로 캐시하고 Close메서드를 호출해야 합니다. 예를 들어이 코드를 사용하여 연결이 누출됩니다.

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

첫 번째 호출에서 반환 된 연결 getConnection() 이 닫히지 않았습니다. 연결을 닫는 대신이 줄은 새로운 연결을 만들어 닫으려고합니다.

또는를 사용 SqlDataReader하는 OleDbDataReader경우 닫습니다. 연결 자체를 닫는 것이 속임수 인 것처럼 보이지만 데이터 리더 개체를 사용할 때 명시 적으로 닫으려면 추가 노력을 기울이십시오.


MSDN / SQL Magazine 의이 기사 " 연결 풀 오버플로는 왜 발생합니까? "에서 많은 세부 사항을 설명하고 몇 가지 디버깅 전략을 제안합니다.

  • sp_who또는을 실행하십시오 sp_who2. 이 시스템 저장 프로시 저는sysprocesses 시스템 테이블 모든 작업 프로세스의 상태와 정보를 표시하는 합니다. 일반적으로 연결 당 하나의 서버 프로세스 ID (SPID)가 표시됩니다. 연결 문자열에서 응용 프로그램 이름 인수를 사용하여 연결의 이름을 지정한 경우 작동중인 연결을 쉽게 찾을 수 있습니다.
  • SQLProfiler TSQL_Replay템플릿 과 함께 SQL Server 프로파일 러를 사용하여 열린 연결을 추적하십시오. Profiler에 익숙한 경우 sp_who를 사용하여 폴링하는 것보다이 방법이 더 쉽습니다.
  • 풀과 연결을 모니터링하려면 성능 모니터를 사용하십시오. 이 방법에 대해서는 잠시 후에 설명하겠습니다.
  • 코드에서 성능 카운터를 모니터링합니다. 루틴을 사용하여 카운터를 추출하거나 새로운 .NET PerformanceCounter 컨트롤을 사용하여 연결 풀의 상태와 설정된 연결 수를 모니터링 할 수 있습니다.

4
작은 수정 : GC는 객체의 Dispose 메소드를 호출하지 않으며 종료 자 (있는 경우) 만 호출합니다. 그런 다음 SqlConnection의 사용 여부는 확실하지 않지만 필요에 따라 종료자는 Dispose에 대한 "대체"호출을 수행 할 수 있습니다.
LukeH

1
최대 풀 크기를 50으로 설정해야하고 사용자가 거의없는 경우 성능 저하가 있습니까?
mahesh sharma

37

.NET Framework v4.6.1을 설치하면 이 변경으로 인해 원격 데이터베이스에 대한 연결이 즉시 시간 초과 되기 시작했습니다 .

간단히 TransparentNetworkIPResolution연결 문자열에 매개 변수를 추가하고 이를 false로 설정하십시오 .

서버 = myServerName; 데이터베이스 = myDataBase; Trusted_Connection = 참; TransparentNetworkIPResolution = 거짓


이 경우 문제는 "풀에서 연결을 얻기 전에 시간 초과 기간이 경과했습니다"입니다. 연결 문자열이이 문제를 해결 했습니까? 아니면 별도의 핸드 셰이 킹 문제입니까?
FBryant87

1
내가 기억하는 것에서 그것은 질문에서와 정확히 같은 오류 메시지였습니다. .NET Framework v4.6.1로 업데이트 한 직후에 발생했습니다.
ajbeaven

이것은 나에게도 해당되며 Azure에서 실행중인 App Service에서 Azure SQL 데이터베이스에 연결하여 수정했습니다. Dapper를 사용하고 연결을 올바르게 삭제했지만 "풀에서 연결을 가져 오기 전에 시간 초과 기간이 경과했습니다"오류 메시지가 계속 표시됩니다. 그러나 더 이상, 감사 @ajbeaven 있도록
스티브 Kennaird

13

사용량이 많지 않으면 백 로그 작업 만있을 것 같지 않습니다. IMO에서 가장 가능성이 높은 옵션은 무언가가 연결을 사용하고 있으며 즉시 해제하지 않는 것입니다. 당신이 있습니까 장해야 사용하면 using모든 경우에? 아니면 (어떤 메커니즘을 통해) 연결을 해제합니까?


13

연결 또는 데이터 리더를 닫기 전에 닫히지 않은 response.redirects 및 DataReader를 확인 했습니까? 리디렉션 전에 연결을 닫지 않으면 연결이 열려 있습니다.


3
+1-또는 DataReaders를 리턴하는 함수-연결은 사용자가 작성한 함수 외부에서 절대 닫히지 않습니다.
splattne

1
함수의 반환은 최대 풀 크기를 올리는 것보다 DataTable을로 변환 떨어져 더 나은 SqlDataReader의 경우
라이브 사랑을

10

웹 사이트에서도 때때로이 문제가 발생합니다. 우리의 경우 범인은 통계 / 색인이 오래되었습니다. 이로 인해 이전에 빠르게 실행중인 쿼리가 (최종적으로) 느리고 시간 초과됩니다.

쿼리의 영향을받는 테이블에서 통계를 업데이트하거나 인덱스를 다시 작성하여 도움이되는지 확인하십시오.


3
이것이 쿼리 시간 초과 이유를 설명한다고 생각하지만 연결을 얻는 동안 시간 초과가 발생하는 이유를 설명하지는 않습니다.
DrGriff

1
인덱스가 잘못되면 쿼리에 시간이 오래 걸리고 더 많은 연결이 동시에 사용될 수 있습니다.
LosManos

1
db에서 sp_updatestats로 모든 통계를 업데이트 한 후 저를 위해 일했습니다. EXEC sp_updatestats;
boateng

6

연결 문자열에서 MinPoolSize=xyz및 / 또는 지정하여 최소 및 최대 풀 크기를 지정할 수 있습니다 MaxPoolSize=xyz. 그러나이 문제의 원인은 다른 것일 수 있습니다.


3
권장되는 MaxPoolSize는 무엇입니까?
Amr Elgarhy

2
아마 갈 수있는 가장 좋은 방법은 없습니다 당신은 특별한 요구 사항이 당신이 당신을 위해 좋은 풀 크기를 알고 자하지 않는 한을 지정하는 특정 케이스 .
Mehrdad Afshari

1
참고 : 확인한 결과 내 DB에 대한 활성 연결이 약 22 개의 라이브 연결이라는 것을 알았습니다.
Amr Elgarhy

나는 그렇게 생각하지 않습니다. 기본 풀 크기는 100 연결이라고 생각합니다. 네트워크 및 SQL Server의 각 연결로드에 따라 다릅니다. 무거운 쿼리를 실행중인 경우 문제가 발생할 수 있습니다. 또한 새 연결을 시작할 때 네트워크 문제가 발생할 수 있으며 해당 예외가 발생할 수 있습니다.
Mehrdad Afshari

5

내 .NET 응용 프로그램 중 하나에서 일부 타사 데이터 계층을 사용할 때도이 문제가 발생했습니다. 문제는 레이어가 연결을 제대로 닫지 않았다는 것입니다.

우리는 레이어를 버리고 직접 연결을 닫고 처리하는 레이어를 만들었습니다. 그 이후로 더 이상 오류가 발생하지 않습니다.


우리는 LLBL을 사용하고 있으며 웹 사이트는 2 년 동안 운영되고 있으며 지난 며칠 동안 이와 같이 작동하기 시작했습니다.
Amr Elgarhy

5

시간 초과 문제를 해결하기 위해 시도해 볼 수도 있습니다.

웹 구성에 httpRuntime을 추가하지 않은 경우 <system.web>태그에 추가하십시오

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

다음과 같이 연결 문자열을 수정하십시오.

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

마지막으로 사용

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

3

주로 응용 프로그램에서 연결이 닫히지 않았기 때문입니다. 연결 문자열에 "MinPoolSize"및 "MaxPoolSize"를 사용하십시오.


3

필자의 경우 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.
            }

2

간단한 using (..) {..}을 사용할 수없는 복잡한 레거시 코드를 작업하고 있다면이 SO 질문 에 게시 한 코드 스 니펫 을 확인하여 연결이 누수되었을 때 연결이 생성 된 호출 스택 (설정된 시간 초과 후 닫히지 않음). 이를 통해 누출 원인을 쉽게 파악할 수 있습니다.


2

SQL 연결을 너무 많이 인스턴스화하지 마십시오. 하나 또는 두 개의 연결을 열고 다음의 모든 SQL 조작에 사용하십시오.

Dispose연결 을 할 때도 예외가 발생하는 것으로 보입니다 .


2

게시 된 솔루션 외에도 ....

각각 공통 GetRS를 여러 번 호출하는 1000 페이지의 레거시 코드를 처리 할 때 문제를 해결하는 또 다른 방법이 있습니다.

기존의 일반적인 DLL에서 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);   
    }

그런 다음 각 페이지에서 데이터 리더를 닫는 한 연결도 자동으로 닫히므로 연결 누수가 방지됩니다.

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

2

방금 같은 문제가 있었고 소스를 찾는 데 도움이되는 것을 공유하고 싶었습니다. 응용 프로그램 이름을 연결 문자열에 추가 한 다음 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>'

1

이 문제는 내 코드에있었습니다. 위의 예제 코드를 붙여 넣으면 오류가 발생합니다. 풀에서 연결을 얻기 전에 시간 종료 기간이 경과했습니다. 풀링 된 모든 연결이 사용 중이고 최대 풀 크기에 도달했기 때문에 발생했을 수 있습니다.

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

매번 연결을 닫으려고합니다. 그 전에 나는 이것으로 인해 우리에게 가까운 연결을하지 않았다. 나는 오류가있다. 닫기 문을 추가 한 후이 오류가 발생했습니다.


0

코드에서 연결이 누출되었습니다. 닫기를 인증하는 데 사용을 시도 할 수 있습니다.

 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

이 문제는 이전에 발생했습니다. 결국 방화벽 문제가되었습니다. 방금 방화벽에 규칙을 추가했습니다. 1433SQL 서버가 서버에 연결할 수 있도록 포트를 열어야했습니다 .


0

이것을 사용하십시오 :

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

12
어쩌면 나는 요점을 잃어 버렸지 SqlConnection.ClearPool만 현재 연결이 연결 풀로 다시 해제되는 것을 막을 수 있습니까? 연결 풀의 아이디어는 더 빠른 연결을 허용하는 것이라고 생각했습니다. 연결이 완료 될 때마다 풀에서 연결을 해제한다는 것은 풀에서 여분의 연결을 가져 오는 대신 필요할 때마다 새로 연결을 작성해야한다는 것을 의미합니까? 이 기술이 유용한 방법과 이유를 설명하십시오.
Dib

0

예, 구성을 변경하는 방법이 있습니다. 전용 서버에 있고 더 많은 SQL 연결이 필요한 경우 다음 지침에 따라 두 연결 문자열에서 "최대 풀 크기"항목을 업데이트 할 수 있습니다.

  1. 원격 데스크톱을 사용하여 서버에 로그인
  2. 내 컴퓨터 (Windows-E)를 열고 C : \ inetpub \ vhosts [도메인] \ httpdocs로 이동하십시오.
  3. web.config 파일을 두 번 클릭하십시오. 파일 구조가 확장자를 숨기도록 설정된 경우 웹으로 표시 될 수 있습니다. Visual Basic 또는 유사한 편집기가 열립니다.
  4. 연결 문자열을 찾으십시오. 아래 예제와 비슷합니다.

    "add name ="SiteSqlServer "connectionString ="server = (local); database = dbname; uid = dbuser; pwd = dbpassword; pooling = true; connection lifetime = 120; max pool size = 25; "

5. max pool size = X 값을 필요한 풀 크기로 변경하십시오.

  1. web.config 파일을 저장하고 닫습니다.


0

필자의 경우 수백 개의 Sql 연결을 계속 유지하는 무한 루프 (데이터베이스에서 값을 얻으려고하는 get 속성에서)가있었습니다.

문제를 재현하려면 다음을 시도하십시오.

while (true)
{
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        connection.Open();
        someCall(connection);
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.