오버 스택으로 인한 EC2 서버 계속 터짐 이슈
문제발생 전 상태
-
다음은 저희 웹 서비스의 시스템 아키텍쳐입니다.
-
EC2 인스턴스 안에 Spring boot 서버와 Flask 서버가 동시에 있습니다. Flask는 AI 용도의 서버로 Dalle3 API와, Konlpy 라이브러리를 이용한 AI 서버라고 보시면 될 것 같습니다.
-
Spring boot에서는 유저, 일기 데이터에 대한 비지니스 로직을 구성한 기본 백엔드 서버입니다.
-
EC2 인스턴스로는 t2.medium을 사용했는데 CPU의 개수는 2개이고 메모리는 4기가 입니다.
- 그렇게 좋은 성능을 가진 인스턴스는 아니지만 저희는 학생이기에 비용 부분을 생각하여 일단 t2.medium으로 결정한 것입니다.
- EC2 안에 백엔드 서버가 2개가 있고, Redis 2개, Rabbitmq, Celery, React… 많은 기술 스택들이 담겨 있는 것이 문제였습니다. 배포 후 메트릭을 모니터링 해보기 위해 Grafana와 Promethes를 이용하려고도 했습니다.
- 그러나 저희는 EC2 인스턴스의 성능을 과대평가한 실수로 문제가 발생했습니다.
문제 발생
- 저희는 스택을 멈추지 않고 Elasticsearch와 Logstash를 이용해 검색 엔진을 구축해보려고 하였습니다. Elasticsearch는 역인덱싱을 이용해 검색 성능과 질을 향상 시킬 수 있기도 하지만 단순히 토이 프로젝트에 한 번 붙여보고 싶어서였기 때문입니다. 공부도 하고 좋잖아요! ㅋㅋ 그렇게 로컬 도커 환경에서 제대로 구현이 완료된 것을 확인하고 EC2 내에서도 적용을 해보려고 하였습니다.
- 여기서 근데! EC2 내에서 도커 컨테이너를 띄우려고 하면 이후에 네트워크 오류가 계속 발생하는 것입니다!!!!!!!
- 와이파이 네트워크 이슈인가? 라고 생각을 했지만 이후 한 번 더 EC2와의 연결이 끊겨지는 문제가 발생했습니다.
문제 발생 이유 : 예산 이상의 인스턴스를 초과하는 과도한 오버엔지니어링
- 뭔가 잘못됨을 감지하고 AWS의 EC2의 모니터링을 확인해보았습니다.
- 도커 컨테이너를 띄우는 도중 CPU 사용률이 최대 96.4까지 올라갔기 때문입니다. 결국 서버는 터지게 되어서 연결이 끊기고 컨테이너를 띄우지도 못하게 되었습니다.
문제 해결 방법 고민
- 이 문제를 해결하기 위해서는 우선 swap 메모리를 이용하여 해결하려고 하였습니다.
- swap memory : 실제 디스크의 용량을 이용하여 부족한 메모리를 대체할 공간
- 이유 : CPU 사용률이 높으니깐 메모리 사용률도 높을 것이라 판단 -> 디스크 속도보다 메모리 속도가 훨씬 빠름 -> swap 메모리를 이용해 디스크의 용량 중 일부를 가상 메모리로 사용하여 메모리 용량을 확보해서 메모리 부족 문제를 해결한다.
- 보통 swap memory는 할당된 램 메모리의 2배 또는 그 이상을 추천한다고 합니다. 그 외에 추가로 축적될 파일들의 용량(로그 파일들이 기록된다든지 등등) 도 고려해야 되기 때문입니다.
- 그럼에도 불구하고 Elasticsearch와의 연결문제, Front network 문제 등등 로컬 도커 환경에서는 발생하지 않았던 알 수 없는 에러들이 계속 등장했습니다. 😭 😭 😭
- 저는 이 문제들이 EC2 인스턴스의 과도한 CPU 사용률 때문에 발생한 것이라 생각을 했습니다.
- 따라서 저는 EC2 인스턴스의 Scale up을 통해 CPU 용량을 늘리거나, Spring boot 서버와 Flask 서버를 각각 인스턴스를 생기는 Scale out 방식을 생각해 보았습니다. 그러나 이것의 문제점은 더 큰 비용이 발생한다는 것입니다. ㅠ_ㅠ
- 비용을 늘리지 않고 현재 상황에서 정상적으로 서비스를 운영하기 위해서는 Elasticsearch와 Logstash로 구축한 검색 엔진을 버리면 되는 것입니다…. 흑흑
- 제가 그렇게 생각한 이유는 Prometheus와 Grafana는 메트릭을 시각화해서 실제 사용자들이 사용했을 때 분석을 하면 좋을 것 같아 필요하다고 느꼈고, Elasticsearch와 Logstash는 너무 무겁고, 실사용자가 너무 많아 검색 기능에 문제가 발생할 것 같다는 생각이 안들었기에 이 두 개의 스택을 붙이는 것은 결국 오버 엔지니어링이라고 판단을 하였습니다. (만약 사용자가 많다면, 그 때 Scale up/Scale Out을 하거나 Elasticsearch를 붙이면 좋을 것 같습니다.)
- 또한 기존의 검색 쿼리의 실행 계힉을 보면 type이 const와 ref로 튜닝이 필요가 없습니다. -> 즉, 검색 쿼리는 이미 최적화가 되어 있어 굳이 검색엔진을 도입할 필요가 없습니다.
- 결론 : 과도한 오버엔지니어링을 없에버리면서 해결이 됌
참고로…
- swap 메모리를 사용 안 했을 때는 CPU 사용률이 빨간색 선 넘어 버렸지만, swap 메모리를 사용한 이후 부터는 CPU 사용률을 조금은 줄일 수 있었습니다. 물론 swap 메모리를 통해 직접적으로 CPU 작업을 줄여주는 것은 아닙니다. CPU 작업은 주로 프로세스나 스레드의 실행에 따라 결정되며, 메모리 공간을 늘리는 것은 해당 프로세스가 메모리 부족으로 인한 성능 저하를 겪지 않게 하는 것입니다. CPU 사용률을 줄어진 것을 확인해서 swap 메모리를 적용하기 전에는 메모리 부족으로 인한 성능 저하가 발생했을 것 이라고 예상할 수 있었습니다.
Mixed Content 이슈
문제 발생 전 상태
- 웹 서비스에 HTTPS를 붙이기 위해 2가지 방법을 생각했습니다.
- Nginx에서 cerbot을 이용한 SSL
- AWS ACM에서 인증서 발급 후 ELB 적용
- 저는 AWS에서 인증서를 발급 받고 ELB를 통해 HTTPS를 적용하는 방식을 택했습니다. 왜냐하면 EC2는 t2.medium으로 실행 중인 server가 ssl decryption을 수행하지 않아도 되니 조금 더 가벼워 질 수 있기 때문입니다. → 서버의 짐을 하나 덜어준 셈입니다.
- 다음은 AWS 아키텍처인데
- 서버로 request가 들어오면 Load Balancer는 HTTPS(port 443) 요청인지 확인한다
- 만약 HTTP(port 80) 요청이면 Load Balacer가 HTTPS로 Redirection 한다.
- HTTPS 요청이면 Load Balancer가 SSL session의 종단점 역할을 대신해 요청을 Decryption해 Target Group의 80번 포트로 요청을 Forwarding 합니다.
이 순서로 흘러가게 됩니다. 따라서 이 구조에서 EC2 서버 내의 요청은 HTTP 통신인 것입니다.
문제 발생
- 그리고 테스트를 하기 위해 도메인에 접속해서 HTTPS를 확인했습니다. 근데!!! 개발자 도구를 확인해 본 결과 로그인 API 요청을 보넸을 때 Mixed Content라는 에러가 발생하면서 어떠한 기능도 수행할 수 가 없었습니다.
문제 발생 이유
- AWS ELB를 잘 못 설정해서 그런건가? 아니면 NGINX, REACT, 서버 간의 API end point가 잘못되었는지 부터 의심을 해보면서 삽질을 해보았는데 구글링을 통해 최신 브라우저들에서는 HTTPS 페이지에서 HTTP 리소스를 요청할 없다. 라는 것을 알 수 있었습니다!!
- 저희가 설계한 HTTPS 구조는 ACM + ELB로 EC2 내부에서는 HTTP 통신이어서 end point가 HTTP 일 수 밖에 없었습니다.
문제 해결
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
- 이 태그를 사용하면
http
로 요청을 보내면 브라우저가 똑똑하게 https
로 업그레이드 시켜주기 때문에 가능한 것이었습니다.
이는 웹페이지의 Content Security Policy (CSP)를 설정한 것입니다. Mixed Content 에러는 일반적으로 보안 정책에 어긋나는 리소스로 인해 발생한 것인데 CSP는 이러한 보안 이슈를 해결하기 위해 웹페이지에 대한 특정 보안 정책을 설정하는 데 사용됩니다.
- 이 메타 태그는 서버에 보내는 HTTP 요청을 HTTPS로 변환하는 것이 아니라, 브라우저에서 로드되는 웹 페이지의 리소스를 HTTPS를 통해 제공되는 콘텐츠로 변환합니다. 즉 클라이언트 측에서의 동작입니다.
- 따라서 이 태그를 index.html head 안에 넣으니깐 문제가 해결되었습니다. 로그인 성공!
참고 자료
[aws] ELB Application Load Balancer를 이용한 SSL 설정
[프론트엔드] - Mixed Content 이슈를 해결하며
Mixed content - Security on the web | MDN