WATCHA PLAY 서비스 MSA 적용하기

왓챠

Photo by Linh Pham on Unsplash

소개

안녕하세요. WATCHA에서 서버 개발을 하고 있는 Allan 입니다. 이번 포스팅에서는 WATCHA PLAY 동영상 플랫폼에서 MSA를 적용한 사례에 대해 이야기를 해보고자 합니다.

적용전 시스템

기존의 WATCHA PLAY 동영상 플랫폼은 크게는 WEB 서버, API 서버, 추천 서버 등으로 구성되어 있었습니다.

이 중 API 서버가 거의 모든 요청을 처리하고 있었고, 지속적으로 다양한 기능이 추가되며 잦은 배포가 이뤄지면서 간혹 장애가 발생하기도 했습니다.

특히 영상 재생과 관련된 트래픽이 전체 트래픽의 30% 이상을 차지하고 있었고, 영상 재생 부분과 관련 없는 곳에서 장애가 발생하였을 경우에도 영상 재생에 영향을 끼치게 되어, 장애 대응 및 성능 측면에서 분리가 필요한 상황이었습니다.

그래서

영상 재생 관련 일부 서비스를 분리하여 성능 향상을 도모하며, 장애에도 견고한 서비스를 만들어 최대한 영상 재생에 영향을 적게 끼칠 수 있도록 하기 위해 MSA(MicroService Architecture) 기반으로 서비스를 구축하였습니다.

사용 기술 스택

새롭게 적용된 시스템 소개에 앞서, 사용한 기술 및 용어에 대해 설명합니다.

AWS Elastic Beanstalk With ECS: 적용된 서버는 ECS 기반의 Elastic Beanstalk 에서 운영하고 있습니다. 멀티 컨테이너 기반으로 동작하고 있으며 Nginx, App(Moneta) 요청 처리를 위한 2개의 컨테이너와 Sidecar 패턴으로 로그 수집을 위해 Fluent Bit 컨테이너를 운영하고 있습니다.

모니터링 시스템: 모니터링 시스템은 Fluent-Bit 정보, App 서버 프로세스 정보를 수집하여 보여주고 이상 징후 발견 시 알림이 발생합니다. 자세한 정보는 이전 블로그를 참고하시면 됩니다.

로그 플랫폼: 로그를 수집 및 가공해서 BigQuery 및 Elastic Cloud 에 전송하는 플랫폼입니다. 자세한 정보는 이전 블로그를 참고하시면 됩니다.

Elastic APM: 여러 서비스 간의 Distributed Tracing(분산추적)을 통하여, 지연시간 및 요청 흐름에 대해 추적하기 위해 도입되었습니다. CNCF 프로젝트중 하나인 OpenTracing 와 Elastic APM 을 통하여 각기 다른 서비스간에 Context를 전파하여 분산추적이 가능하도록 구현되어 있습니다.

Circuit Breaker: 서킷브레이커는 장애 발생 시 빠르게 Fallback으로 전환하여 장애 전파를 막기 위한 패턴입니다. 주로 MSA 구조에서 많이 사용되고 있습니다. 현재 적용된 시스템에서는 HYSTRIX 라는 해당 패턴이 구현된 라이브러리를 Go로 포팅된 것을 이용하고 있습니다.

내부 API 서버: 내부적으로 이용되는 Private API를 제공합니다.

Redis: Redis 에서 재생 관련 정보를 저장하고 있으며, 내부 API 를 통하지 않고 최대한 빠르게 정보를 제공하기 위해서 이용하고 있습니다.

JWT: JWT(JSON WEB TOKEN)를 이용하여 클라이언트와 통신 하고 있습니다.

CI/CD: Elastic Beanstalk로 테스트와 배포는 CircleCI를 이용하고 있습니다. 특정 Git 브랜치에 커밋되면, 테스트케이스 통과 후 자동으로 배포되도록 운영하고 있습니다.

Golang: 동시성 처리 면에서 우수한 성능과 편리성을 제공하는 언어입니다. 개선된 시스템에서 APP 서버는 Golang을 이용하고 있습니다.

