programing

.용 오라클 데이터 공급자.NET: 연결 요청 시간이 초과되었습니다.

css3 2023. 7. 24. 22:42

.용 오라클 데이터 공급자.NET: 연결 요청 시간이 초과되었습니다.

Oracle 데이터베이스에 액세스하는 윈도우즈 2008 SP2/IIS 7에서 호스팅되는 C# WCF 웹 서비스가 있습니다.일반적으로 데이터 액세스는 정상적으로 작동하지만 로드 테스트 중에 다음과 같이 시간이 초과되고 로그 및 예외가 기록됩니다.

Error occurred when processing XXXXXXXX Web Service
Oracle.DataAccess.Client.OracleException Connection request timed out at Oracle.DataAccess.Client.OracleException.HandleErrorHelper(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, OpoSqlValCtx* pOpoSqlValCtx, Object src, String procedure, Boolean bCheck)
   at Oracle.DataAccess.Client.OracleException.HandleError(Int32 errCode, OracleConnection conn, IntPtr opsErrCtx, Object src)
   at Oracle.DataAccess.Client.OracleConnection.Open()
   at MyWorkspace.WorkForceDataAccess.CheckStaffIdInRSW()
   at MyWorkspace.MyClass.MyFunction(MyDataType MyData)

데이터베이스를 쿼리하기 위해 다음과 같은 방법을 사용합니다.

OracleConnection orConn = new OracleConnection();
orConn.ConnectionString = "user id=xxx; password=xxx; Connection Timeout=600; Max Pool Size=150; data source= (DESCRIPTION =(ADDRESS = (PROTOCOL = TCP)(HOST = MYHOST.MYDOMAIN.com)(PORT = 1771)) (CONNECT_DATA =(SERVER = DEDICATED)(SERVICE_NAME = MYSERVICE.MYDOMAIN.com)))";
orConn.Open();

using (var cmd = new OracleCommand("MY_UTIL.check_StaffIdInRSW", orConn) { CommandType = CommandType.StoredProcedure })
{
    cmd.Parameters.Add("P_Staff_Id", OracleDbType.Int32);
    cmd.Parameters["P_Staff_Id"].Direction = ParameterDirection.Input;
    cmd.Parameters["P_Staff_Id"].Value = Convert.ToInt32(MyDataObject.StaffId);

    cmd.Parameters.Add("P_retvalue", OracleDbType.Int32);
    cmd.Parameters["P_retvalue"].Direction = ParameterDirection.Output;

    cmd.ExecuteNonQuery(); // Execute the function

    //obtain result
    returnVal = int.Parse(cmd.Parameters["P_retvalue"].Value.ToString());
}

저는 호출되는 저장 프로시저가 항상 필요한 것은 아니라고 확신합니다.테이블에 P_Staff_Id가 있는지 빠르게 확인하고 결과를 반환하는 매우 간단한 절차입니다.

또한 이 문제는 부하 테스트 중에만 발생합니다.정상 작동 중에는 문제가 없지만 초당 1개의 메시지가 표시되는 과부하 상태에서는 일정 시간 동안 원활하게 실행된 후에 발생합니다.

해결 방법으로 연결 문자열에 "연결 시간 초과=600, 최대 풀 크기=150"을 추가했지만 문제가 해결되지 않았습니다.

개발 서버에서 동일한 애플리케이션을 실행하고 있으며 정상적으로 작동합니다.우리는 그곳에서 이런 문제를 만난 적이 없습니다.

무엇을 시도해야 하는지에 대한 어떤 제안도 감사하겠습니다.선택의 여지가 없어 보입니다.

비슷한 문제가 있었는데, 이 문제를 디버그하고 수정하는 데 시간이 좀 걸렸습니다.많은 입력 파일과 많은 스레드 처리, 각 스레드가 엔터티 프레임워크를 사용하고 Oracle db 연결을 여는 것, 그리고 많은 db 쿼리와 삽입을 수행하는 것에 대한 우리의 코드는 때때로 파일에 사용됩니다.하지만 대부분 효과가 있습니다.

Oracle Connection을 명시적으로 열기 위해 DbContext 생성자를 수정했습니다.나는 다음과 같은 코드를 추가했습니다.

