프로젝트 설계 with MSA
이 글은 알파코에서 진행되는 [신한투자증권] 프로디지털아카데미 과정 중, 김송아 강사님과 함께하는 '파이널 프로젝트'를 기반으로 작성되었습니다.
우리 프로젝트 초보자 어시스트 대시보드는 초보 투자자를 위한 맞춤형 서비스를 제공하여 신규 사용자 유입을 증가시키는 것을 목표로 구축했다. 증권 애플리케이션의 특성상 한 번 사용자가 유입되면 서비스 내 활동이 계속되므로, 안정적이고 확장 가능한 시스템 설계가 필수적이다. 이를 위해 마이크로서비스 아키텍처(MSA) 를 적용하여 확장성과 내결함성을 확보했다.

모듈간의 통신을 최소화하기 위해서 모듈을 열심히 나누었다. 클라우드 김경훈 강사님이 항상 이야기하시던 MSA의 핵심은 bonded context와 느슨한 결합이었다. 즉, 각 서비스는 자신의 도메인 내에서만 책임을 가지고 동작하며, 다른 서비스의 내부 로직이나 데이터 구조에 직접 의존하지 않아야 했다. 이를 위해서 서비스간 통신을 최소화하여 Kafka 이벤트를 통한 비동기 통신 구조를 이루어야 했다. 이러한 구조를 통해 서비스 간 결합도를 낮추고, 장애 전파를 방지하며, 서비스별 독립 배포와 확장성을 확보할 수 있었다.
아키텍처는 도메인별 모듈 분리를 기본 원칙으로 한다. MSA에서는 비즈니스 도메인에 따라 경계 지어진 컨텍스트를 정의하고 서비스를 설계하는 것이 권장된다. 이를 바탕으로 다음과 같이 네 가지 모듈을 구성했다.

이처럼 서비스를 도메인별로 분리함으로써 각 팀은 자신이 맡은 비즈니스 로직에 집중할 수 있어 관리 효율이 높아진다. 또한 서로 다른 서비스가 독립적으로 배포되므로, 한 서비스에 문제가 생겨도 전체 시스템 다운으로 이어지지 않는 장애 격리 효과를 누릴 수 있다. 각 서비스는 독립되므로, 특정 영역을 수정하거나 확장할 때 전체 시스템 영향 없이 빠르게 대응할 수 있다.
개발 효율성과 안정성을 위해 서비스별 CI/CD 파이프라인을 구축했다. GitHub 리포지토리에서 메인 브랜치 외에 각 서비스 이름의 브랜치를 운영하며, 브랜치로 코드가 커밋되면 해당 서비스에 대한 무중단 배포가 자동으로 수행된다. 구체적으로:
이러한 CI/CD 자동화는 배포 속도와 신뢰도를 높여준다. 자동화된 파이프라인 덕분에 새로운 기능이나 버그 패치 배포가 빠르고 안전해졌으며, 매일 또는 수시로 여러 번 배포할 수 있는 유연성을 지켰다.

