본문 바로가기
DevOps/AWS

AWS elasticBeanstalk 성능 향상기(1) - 성능 향상을 해야하는 이유

by mandarinko 2022. 12. 25.

이전링크에서 상용 환경의 ELB를 변경하였습니다. 

CLB -> ALB로 변경 후 특정 시간대에 로드밸런서에서 5XXs에러가 다수 발견 되었습니다.

문제 발생의 원인을 찾고 해결하는데 있어 팀장님의 큰 도움을 받아 문제를 해결할 수 있었습니다.

따라서 해당하는 기록을 남겨보려 합니다.

 

에러 발생

ALB HTTP 5xxs

특정 시간에 로드벨런서에서 5XXs에러가 무수히 많이 발생하고 있었습니다. 다만 HTTP2XXs 응답도 되고 있었습니다. 2XXs응답이 특정 Count이상에서 발생하는 게 아닐까 하고 추측하고 찾아보았지만 원인을 찾을 수 없었습니다.

CLB -> ALB 교체 과정에서 빈스톡 인스턴스 환경을 추가적으로 조금 수정해주었습니다. AWS에서 지원해주는 AWS linux2(arm64)로 변경하였습니다.

linux2 환경에서는 beanstalk 환경을 생성하면 자동적으로 nginx를 구성해줍니다.

기존의 linux1 환경에서 beanstalk을 구동하였기에 nginx 로그를 볼 생각을 크게 하지 못했으나 팀장님께서 확인해보신 nginx로그에서

99: Cannot assign requested address

에러로그를 확인할 수 있었습니다. 다만 해당 에러를 검색해보면 ip, port 설정문제에 대한 자료가 많습니다.

 

nginx 에러 원인 찾기

nginx에러 로그를 기반으로 조금만 더 찾아보다 보니 참고할만한 사이트를 찾을 수 있었습니다.

 

포트 범위가 문제였습니다.

위의 내용을 보면 대게 3만 개 이하의 TCP커넥션을 맺을 수 있다고 되어 있습니다.

아래의 명령어를 통해  각각의 인스턴스에서 열려있는 커넥션을 찾아보았습니다.

$ ss -s
Total: 1201
TCP:  26809 (estab 871, closed 25923, orphaned 3, timewait 25922)
Transport Total   IP    IPv6
RAW	 0     0     0
UDP	 24    20    4
TCP	 886    874    12
INET	 910    894    16
FRAG	 0     0     0

TCP 커넥션이 3만 개에 거의 도달했다고 생각할 수 있습니다. 또한 timewait 상태가 26000개가량 있는 것을 확인할 수 있었습니다.

timewait이 왜 이렇게 많은가 싶어

netstat -nap | grep TIME_WAIT

명령어를 통해 확인한 결과

내부 로컬포트에서 로컬 4001 포트로의 TIME_WAIT이 다수 걸려있는 것을 확인했습니다.

 

TIME_WAIT 왜?

TCP connection은 최초 송신자와 수신자가 connection을 open 하기 위해 3-hand-shaking을 하고 데이터를 송수신합니다.

이후 송, 수신자 중 연결을 끊기 위해서는 FIN을 보내고 최종적으로 FIN을 받은 곳으로부터 FIN을 수신받으면 최초 연결을 끊기 위해 FIN을 수신한 쪽이 TIME_WAIT상태에 머무르게 됩니다. TIME_WAIT은 60초(default) 간 유지하게 되고 TIME_WAIT상태는 패킷의 오작동을 막기 위해 필요하다고 간단하게 설명하고 넘어가겠습니다. 아래 참고사이트에서 더욱 자세하게 알 수 있습니다.

TCP connection 커넥션 및 TIME_WAIT 관련 참고 사이트를 보면 자세하게 나와있습니다.

 

TIME_WAIT과 에러 발생의 관계

API request가 발생하면 ALB로 최초 request가 도달하고 이후 각 인스턴스에 요청이 전달됩니다.

각 인스턴스에 전달된 요청은 인스턴스 내부에서 동작하는 nginx에 request가 도달하고

해당 request는 내부 로컬 포트(32768 ~ 60999)를 사용해서 우리가 동작시킨 앱서버에 요청을 보내게 됩니다.

출발지: localhost:(32768 ~ 60999) -> 목적지: localhost:4001(저희 서버는 4001 포트에서 동작합니다)

이때 nginx -> 앱서버의 내부 통신에도 각 request마다 세션을 만들고 tcp connection을 맺습니다.

과정

  1. nginx -> 앱서버로 request
  2. nginx -> 앱서버 tcp 3-hand-shaking
  3. 앱서버 -> nginx 데이터 전송
  4. nginx -> 앱서버 tcp 4-hand-shaking을 위해 FIN전송
  5. nginx TIME_WAIT(60초 대기)
  6. 연결 종료

위의 과정이 가용 로컬포트(32768 ~ 60999)만큼 사용되고 데이터 전송이 마무리되면 TIME_WAIT단계에서 60초 대기를 하고 있습니다.

이때 request가 몰려서 모든 가용포트가 TIME_WAIT에 걸려있다면 request를 전달할 수 있는 가용포트가 없기 때문에 에러가 발생합니다.

 

사실 포스팅을 하면서 환경을 변경하는 데 있어 부하 테스트를 진행하고 했으면 에러를 만나지 않았을 것...이라는 생각이 깊게 들면서 앞으로는 부하테스트를 잘해야겠다는 생각도 들었습니다.

 

이제 발생한 에러의 원인은 파악을 완료했습니다. 다음 포스팅에서 에러를 해결하는 방법에 대해 이야기해보도록 하겠습니다.

 

참고 사이트

https://tech.kakao.com/2016/04/21/closewait-timewait/

https://brunch.co.kr/@alden/11

https://serverfault.com/questions/154663/how-to-find-the-number-of-open-ports-in-linux

https://serverfault.com/questions/421310/check-the-number-of-active-connections-on-port-80