for (i = 0; i < 5; i++)
   try {
       oracleConnection.Open();
   } catch (OracleException) {
     Sleep for 15 ms and retry. 
     On last attempt I also do OracleConnection.ClearAllPools()
   }

그것은 개선되었지만, 여전히 완전히 해결되지는 않았습니다.디버거의 캐치를 깨고 들어가 보니 많은 스레드가 열려고 하고 처리되는 스레드는 거의 없습니다.Open in Oracle 스택에서 Oracle은 내부 목적으로 ThreadPool을 수행합니다.사용자 작업 항목을 큐에 넣고 완료를 기다립니다.저는 그것의 기다림을 쌓아올린 위에서 볼 수 있습니다.여기서는 풀링된 연결을 많이 사용할 수 있습니다(기본값은 100). 10을 거의 사용하지 않습니다.그래서 그것은 자원이 부족하지 않습니다.

하지만 이 문제는 스레드풀을 사용한 코드에도 있습니다.추가 조절 없이 사용자 작업 항목을 큐에 넣습니다.저는 우리가 해야 할 모든 일들을 줄 서서 얼마나 많은 일들이 필요한지를 생각했습니다. 그리고 그냥 내버려두는 것이 멋지다고 생각했습니다.NET에서 처리합니다.하지만 이것은 미묘한 문제를 가지고 있습니다.모든 작업이 전체 대기열 수를 사용했습니다.Oracle Connection은 풀에서 풀링된 연결을 가져오려고 할 때 스레드 풀에도 대기열을 표시합니다.하지만 그것은 결코 완성되지 않을 것입니다.우리의 일은 모두 Oracle Connection을 기다리고 있습니다.열리면 대기 중인 스레드 프로세스가 계속 대기 중입니다.마지막으로 대기 시간이 초과되면 종료됩니다.풀링된 연결을 많이 사용할 수 있음에도 불구하고 ThreadPool 프로세스를 모두 사용했으며 Oracle의 스레드 풀은 기회조차 얻지 못한 것이 유감입니다.스레드 풀을 설정하는 중입니다.SetMaxThreads도 도움이 되지 않습니다.그 문제는 여전히 동일합니다.우리는 모든 스레드 풀 리소스를 독차지하고, Orcale은 하나도 찾지 못하고 대기열에 있을 것입니다.

해결책은 ThreadPool에만 의존하는 것이 아니라 자체 조절 기능도 추가하는 것입니다.BlockingCollection과 sempahors를 사용하고 ThreadPool에서 몇 가지 제한된 수의 동시 작업만 추가했습니다(예: 5).이러한 방식으로 Oracle Connection은 항상 사용 가능한 ThreadPool 스레드를 찾고 실패하지 않습니다.

심지어 저도 Connection을 사용한 후에도 이 문제가 더 자주 발생하곤 했습니다.닫기()

오랜 분석 끝에 아래에 언급된 바와 같이 몇 가지를 배웠습니다.

  1. 연결.Close()는 DB 연결을 삭제하지 않습니다.
  2. 연결 시간 초과가 문제가 db 쿼리에만 있는 것을 의미하지 않습니다.
  3. 연결 시간 초과는 연결 풀의 전체 연결로 인해 발생할 수도 있습니다(데이터베이스 연결의 최대 세션에 도달했을 때 원인이 되었습니다).

수정:- 분석에 오랜 시간이 걸렸지만 수정 시간은 2분에 불과합니다.

using(DbConnection instance)
{

}

예:-

using (DbConnection  objDbConnection = new DbConnection())
{
   ojDbConnection.PersistData();
}

PersistData(); 모든 dbOperations likeOpen에서 e.tc 을 닫습니다.

모두가 알고 있듯이 "사용"은 다음과 같은 간단한 형태입니다.

try
{

}
catch()
{

}
Finally
{
  Dispose objDbConnection;
}

나에게 도움이 되었으니 도움이 되길 바랍니다.

마지막에 connection.close()를 추가해 보십시오.코드에서 연결을 해제하고 연결 풀에 명시적으로 반환하지 않습니다.따라서 GC가 시작될 때만 연결 풀로 연결이 반환됩니다.

언급URL : https://stackoverflow.com/questions/32807889/oracle-data-provider-for-net-connection-request-timed-out