모락의 운영 인프라는 클라이언트-웹서버-웹애플리케이션서버-데이터베이스로 구성되어있으며, 로드 밸런싱, CI/CD 자동화, 무중단 배포, 모니터링, 슬랙 에러 알림 등으로 서비스의 안정성을 높이고 있습니다.
현재 모락의 인프라 구조에서 Nginx는 꽤 많은 역할을 해주고 있습니다.
클라이언트에게 정적 파일을 호스팅해주는 WS의 역할을 하고 있습니다. 모락의 프론트엔드는 React 기반으로 개발했기 때문에 build 과정을 거치면 관련 정적 파일을 가지고 있는 dist 디렉터리가 생성됩니다. 이 dist 디렉터리 내의 정적 파일들을 url에 따라 클라이언트에게 응답해주고 있습니다.
애플리케이션 서버를 감춰주는 리버스 프록시 역할을 하고 있습니다. 클라이언트는 프록시 서버로 요청을 보내고 프록시 서버는 알맞은 애플리케이션 서버로 요청을 보내고 응답을 받아와 클라이언트에게 전달해줍니다.
리버스 프록시의 특징
- 로드밸런싱: 리버스 프록시 뒤에 여러 WAS를 두고 사용자의 요청을 분산시킬 수 있습니다. 모락에서는 두 대의 WAS로 로드밸런싱을 하고 있습니다.
- 보안: 프록시 서버만 public IP를 이용해 외부망과 통신할 수 있게 열어두고, WAS와 DB 서버는 private IP를 이용해 내부망에서만 통신할 수 있게 하므로써 보안을 강화할 수 있습니다.
기존 인프라 구조에서는 여러 지점의 SPOF가 있었고, 그 중 하나가 WAS였습니다. 하나의 WAS에 장애가 발생하면 이는 모든 시스템의 장애로 이어집니다. 따라서 저희는 시스템의 고가용성을 위해 WAS를 스케일 아웃하기로 결정했습니다.
Nginx의 설정 파일에서 upstream 속성에 WAS1과 WAS2의 IP를 등록해 로드밸런싱을 적용했습니다. 로드밸런싱 알고리즘에는 여러가지가 있겠지만 두 WAS가 떠있는 인스턴스의 사양이 동일하고 역할도 같기 때문에 세부적인 설정까지는 필요없다고 판단해 기본 설정인 라운드로빈 알고리즘을 사용하고 있습니다. (유로 버전의 Nginx에서는 로드밸런싱을 제공해줍니다.)
라운드로빈 이외에는 현재 커넥션이 가장 적은 서버로 요청을 보내거나 IP hash에 따라 요청을 분기하는 등의 방법이 있습니다.
팀의 개발 생산성을 높이고 휴먼 에러를 방지하기 위해 모락에서는 CI/CD 과정을 자동화했습니다.
CI 과정에서는 추가적으로 SonarQube를 이용한 정적 분석 과정을 자동화했습니다. 코드 리뷰 전 정적 분석 결과를 확인해 기본적인 컨벤션을 맞추고 버그 가능성이 보이는 코드를 제거함으로써 개발자의 편의성을 증대시켰습니다.
레포지토리가 타 오가니제이션의 권한으로 설정되어 있어 SonarCloud를 사용할 수 없었습니다. 이러한 경우가 아니라면 별도의 서버 구축이 필요하지 않은 SonarCloud만으로도 충분할 것이라고 생각합니다.
대표적인 무중단 배포 방식에는 롤링, 블루-그린, 카나리아 방식이 있습니다. AB 테스트가 필요없으며 호환성 문제가 발생하지 않길 원했기 때문에 블루-그린 방식을 채택했습니다. 하나의 인스턴스에서 서로 다른 포트를 이용해 블루 서버, 그린 서버를 나누었습니다.
Jenkins를 활용했습니다. Deploy Job에서 1. 현재 그린 서버의 포트를 확인하고 그 반대 포트로 새로 배포되는 서버를 띄웁니다. 2. 새로 배포된 서버가 잘 실행 됐는지 health check를 수행합니다. 3. Nginx 서버의 설정파일을 이번이 그린이 되는 포트로 변경합니다. (리눅스의 envsubt 명령어 활용) 4. 기존 그린 서버를 다운시킵니다.
무중단 배포 적용 전에는 10~20초(기존 서버를 죽이고 새로 띄우는 시간) 정도 전체 시스템이 다운 되었는데, 무중단 배포를 적용해 가용성을 높일 수 있었습니다. 또한 새로 배포한 버전에서 문제가 발생하는 경우 바로 블루 서버로 전환하면 되기 때문에 장애 상황에 빠르게 대처할 수 있는 환경을 만들 수 있었습니다.
Spring Actuator를 활용해 서버의 데이터를 제공합니다. 이러한 데이터 중 메트릭 데이터는 Prometheus를 이용해 수집하며, 로그 데이터는 Loki를 이용해 수집합니다. Grafana에서는 Prometheus와 Loki에서 데이터를 받아와 개발자가 분석할 수 있게 데이터를 시각화해줍니다.
보통 부하테스트를 하는 과정에서 CPU 사용률, Thread 개수, HikariCP Connection 개수, 요청 처리 시간 등을 모니터링했습니다.
