ASP.NET 풀링 에러에 대해 질문드립니다.

답변됨 ASP.NET 풀링 에러에 대해 질문드립니다.

  • 2012년 5월 15일 화요일 오전 12:05
     
     

    ASP.NET 사이트를 운영중입니다.

    제한 시간이 만료되었습니다. 풀에서 연결을 만들기 전에 제한 시간이 경과되었습니다. 풀링된 연결이 사용 중이었거나 최대 풀 크기에 도달했기 때문일 수 있습니다.

    상기 에러로 대응중인데요.

    DB Connection 풀링 관련 옵션에서 MaxPoolSize, MinPoolSize 의 수를 가감해도 해당 에러가 비정기적으로 나옵니다.

    기타 옵션도 대부분 테스트해 보았구요.

    마지막으로 Pooling=false 로 풀링 사용을 안하는 것으로 변경했더니 상기 에러가 안 나오네요.

    사이트에 사용자가 급증한 상태도 아니고, 갑자기 에러 상항이 발생했었습니다.

    이 상황에 대해 설명을 해 주실만한 분 계시면 도움 부탁드립니다.

    향후 어떻게 해야 할지도 조언 부탁드립니다.


    오류 종류가 세가지 정도 됩니다.

    오류 메시지에는 SQL Server 2005라고 되어 있지만 실제는 SQL Server 2000입니다.

    AbstracBeanDAO는 DB Helper 정도로 봐 주시면 될 거 같습니다.

    조언 부탁드립니다


    17:07:43 제한 시간이 만료되었습니다. 풀에서 연결을 만들기 전에 제한 시간이 경과되었습니다. 풀링된 연결이 사용 중이었거나 최대 풀 크기에 도달했기 때문일 수 있습니다.
    Source = System.Data
    StaceTrace =    위치: System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
       위치: System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
       위치: System.Data.SqlClient.SqlConnection.Open()
       위치: AbstracBeanDAO.FatechQuery(String Query)

    17:10:16 서버에 연결하는 동안 오류가 발생했습니다. SQL Server 2005에 연결하는 경우 SQL Server 기본 설정에서는 원격 연결을 허용하지 않기 때문에 발생한 오류일 수 있습니다. (provider: 명명된 파이프 공급자, error: 40 - SQL Server에 대한 연결을 열 수 없습니다.)
    Source = .Net SqlClient Data Provider
    StaceTrace =    위치: System.Data.ProviderBase.DbConnectionPool.GetConnection(DbConnection owningObject)
       위치: System.Data.ProviderBase.DbConnectionFactory.GetConnection(DbConnection owningConnection)
       위치: System.Data.ProviderBase.DbConnectionClosed.OpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory)
       위치: System.Data.SqlClient.SqlConnection.Open()
       위치: AbstracBeanDAO.FatechQuery(String Query)

    17:49:22 제한 시간이 만료되었습니다. 작업을 완료하기 전에 제한 시간이 경과되었거나 서버가 응답하지 않았습니다.
    Source = .Net SqlClient Data Provider
    StaceTrace =    위치: System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
       위치: System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
       위치: System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
       위치: System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
       위치: System.Data.SqlClient.SqlDataReader.ConsumeMetaData()
       위치: System.Data.SqlClient.SqlDataReader.get_MetaData()
       위치: System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
       위치: System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
       위치: System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
       위치: System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
       위치: System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
       위치: System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
       위치: AbstracBeanDAO.FatechProc2(String ProcName, IDataParameter[] parameters)


        public SqlDataReader FatechQuery(string Query)
        {
            SqlDataReader fatechReader = null;

            try
            {
                // 수정
                this.mDbConn = new SqlConnection(GetDSN);
                this.mCmd = new SqlCommand();
                this.mCmd.Connection = this.mDbConn;
                this.mCmd.CommandType = CommandType.Text;
                this.mCmd.CommandTimeout = 600;
                this.mCmd.CommandText = Query;

                if (this.mCmd.Connection.State != ConnectionState.Open)
                    this.mCmd.Connection.Open();
                // 수정

                fatechReader = mCmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (Exception e)
            {
                DbErrorMsg(e.Source, e.Message, e.StackTrace, Query);
            }
            finally
            {
                if (mCmd != null)
                    mCmd.Dispose();
            }

            return fatechReader;

        }

        public SqlDataReader FatechProc2(string ProcName, IDataParameter[] parameters)
        {
            SqlDataReader mReader1 = null;
            try
            {
                this.mDbConn = new SqlConnection(GetDSN2);
                this.mCmd = new SqlCommand();
                this.mCmd.Connection = this.mDbConn;
                this.mCmd.CommandTimeout = 600;
                this.mCmd.CommandText = ProcName;

                if (mCmd.Connection.State != ConnectionState.Open)
                    mCmd.Connection.Open();

                this.mCmd = BuildProcCommand2(ProcName, parameters, this.mDbConn);


                this.mCmd.CommandType = CommandType.StoredProcedure;
                mReader1 = mCmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (Exception e)
            {
                DbErrorMsg(e.Source, e.Message, e.StackTrace, "Procedure FatechProc Error");
            }

            return mReader1;
        }

모든 응답

  • 2012년 5월 15일 화요일 오전 1:22
     
     답변됨

    Pooling = false 를 했는데 오류가 없어졌다면, 대개의 경우 연결 개체를 정확히 닫지 않아서 발생하는 문제일 것입니다.

    이에 대해서는 성능 카운터를 이용하면 진단이 될 텐데요.

    Using ADO.NET Performance Counters
    ; http://msdn.microsoft.com/en-us/library/ms254503(v=vs.80).aspx

    위의 글에 보시면 NumberOfActiveConnections 수를 해당 ASP.NET 에 대해서 모니터링 해보시면 됩니다. 예상대로라면 이 수치가 SQL 을 연결이 샐 때 마다 감소되지 않고 지속적으로 상승할 것입니다.

    이런 경우, 외부 환경 설정으로 문제를 해결하기 보다는 내부적인 코드 리뷰를 꼼꼼하게 체크하는 것이 해결에 도움이 될 것입니다.

    • 답변으로 표시됨 Jina LeeModerator 2012년 6월 4일 월요일 오후 1:01
    •  
  • 2012년 5월 16일 수요일 오전 5:59
     
     답변됨

    위에서 말씀하신대로 ActiveConnection을 추적해보시면 될 듯 하고요..
    Pool 개수를 조절하더라도 결국은 Connection이 제대로 Close되지 않아 Pool이 모두 소진되어서 발생하는 문제입니다.

    위의 코드들을 보면 SqlDataReader를 사용하고 계신데요,
    Fetch* 메서드 내부 상에서도 mCmd.Connection.Open() 이후에 exception이 발생했을 때 Connection을 Close하는 코드가 보이지 않습니다.
    그나마 첫번째 메서드에서는 Command 개체는 Dispose를 해주시고 있지만, 그걸 한다고 해서 Connection이 Close되지는 않습니다.
    정상적으로 SqlDataReader를 반환 시에도 Caller 쪽에서 SqlDataReader를 Close(또는 Dispose)해줘야 CommandBehavior.CloseConnection이 제대로 작동합니다.

    이러한 문제를 좀 더 깔끔하게 처리하기 위해 try~catch 형태보다는 using ( ... ) 구문을 사용하여 Auto Dispose를 해주는 것이고요.
    참고로 SqlDataReader의 경우, 데이터에 접근하기 위해서는 Connection이 Open된 상태로 유지되어야 합니다.
    그 때문에 Caller 쪽에서 Close를 해줄 의무가 있고요. 이를 피하시려면 DataSet이나 Entity 형태로 데이터를 받는 Disconnected 모델 형태로 변경하셔야 합니다.

    • 답변으로 표시됨 Jina LeeModerator 2012년 6월 4일 월요일 오후 1:01
    •