적용된 재생 관련 인프라 구조

적용된 재생 관련 인프라 전체 구조는 아래와 같습니다.

EB 기반의 인프라 구조, 클라이언트 통신 2부분으로 나눠서 설명하겠습니다.

적용된 시스템

EB 기반의 인프라 구조

새로 적용된 서비스는 Elastic Beanstalk With ECS (EB) 기반의 멀티 컨테이너를 이용하여 구축되어 있습니다. EB기반으로 구축하였을 때 장점으로는 다음과 같습니다.

AWS에서 제공하는 EB 전용 CLI 또는 콘솔에서 쉽게 설정, 배포가 가능합니다.

ALB 설정, Autoscale 설정, EC2 설정, Security 설정, 배포 설정 등 대부분 설정들이 코드로 관리 가능합니다.

EB With ECS 를 이용하게 되면 독립적인 환경에서 동작하는 Docker 이미지만 만들어 관리할 수 있어 안정적으로 운영 가능하여, ECS 클러스터, 모니터링 등 자동으로 알아서 처리하여 인프라에 신경 쓸 필요 없이 코드에만 집중이 가능합니다.

ECS 내의 Task별 Container 구조는 아래와 같습니다.

TASK 별 CONTAINER 구조

NGINX 해당 Container는 ALB 요청에 직접 응답 합니다. 물론 App 서버를 바로 ALB 요청에 직접 응답하도록 하면 성능적으로 장점이 있지만, NGINX를 통해 ALB요청을 처리하도록 하는것 또한 다음과 같은 장점이 있습니다.

불필요한 헤더 정리(불필요한 헤더 삭제 등)

보안(비정상적인 BODY 사이즈를 가진 요청을 거부, 허용되지 않은 PATH 거부)

APP 서버에서 굳이 처리할 필요 없는 것들을 손쉽게 처리 할수 있는 장점이 있어, Reverse Proxy 형태로 활용하고 있습니다.

APP Go로 만들어진 Server이며 영상 재생 관련된 요청을 처리 합니다. (내부적으로는 MONETA 라고 불리고 있습니다.) 들어온 요청에 대해 정상적인 요청인지를 확인후 서비스를 제공합니다. 해당 서버는 크게 안정성, 성능 부분에 맞춰 작업을 진행했습니다.

Moneta App 구조

안정성: APP 서버 내에서 요청이 발생하는 Redis 나 Private API 서버 장애발생 시에도 안정적인 서비스를 제공하기 위해서, 장애 발생 시에 서킷브레이커를 오픈하여 자동으로 Fallback 시나리오로 동작하도록 구현되어 있습니다. 장애상황에서 요청이 밀려 CPU 부하가 올라가고, 불필요한 Autoscale 이 발생하지 않도록 하여 장애 전파가 이뤄지지 않도록 되어 있습니다.

성능: 최대한 적은 서버 수로 많은 요청을 처리하기 위해서, 첫 번째로 외부 리소스 접근과 같이 Network I/O 병목이 적게 발생하도록 설계 및 구현되어 있습니다. 두 번째로 프로세스 메모리 최적화를 많이 하여 메모리 HEAP 할당을 최소화하는 등 GC 부하가 적어지도록 구현되어 있습니다. CONSUL 과 PROMETHEUS를 이용하여 스레드 및 고루틴 수, 메모리 HEAP 사이즈 … 등 프로세스 정보와 Circuit Breaker 또한 PROMETHEUS METRIC 이용하여 오픈 여부, 요청 수, 에러 수 … 등 정보 수집하여 알림 및 모니터링에 활용하고 있습니다. 그리고 OpenTracing 과 Elastic APM을 이용한 분산 추적을 통하여 클라이언트 요청 -> 응답 사이에 발생 하는 여러 내부 서비스 요청에 대해서 지연시간 및 요청 흐름을 추적하여 모니터링 및 서비스 개선에 활용되고 있습니다.

FLUENT BIT Sidecar 형태로 서비스에는 관련없지만 APP에서 발생한 로그를 수집하여 PROTOBUF 포맷으로 로그플랫폼에 전송합니다. 자세한 정보는 이전 블로그를 참고하시면 됩니다.

