개발 As 현생/오늘의 뻘짓 & 문제해결

클라이언트가 죽는 현상에 대한 고찰

민킹 2022. 2. 23. 22:13

 

------클라이언트 소개------
역할 : 교환기 전화데이터 수신 서버(=telServer)와 통신
위치 : telServer, 클라이언트는 각각 다른 망 위치
상황 : 클라이언트가 어느 순간 데이터 수신을 멈춤

 

테스트용 IP폰으로 걸려 온 전화를 받으면 통신원창에 발신자에 대한 정보가 떠야 한다. 그런데 며칠 후 다시 테스트 했을때는 전화를 받아도 발신자 데이터가 들어오지 않는 것이다. 

저번 출장 때 현장에서 프로그램 다 올려놓고 돌아가는 것 까지 확인 하고 왔는데 갑자기 안 된다? 다른 것 보다 Connection문제가 제일 먼저 떠오른다.

log폴더에 오늘자 로그가 생겼는지 확인 해 보자. 로그가 없다. 로그가 몇일 전 부터 생기지 않았다. 클라이언트 재기동을 해봐야겠다.

된다. 역시 통신의 문제였다. 어느 순간부터 둘의 통신이 끊긴 것 같다.

 

서버 문제일까? 클라이언트 문제일까?

현장에서 가져 온 로그파일을 나름대로 분석 해 보았고, 발견한 단서는 다음과 같다.

1. 클라이언트가 어느순간 "Error: java.net.SocketException: Connection reset"에러를 내고 재접속을 시도함
2. 재접속 시도 시 "Error: java.net.ConnectException: Connection refused: connect"에러와 함께 실패
3. 혹은 성공. 하지만 지속적으로 연결이 끊기며 1번과 2번을 반복.
4. 저녁시간에는 아무런 에러 로그를 남기지 않은 채 통신이 끊김

 

-Connection reset?

해당 로그는 '커넥션 에러'에 대한 가정확신으로 바꿔 주었다.

 

-Connection refused?

클라이언트의 재접속 시도 시 발생하는 에러. 평소에 보던 'Connection: timed out'이 아니다. Connection refused? 어떤 경우에 일어나는 에러일까? 대부분 서버 포트와의 연결문제라는 의견이었다. 그렇다면 포트와 연결이 되지 않는 이유는 무엇일까? 또 열심히 구글링을 하다 제일 간단 명료하다 생각하는 글을 캡쳐해왔다.

출처:http://daplus.net/java-java-net-connectexception-%EC%97%B0%EA%B2%B0-%EA%B1%B0%EB%B6%80/

 

잘못된 IP/호스트로의 연결? → 아니다. 올바른 주소로의 접속 시도라는것을 로그로 확인했다.

서버를 시작하지 않았다? 서버가 연결을 수신하지 않는다? → 가능성 있다. 하지만 서버 자체 문제는 아니라 판단했다. 왜냐하면 클라이언트를 아예 종료 후 재기동하면 정상 연결 되기 때문이다. 기존에 연결 된 클라이언트의 재접속만 불안정하다는건데... 그렇다면 외부 원인이 아닐까?

청취 백 로그 큐가 가득 찼다? → 재접속 시도는 대부분 24시간 내 7번 미만으로 일어난다. 가능성 낮다고 생각한다. 하지만 확실히 배제할 근거는 없어서 일단 우선순위를 낮추는 방향으로 갔다.

연결을 차단하는 방화벽이 없다? → 있다. 심지어 보안이 매우 중요한 사이트다.

 

-에러 로그 없이 통신이 끊긴다?

이건 뭐지? 커넥션 에러도 없이 어느 순간 통신이 끊긴다? 낯설다. 진짜 커넥션이 끊긴게 맞나하는 의심도 들었다. 로그가 안찍힌건가? 하지만 데이터가 들어오지 않는걸 봐서 커넥션에 문제가 있기는 한데.. 서로 에러를 내지 않고 있으니 당황스럽다. 클라이언트가 본인이 서버와 연결이 끊겼다는 사실조차 인지하지 못 하는 것 같다.

일단 이 현상은 저녁시간에만 발생한다. 저녁시간의 공통점이 있다. 바로 들어오는 데이터가 많지 않다는 것이다. 

 

---

정리를 해 보자. 해당 현상에 대해 나는 세 가지를 염두에 두고 있었다. 서버(업체), 클라이언트(나), 방화벽. 일단 서버는 24시간 정상 동작을 하고 있다. 그리고 외부망의 다른 클라이언트는 해당 서버와 정상적으로 연결을 유지한다. 그렇다면 내 클라이언트가 문제일 확률 99%.

설치 전, 회사 내부에서 테스트를 돌릴때는 클라이언트가 계속 멀쩡히 잘 붙어있었다. 그런데 사이트에서는 끊긴다? 사이트와 회사 환경의 차이점을 생각해 볼 시간인 것 같다.

음..방화벽?

그래. 방화벽을 파보자. 방화벽이 자꾸 내 클라이언트와 서버를 끊어낸다고 가정하자. 그렇다면 방화벽이 연결을 끊어내는 이유는? 서버의 데이터전송이 수상하다 판단 했겠지? 왜 수상할까?

너무 일방적으로 서버만 데이터 전송을 하긴 하네. 수상할만하다. 내가 방화벽이라도 의심할 것 같다. 클라이언트는 서버쪽으로 아무런 데이터를 보내지 않는데 서버만 클라이언트로 데이터를 자꾸 주니까. 마치 싫다는데 자꾸 괴롭히는게... 꼭 해커같잖아..

그리고 또... 몇 시간동안 아무런 데이터가 오가지 않는다면 방화벽에서 커넥션을 끊어버릴 수도 있지 않을까? 하는 생각이 들었다. 퇴근시간부터 다음 출근 시간까지 데이터가 단 한건도 들어오지 않을 확률이 높다. 업무시간이 아니니까.

 

그래서 결론은?

클라이언트와 서버는 서로 소통하는 사이라는걸 방화벽에게 알려주자. 그리고 데이터가 들어오지 않는 시간에도 둘은 소통하는 사이라는걸 알려주자.

서버쪽으로 지속적으로 메시지를 보내자.

나는 클라이언트에 일정한 시간 간격으로 서버로 메시지를 보내는 기능을 추가하였고 결과는...

 

성공이다!!!

클라이언트가 더 이상 죽지 않았고 현재 성공적으로 시범운영을 하고 있다.

아.. 너무 감격스럽다ㅠㅠ

 

알고보니 내가 고민한 모든것은 다 용어가 있었다.

지속적으로 서버로 보내는 메시지 → Heart Beat Message

클라이언트가 연결이 끊긴지 모르는 상태 → Zombie Session

 

역시 알고보면 더 잘 보인다. 해결하고 나면 내가 이걸 몰랐네 싶다. 특히나 좀비세션은 CS클라이언트를 개발할때 반드시 체크해줘야 할 부분이라고 한다. 또한 Exception발생 이유가 꼭 로직만이 이유가 아닐수도 있다는 것을 배웠다. 환경에 의해 발생하는 Exception이 있다는걸 더 확실히 인지할 수 있게 된 것 같다.(여기서는 방화벽이 그 역할을...)