오늘 배운 것

오늘은 어제 진행 중이던 이슈를 계속 진행해 볼 예정이다. 더불어 workflow의 진행이 20분동안 걸리는 것도 문제인 것 같아서, 멘토님께 여쭤보니 ECS에서 health check를 하는 과정에서 시간이 길게 걸릴 가능성이 있다고 말씀해주셨다. 

 

즉 서버 배포 관련해서 해결해야 할 이슈는 긴급도 순으로 정리하면 다음과 같겠다.

1. yaml 파일을 계속 수정하면서 develop 브랜치의 최신 내용이 개발서버에 반영되도록 하기

2. 로드밸런서의 health check에서 시간이 약 20분 정도 걸리는 문제 해결

3. github workflow에 pytest 및 runserver 테스트하는 로직 추가

4. 서버 성능 테스트 해 보기

 

오늘은 이 중에서 1번과, 가능하다면 2번까지 해 보는 것을 목표로 하면 좋을 것 같다. 특히 2번도 꽤 급한 게, 1번이 되는지를 빨리 확인하고 싶은데 계속 몇 분씩 기다려야 해서... 이것도 사실상 1번만큼 급한 이슈인 것 같다. 그냥 1-2번은 가리지 않고 같이 해결하면 될 것 같다. 

답답

github workflow의 로그를 보니 AWS ECS 클러스터>서비스>이벤트의 로그를 보라고 말해주어서, 이 로그를 보면 뭔가 힌트를 얻을 수 있을 것 같아서 찾아봤다. 

로그는 은근 친절하다

 

로그를 보면 (내 추측이지만) 태스크를 시작하고(has started 1 tasks), EC2에서 지정한 타겟 그룹(여기서는 onestep_dev)에 타깃을 등록하고(registered 1 targets in target-group), 해당 태스크에 대해서 커넥션을 차단(draining connections)하는 패턴의 반복인 것 같다. 

 

그리고 이 패턴은 5분마다 반복된다. 왜일까? 이것은 설정값과 관련이 있어 보인다. 사실 이전에 기본값으로 로드밸런서의 헬스체크 간격이 10초로 되어있는데, 이걸 300초로 바꿨었다. 지금 생각해보면 왜 그랬나 싶지만, 그때는 그것 때문에 로드밸런서에서 서버에 10초마다 계속 요청을 보낸다고 생각했었고, 그게 너무 서버에 쓸데없는 요청을 계속 날리는 게 아닌가 싶어서 그 값을 딱 5분인 300초로 설정해 놓았었다... 쓰다보니 이게 원인일 가능성이 높겠다. 

 

그렇다면 어서 바꿔보자. EC2>대상 그룹에 들어가서 해당 대상 그룹의 기존 헬스체크 기준을 보니 2번 연속 성공이고, 2번 연속 실패하면 fail로 간주하며, 각 요청의 간격은 300초(...)로 되어 있었다. 그래서 이 요청의 값을 2번 연속 성공, 4번 연속 실패하면 fail로 간주하며, 요각 요청에서 응답이 올 때까지는 5초간 기다리고, 각 요청의 간격은 10초로 설정해 주었다. 

 

로드밸런서의 설정을 해 주었어도 여전히 태스크가 fail이 나면 다시 실행되는 작업들이 5분 간격으로 진행되고 있었다. 그래서 정확히 뭘 해야할진 모르겠지만 로드밸런서의 타깃 그룹 설정 외에도 다른 것들을 해 주어야 할 것 같다. 마침 멘토님께서 참고하라고 보내주신 링크가 있어서, 이 링크를 읽어보고 내가 하지 않은 부분을 찾아보면 되겠다. 


