WCF : netTcpBinding에서의 각종 Timeout 값 설명
WCF 서비스를 참조하게 되면, 클라이언트 측의 app.config에 제법 많은 설정값들이 구성됩니다. 처음에는 당황스러울 정도인데요. 오늘은 그중에서 "netTcpBinding"에서 제공되는 "closeTimeout", "openTimeout", "receiveTimeout", "sendTimeout", "inactivityTimeout" 값들에 대해서 알아보도록 하겠습니다. (참고로, 여기서 제공되는 값들에 대한 설명은 "Session이 설정된 netTcpBinding" 서비스인 경우로 가정하겠습니다.)
1. openTimeout, closeTimeout
이 값들은, 서로 대칭적인 의미를 가지기 때문에 한꺼번에 설명해 보도록 하겠습니다. 사실, 어찌 보면 설명할 것도 없지요. 이름에서 의미하듯이 서비스가 열리고/닫히는 순간에 필요 이상의 시간이 소모되는 것을 막을 수 있도록 해주는 값입니다.
openTimeout/closeTimeout 값은 모두 기본값이 1분으로 설정되어 있습니다. 의미인 즉, 클라이언트에서 서비스에 접속하려고 할 때, 만약 서비스를 호스팅하고 있는 서버가 죽어 있는 경우에 "1분" 동안 클라이언트 측의 호출 쓰레드가 "Blocking" 된다는 것입니다. 별로 바람직하지는 않죠! 약 3 ~ 10초 정도면 적당할 거라 봅니다.
하지만, 한편으론 시간을 너무 줄이는 것은 주의해야 합니다. .NET의 경우 JIT 컴파일링이 메서드 호출 시에 이뤄지다 보니, 최초 접속 시에는 서비스가 올라오기까지 시간이 좀 걸리기 때문에 openTimeout을 너무 짧게 잡아버리면 예외가 발생하는 경우도 생길 수 있습니다.
closeTimeout의 경우, WCF 연결이 된 상태에서 네트워크 선을 뽑은 후 System.ServiceModel.ClientBase<>.Close 메서드를 호출하게 되면 closeTimeout에 지정된 시간만큼 블록킹이 발생한 후 TimeoutException이 발생하게 됩니다.
부연 설명을 더 드리자면, 항상 정확하게 openTimeout/closeTimeout에 지정된 시간만큼의 지연이 발생하지는 않는다는 점에 유의하셔야 합니다. openTimeout 값을 10분으로 설정했다고 해서, System.ServiceModel.ClientBase<>.Open 메서드가 존재하지도 않은 IP 또는 포트에 대해 10분을 꽉 채운 후에 제어가 반환되는 것은 아닙니다. 즉, 10분으로 설정했어도 35초 만에 Open 메서드 호출이 실패해서 반환될 수 있습니다.
2. sendTimeout
이 값 역시, 어느 정도 의미가 와 닿지요. 특정 메서드를 호출할 때 지정된 sendTimeout 시간 이내에 메서드 실행이 완료되지 않으면 TimeoutException 이 발생하게 됩니다.
재미있는 것은 이것이 서버 측 EXE의 config 내에 있을 때는, 콜백 함수의 실행 시간을 나타내고, 클라이언트 측 EXE의 config 내에 있을 때는 서비스가 제공하는 메서드를 호출하는 시간 만료에 대한 의미를 가집니다.
3. receiveTimeout
이 값은, 정확하다고는 말할 수 없지만 클라이언트에서는 설정 자체에 대한 아무런 의미가 없는 것 같습니다. 단지 서버 측에서 쓰일 때는 의미를 지닙니다. WCF 서비스는 지정된 receiveTimeout 시간 내에 클라이언트로부터 아무런 메서드 호출이 없으면, 설령 클라이언트가 정상적으로 연결되어져 있다 하더라도 접속을 끊어버리는 데에 이 값을 사용하고 있습니다. 그러니까, 만약 이 값을 5초로 설정했다면 반드시 5초 이내에는 해당 서비스에서 제공되는 메서드를 호출해 주어야 서버와의 연결을 지속적으로 유지할 수가 있습니다.
'꼭 기억해 두십시오. 연결이 맺어져 있는 경우라 할지라도 지정된 시간 동안 서비스를 사용하고 있지 않으면 강제로 연결을 끊어버린다는 것.'
4. inactivityTimeout
마지막으로 설명할 이 값은, 특이하게도 reliableSession 요소의 속성값으로 존재합니다. 이 값은, 지정된 시간 동안 상대방에 대해 연결을 확인할 수 없으면 강제로 현재의 연결 개체를 끊어버리도록 해줍니다.
일례로, 서로 WCF 연결 관계를 맺고 있는 2대의 컴퓨터가 있다고 가정할 때. 어느 하나의 컴퓨터에서 랜선을 뺀다거나, 컴퓨터 전원 플러그를 강제로 뽑는다거나, 작업 관리자에서 WCF 프로세스를 강제로 종료하는 등의 경우에 inactivityTimeout 값이 위력을 발휘하기 시작합니다. 만약 이 값이, WCF 서비스 측에 5초로 설정되어 있다면, 클라이언트 프로세스를 작업관리자로 강제 종료시키고 약 5초 후에 서비스 측에서의 연결 개체도 회수되는 것을 확인할 수 있습니다. (바로 이때 불려지는 이벤트를
지난 회에 설명 드린 OperationContext.Current.Channel.Faulted로 잡아낼 수 있습니다.) 물론, 반대로 클라이언트 프로세스에 이 값이 10초로 지정되어 있다면, 서버 측 서비스가 10초 동안 아무런 응답도 할 수 없는 상황에 놓이면 예외가 발생하게 되어 클라이언트가 이를 감지할 수 있습니다.
좀 정리가 되시나요? 가만 보면, .NET Remoting에서 사용되던 Lease Manager 개념과 많이 비슷한 것을 볼 수 있습니다. 한 가지 더 참고로 말씀드리면, sendTimeout, receiveTimeout, inactivityTimeout 등의 값을 너무 짧게 잡으면 VS.NET에서 디버깅 시에 쪼끔 괴롭습니다. (BP 걸고 한 라인씩 코드 실행해 보는 동안 연결이 강제로 끊겨 버립니다.)
마지막으로 한 가지 더! 서버의 비정상 종료에 의해 클라이언트 측에서 발생하는 예외에 관련된 부분을 언급해 보겠습니다.
대개의 경우, sendTimeout에 지정된 시간 동안 메서드 완료가 안되면 거의 서버가 종료되었다고 봐도 무방한 경우가 있을 것입니다. 이런 경우에는 특히 inactivityTimeout 값을 잘 설정해 주어야 합니다.
예를 들어, 다음의 경우를 보겠습니다.
while ( true )
{
try {
svc.DoMethod(); // 서비스에서 제공되는 오퍼레이션 호출
Thread.Sleep( 1000 );
} catch (TimeoutException ex)
{
} catch (CommunicationException ex)
{
}
}
위와 같은 상황에서, 어느 순간 대상이 되는 서비스를 강제 종료를 하게 되면, 곧이어 발생하는 메서드 호출에서 sendTimeout 시간 동안 응답을 받지 못해 TimeoutException이 발생하게 됩니다. 바로 여기서부터 문제가 발생됩니다. 만약 이때, inactivityTimeout 값이 1분이고 sendTimeout 값이 5초라면, 1분 동안 계속해서 5초마다 TimeoutException이 발생하고 나서야 CommunicationException이 발생하게 되어 OperationContext.Current.Channel.Faulted 이벤트가 실행되어집니다.
대부분의 경우에 위와 같은 상황을 원하는 경우는 없을 것입니다. sendTimeout 내에 메서드 실행이 완료되지 않으면 서비스가 비정상 종료되었다고 판단하고 서비스 재접속을 시도하는 것이 바람직할 수 있습니다. 따라서, 이런 경우에는 inactivityTimeout == sendTimeout 값을 같게 설정하는 것도 고려해 볼 수 있겠습니다.
[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]