본문 바로가기
삽질일기/트러블 슈팅

[AWS] ELB와 Nginx가 만들어낸 장애

by 권성호 2022. 1. 11.

어제 오전 출근하자마자 클라우드에 올라간 서버에 접속이 안된다는 문의가 들어왔습니다.

 

지난 9월에 클라우드에 올라간 직후 4달가량 멀쩡히 운영되던 클라우드 서버가 갑자기 접속이 되지 않는다니?!

 

어떤 설정도 건드리지 않았고 배포를 다시 한 것도 아니었는데 갑자기 문제가 발생하여 매우 의아했습니다.

 

우선 원인을 분석하기 위해 Cloud Watch를 통해 각 서비스의 로그를 확인했고 ELB의 모니터링 대시보드를 확인해 보았습니다.

(참고로 클라우드에 올라간 서버 구성을 짧게 설명하자면, 앞단에 ELB를 두고 뒷단은 spring cloud기반 마이크로 서비스로 구성되어 있습니다. ELB를 통해 scale out을 적용하기 위해 모든 트래픽은 ELB를 통하게 구성하였습니다.)

 

확인 결과 눈에 띄는 현상은 아래와 같았습니다.

  1. 1월 10일 9시 새벽부터 ELB의 5xx응답 개수가 급격히 증가했습니다.
  2. nginx의 access log를 보니 대부분의 요청이 499로 처리되고 있었습니다.(499는 nginx에서 정의한 코드입니다. 클라이언트가 서버로 보낸 요청에 대해 서버의 응답이 지연될 시 일정 수치[타임아웃]를 넘게 되면 클라이언트에서 연결을 종료하는데, 이러한 상황에서 nginx는 499 코드를 남깁니다.)
  3. nginx 뒷단의 마이크로 서비스로 트래픽이 전달되지 않고 있었습니다.

 

즉, [클라이언트 -> ELB -> nginx]까지의 트래픽은 정상적으로 들어오지만, [nginx -> 뒷단의 마이크로 서비스]로의 트래픽이 전달되지 않고 있었고, nginx에서는 지속적으로 타임아웃이 발생하고 있었습니다.

 

원인이 nginx에 있다고 판단하여 log를 상세하게 확인한 결과 nginx가 바라보는 ELB의 ip가 잘못되어 있었습니다.

(다시 말하자면, ELB를 통해 scale out을 적용하기 위해 모든 트래픽은 ELB를 통하게 구성하였습니다.)

 

nginx는 ELB의 위치를 ip가 아닌 도메인 네임으로 기록하고 있었습니다. 

이렇게 하면, nginx가 기동 시 도메인 네임에 대한 실제 ip를 네임서버에 질의해 케싱 해 둡니다.

그런데, nginx 기본 설정은 항상 케싱 된 정보를 사용하는 것입니다.

따라서, ELB의 도메인 네임에 해당하는 ip가 변경된다면 nginx는 엉뚱한 ip로 트래픽을 라우팅 하게 됩니다.

 

그렇다면, ELB의 ip가 바뀔까요?

AWS는 ELB의 A 레코드를 고정적으로 제공하지만 실제 인스턴스는 상황에 따라(트래픽에 따라?!) 늘거나 줄어들 수 있습니다. 따라서 실제 ip가 변할 수 있습니다.

정리하면, nginx는 기동 시 ELB의 실제 ip를 케싱 해 두고 트래픽을 그쪽으로 보내는데 정작 ELB의 ip가 변하게 되면 엉뚱한 곳으로 요청을 하기 때문에 지속해서 타임아웃이 발생하게 됩니다.

따라서 nginx에서 실제 ip를 케싱 하지 않도록 하면 됩니다.

 

방법은 간단한데, 기존에 정적으로 지정한 ELB의 도메인 이름을 변수 처리하고 별도의 resolver를 설정하여 일정 주기마다 cache를 갱신하도록 하면 됩니다.

 

nginx설정을 위에 설명한 대로 바꾼 후 클라우드 서버에 배포하니 다시 정상 동작하는 것을 확인했습니다.

 

참고 글

https://circlee7.medium.com/nginx-proxy-pass-%EC%9D%98-aws-elb-%EC%97%B0%EA%B2%B0-%EC%84%A4%EC%A0%95-f0c4b792ef71

 

 

 

댓글