클라이언트 통신

MONETA 와 클라이언트 간의 요청은 JWT 를 이용해서 통신하고 있습니다.

클라이언트 서버 간 통신

JWT 를 이용하게 되면 서명을 통해 데이터 변조 및 무결성 체크도 가능하며, JWT 자체에 만료 시간을 정할 수도 있고, 필요한 메타정보를 담을 수 있습니다. 게다가 저장소(DB, CACHE ...등) 없이도 인증 처리를 할 수 있어서, 분산된 여러 서비스 간에 의존성 없이 인증 처리가 가능합니다. JWT 서명을 위한 KEY 값은 AWS SECRETS MANAGER를 통해 여러 서비스에 공유 되어 있어 안전하게 공유 가능합니다.

CI/CD 및 서버접속

CI/CD

테스트와 배포는 CIRCLE CI를 통하여 이뤄지고 있습니다. 특정 GIT 브랜치에 커밋하게 되면 테스트 케이스를 통과후 Docker Image를 만들어 태깅하여 ECR에 올리고 자동으로 배포되도록 구현되어 있습니다.

배포 정책은 ROLLING 방식, IMMUTABLE 방식, BLUE/GREEN 방식 등 다양하게 선택할 수 있는데, 현재는 IMMUTABLE 방식으로 배포를 하고 있습니다. 배포 방식에 대해서는 링크를 참조하시면 되겠습니다.

서버접속

서버 상태 확인 및 문제 발생 시 서버에 접속하기 위해서는 간단히 Elastic Beanstalk 전용 CLI 툴로 손쉽게 접근이 가능합니다.

EB에서도 기존의 서버를 접근하는 방식과 동일하게 SSH KEY를 이용해야 접속이 가능합니다. 하지만 접속 제한이 없고, 동일한 SSH KEY를 여러 사람한테 공유를 하게 되면 보안적으로 굉장히 취약합니다.

WATCHA에서는 내부적으로 SSH 인증서버 및 CLI 툴을 개발했습니다. AWS IAM 유저 권한 및 그룹을 체크해 유저 별로 시간 제한(1시간, 1일 …등)있는 서버에 접속 가능한 SSH KEY를 발급하고, 해당 시간이 지나면 발급된 SSH KEY는 자동 만료됩니다.

WATCHA SSH 인증서버

해당 SSH 인증 서버 및 CLI 은 다음 포스팅에서 자세히 설명을 해보도록 하겠습니다.

얼마나 개선 되었나?

Elastic Beanstalk With ECS(EB)에서 c5.large (VCPU 2 개, MEM 4GiB) 인스턴스를 사용하고 있으며 주말 피크 타임에 3대로 유지되고 있습니다.

그러나 기존 API 서버 c5.xlarge(VCPU 4개, MEM 8GiB) 인스턴스는 7대 정도 줄어들도록 개선되었습니다.

개선

결론

재생 관련 서비스를 MSA구조로 만든 과정에 이용한 기술에 대해 공유해 보았습니다.

MSA구조로 분리되면서, 메인 API 서버는 잦은 배포에도 안정적으로 운영이 가능해졌습니다.

영상 재생 관련된 모든 API가 새로 구축된 시스템으로 마이그레이션 된 건 아니지만, 일부 API만 마이그레이션 하여도 많은 성능 향상이 있는 것을 볼 수 있었습니다.

그리고 지속적으로 일부 남아 있는 API도 새로 구축된 시스템으로 마이그레이션 하게 되면 성능은 물론 안정성도 높아질 것으로 예상합니다.

여기서 못다 한 SSH 인증서버는 다음 포스팅에서 다루도록 하겠습니다.

WATCHA에서는 다양한 기술들을 활용해 서비스를 지속적으로 개선, 발전시켜 갈 실력 있고 뜻있는 개발자들을 모집하고 있습니다. 관심있는 분은 채용공고를 참고해주세요.

긴 글 읽어 주셔서 감사합니다.

기업문화 엿볼 때, 더팀스

로그인

/