참고한 문서에서는 로드밸런서의 헬스 체크 기준 체크, 로드 밸런서의 연결 해제(connection draining) 작업 관련 설정, ECR에서 도커 이미지를 업로드하는데 걸리는 시간 등을 고려하라고 말해주었다. 헬스 체크 기준은 위에 언급한 것처럼 각 요청 간의 시도 간격을 10초로 바꿔주어서 괜찮을 것 같았다. 도커 이미지의 경우는 크기도 크지 않을뿐더러 대부분의 github workflow의 시간은 ECS에서 배포하는 데 걸렸지 ECR에 도커 이미지를 업로드하는데 쓰고 있지 않았어서 이것도 원인으로 보지는 않았다. 몰랐던 부분은 '로드 밸런서의 연결 해제 과정'이었다. 

서버에서 캡처해온 사진입니다

 

덕분에 ECS 서비스를 설정할 때 로드밸런서를 지정하는 것이 무슨 의미인지 조금이나마 더 알 수 있었다. ECS 서비스가 disable 되는 과정은 다음과 같았다. 

 

ECS 서비스에서 로드밸런서에게 현재 로드밸런서에 연결 중인 클라이언트에 대해 연결을 끊으라고 요청한다. 그리고 로드밸런서가 클라이언트에 대해 커넥션을 끊었는지를 모니터링 한다. 이 요청을 받았을 때 로드밸런서는 바로 연결을 끊지 않고, 클라이언트(서버에 접속해 있는 브라우저나 앱 등의 클라이언트를 의미한다)가 keep-alive 커넥션을 끊었는지를 확인한다. 만약 끊지 않았다면 로드밸런서는 기본 설정된 값 동안 클라이언트가 keep-alive 커넥션을 끊기를 기다린다. 문서에서는 이 기본값(deregistration delay)이 300초로 설정되어 있다고 했다. 그렇다면 5분 뒤에 새로운 시도가 이어지는 것이 설명된다. 

 

이 기본 시간이 지나면 로드밸런서는 자신과 연결된 클라이언트의 연결을 강제로 종료시킨다. 그러면 ECS 서비스에서 이것을 알 것이고, 그러면 해당 컨테이너의 프로세스를 종료시키는 SIGTERM 시그널을 보낸다. 그런데 그림처럼 컨테이너에 직접 시그널을 보내는 것은 또 아닌 것 같고, 컨테이너와 같은 namespace? network? 어쨌든 같은 도메인이나 무언가에 속해 있는 Agent에게 해당 요청을 보내면 해당 agent가 컨테이너에게 SIGTERM 시그널(혹은 요청)을 보내는 방식으로 이해했다. 

서버에서 캡처해 온 사진입니다

 

이제 이 기본값이 300초로 설정된 deregistration delay 값을 바꿔주면 되겠다. 문서에서는 5초로 바꾸라고 해서 그렇게 해 보면 되겠다. 

GPT는 바로 구체적인 방법을 잘 제시해 주었다. EC2>대상 그룹>설정에서 '등록 취소 지연(드레이닝 간격)'의 값을 확인해 보니 300초로 되어 있었다! 이걸 바로 5초로 바꿔주었다. 

 

이제 임의의 변경사항을 develop 브랜치에 만들어서, github workflow의 실행 시간이 단축되는지를 확인해 보자. 

 

단축은 되었다! 더 단축될 수 있는지는 모르겠지만 확실히 시간은 줄었다. 여전히 개발 서버에 내용이 반영은 되지 않는다... 직접 도커 이미지를 pull 받아서 확인해 보고 싶었지만, 예전에 unauthorized 에러가 났었다. 이쯤 되면 ECR에 최신 이미지가 안 올라오는 것이 아닌가? 하는 추측도 든다. 이 부분에 대해서는 내일 확인해 보면 될 것 같다. 

 

 궁금한 것

1. AWS 내부에서 사용하는 시그널 같은 것이 있나보다. (SIGTERM 시그널을 보낸다는 점에서 그런 추측을 했다) 어떤 시그널이 있고, 어떻게 시그널을 보내도록 되어 있는 것인지도 궁금하다. 

 

 

 

 

 

 

+ Recent posts