데이터 관리는 RDS 기반의 관계형 DB와 Redis를 통해 수행한다. RDS는 마스터-슬레이브 구조로 구성하여 쓰기와 읽기를 분리한다. 쓰기 부하가 큰 트랜잭션은 마스터 인스턴스에서 처리하고, 복제된 슬레이브 인스턴스는 읽기 전용 쿼리를 소화하여 데이터베이스 병목을 줄인다. 또한 멀티 AZ 환경에서는 동기식 복제가 이루어져 장애 조치 시 자동 페일오버를 지원한다. 예를 들어 마스터에 장애가 발생하면 AWS가 보조 AZ의 인스턴스를 새 마스터로 승격하여 다운타임을 최소화한다.
Kafka는 서비스 간 이벤트 기반 통신에 사용된다. 내부/외부/차트 각 서비스는 서로 독립적이지만, 서로에게 영향을 줄 수 있는 이벤트(예: 새로운 뉴스 업데이트, 행동기반 데이터, 매매 고수 리스트 등)를 Kafka 토픽에 발행하고 구독함으로써 느슨하게 연결된다. 메시징 큐를 사용하면 서비스 간 직접 호출을 줄여 장애 전파를 막고, 필요에 따라 메시지를 재처리할 수 있어 내결함성이 높아진다.
서비스별로 주요 기능과 API를 간략히 정리:
POST /api/v1/internal/member/loginGET /api/v1/internal/member/logoutGET /api/v1/internal/member/trade/my-stock (보유 종목 조회)GET /api/v1/internal/member/trade/type (내 성향)/api/v1/internal/expert/short/api/v1/internal/expert/midium GET /api/v1/external/news/my-sector (뉴스 내 섹터 조회)GET /api/v1/external/news/my-sector/news-info (내 보유 섹터 정보 조회)POST /api/v1/external/news (뉴스 배치 생성)GET /api/v1/insight/chart/dailyGET /api/v1/insight/chart/minutePOST /api/v1/insight/trade/buy, POST /api/v1/insight/trade/sell (매매 주문) 등을 통해 거래 일부 처리GET /api/v1/insight/chart-similarity/my-stock?:{UUID} (내 보유 종목 유사 차트 신호)GET /api/v1/insight/chart-similarity/unowned (미보유 종목 유사 차트 신호)클라이언트 요청은 Public EC2에 위치한 Nginx 기반 API Gateway를 통해 들어온다. 이 Gateway는 단일 진입점 역할을 하면서, 도메인 또는 URL 경로 기반 라우팅을 통해 내부 MSA 서비스로 요청을 전달한다.

/api/v1/internal/... → Internal 서비스/api/v1/external/... → External 서비스/api/v1/insight/... → Insight 서비스동시 실행 포트: 각 서비스 각 서버에 8081, 8082 등 두 개의 포트에서 실행된다. Nginx에서 이 2개의 포트 중 하나 씩 라우팅해야 한다.
로드 스위칭: 새로운 버전 배포 시, 현재 운영 중인 포트(예: 8081) 외에 다른 포트(예: 8082)에 새 버전을 시작한다.
Nginx는 요청을 번갈아 가며 두 포트로 라우팅하거나, 새 버전 포트로 완전히 전환한다. 테스트 후 문제가 없으면 이전 포트를 종료하고, 새 포트가 운영된다.
MSA의 핵심 장점 중 하나는 장애 격리다. 각 서비스가 분리되어 있으므로 한 서비스가 실패해도 다른 서비스는 계속 동작할 수 있다. 예를 들어, Chart 서비스에 장애가 발생해도 Internal/External 서비스는 계속 사용자 요청을 처리할 수 있다. 또한 Kafka와 비동기 메시징 덕분에 서비스 간 동기 호출을 최소화하여, 네트워크 지연이나 한쪽 장애가 전체 시스템을 마비시키는 리스크를 줄였다.
서비스 배포 또한 가용성을 고려하여 설계했다. 앞서 언급한 무중단 배포(Blue-Green) 전략을 통해 서비스 가용성을 확보하고, 장애 조치 시 자동 롤백으로 다운타임 없이 시스템을 유지한다. 결과적으로, 독립적인 CI/CD 파이프라인과 무중단 배포를 조합하여 운영 중에도 지속적인 서비스 개선이 가능해졌으며, 시스템 전반의 복원력을 강화했다.
이번 설계를 통해 얻은 교훈은 MSA의 장점을 살리기 위한 올바른 분할과 자동화가 중요하다는 점이다. 서비스를 도메인별로 분리하면 각 팀이 전문성 있게 개발할 수 있고, 문제 발생 시 영향 범위를 좁힐 수 있다. 또한 서비스별 CI/CD 파이프라인과 무중단 배포는 빈번한 릴리즈와 높은 가용성을 보장해 주었다.
향후 개선점으로는, 데이터베이스를 서비스별로 분리하거나 k8s같은 컨테이너 오케스트레이션 도입을 고려할 수 있다. 이번 설계를 바탕으로, 서비스 간 결합도를 더욱 낮추고 확장 가능성을 최대한 활용함으로써 사용자 경험과 시스템 안정성, 그리고 팀단위 개발 환경을 동시에 높였다.
