[신한투자증권]도메인 기반 MSA 설계와 무중단 배포 전략으로 구축한 SOL-ASSIST 프로젝트

조정현·2025년 10월 9일

증권프로젝트

목록 보기
8/8

프로젝트 설계 with MSA
이 글은 알파코에서 진행되는 [신한투자증권] 프로디지털아카데미 과정 중, 김송아 강사님과 함께하는 '파이널 프로젝트'를 기반으로 작성되었습니다.

프로젝트 개요

우리 프로젝트 초보자 어시스트 대시보드는 초보 투자자를 위한 맞춤형 서비스를 제공하여 신규 사용자 유입을 증가시키는 것을 목표로 구축했다. 증권 애플리케이션의 특성상 한 번 사용자가 유입되면 서비스 내 활동이 계속되므로, 안정적이고 확장 가능한 시스템 설계가 필수적이다. 이를 위해 마이크로서비스 아키텍처(MSA) 를 적용하여 확장성과 내결함성을 확보했다.

  • Public EC2
    • Bastion 호스트
    • Nginx API Gateway
    • Next.js 프론트엔드 서버
  • Private EC2(internal-service)
    • 매매기록 기반, 개인화 서비스
  • Private EC2(external-service)
    • 뉴스, 차트 등 외부 서비스
  • Private EC2(insight-service)
    • 차트 분석, 차트기반 매매기록 생성 서비스
  • Private EC2(Kafka)
    • 비동기 기반 이벤트 메시징 처리
  • Private RDS Master 1대
    • Slave 2대

설계 이유

  1. 동기적 통신 최소화: 서비스별 독립 서버 구성으로 서로 다른 서비스 간 동기적 호출을 줄이고, 확장성과 안정성을 확보했다.
  2. 보안 강화: 증권 서비스 특성상 민감한 데이터 보호가 필수적이므로, 민감한 서비스들은 모두 private subnet에 위치시켰다.
  3. 무중단 배포: MSA 환경에서는 배포 빈도가 상대적으로 높아, 중단이 반복되면 사용자 경험에 큰 악영향을 미친다. 그렇기에 운영 중에도 사용자의 경험이 끊기지 않도록 MSA 환경에서 무중단 배포 전략을 적용했다.
  4. 깃허브 전략: 각 서비스의 메인 브랜치를 두어, 해당 브랜치로 push되는 경우에 무중단 배포가 이루어지도록 구성했다. MSA의 경우 각 서비스 별로 팀 단위로 붙어서 개발을 하는 경우가 많기에 이를 생각하여 구상했다.

설계에 관하여

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

서비스 모듈 분리

아키텍처는 도메인별 모듈 분리를 기본 원칙으로 한다. MSA에서는 비즈니스 도메인에 따라 경계 지어진 컨텍스트를 정의하고 서비스를 설계하는 것이 권장된다. 이를 바탕으로 다음과 같이 네 가지 모듈을 구성했다.

  • internal-assistant-service: 내부 매매기록 기반 서비스로, 사용자의 거래 내역과 개인에 대한 서비스를 구성했다. 여기에는 로그인/로그아웃/사용자 정보 조회 같은 인증 기능과, 대시보드 내 보유 종목 조회, 멤버 리포트(성향, 평균보유기간, 매매수익, 자산, 월별 거래기록 등) 관련 API가 포함된다. 개인화된 거래 통계를 제공하고, 내부 데이터에 기반한 인사이트를 산출한다.
    또한 고수 종목 거래량/조회 단위와 같은 작업을 수행한다.
  • external-assistant-service: 외부 데이터 연동 서비스로, 뉴스와 차트를 통한 투자 정보를 담당한다. 뉴스 내 섹터 조회, 내 섹터 관련 뉴스 리스트, 뉴스 배치 생성 등이 이 서비스의 주요 기능이다.
    여기에는 차트 데일리/분봉 조회, 호가 조회, 고수 거래량·보유율, 재무 신호등, 위험 종목 체크 등의 기능이 포함되며, 매수/매도 주문 API도 이 모듈이 담당한다. 외부 API와 배치 작업을 처리하여 내부 시스템에 필요한 데이터 피드를 제공한다.
  • chart-similarity-service: 신호 분석 서비스이다. 과거 차트 데이터를 조회하고, 유사 차트 분석을 수행한다. 유사 차트 기능에서 사용자의 보유 종목과 비보유 종목에 대한 매수/매도 신호를 계산한다.
  • common-service: 공통 모듈로, 구성 설정과 멤버 도메인을 포함한다. 이 모듈에는 전체 서비스에서 공유하는 설정파일과 회원 인증/인가, 사용자 토큰 등의 로직이 담긴다. 예를 들어 로그인 정보 및 사용자 성향 정보는 이 공통 모듈의 도메인에서 처리되어, 내부/외부 서비스와 차트 서비스에서 재사용한다.
    • 공통 모듈의 경우 수정을 최소화한다. 공통모듈이 커질 경우 복잡성이 증가하고, 배포 전략상 3개의 마이크로 서비스의 재배포가 이루어짐으로서 많은 비용이 발생한다.

이처럼 서비스를 도메인별로 분리함으로써 각 팀은 자신이 맡은 비즈니스 로직에 집중할 수 있어 관리 효율이 높아진다. 또한 서로 다른 서비스가 독립적으로 배포되므로, 한 서비스에 문제가 생겨도 전체 시스템 다운으로 이어지지 않는 장애 격리 효과를 누릴 수 있다. 각 서비스는 독립되므로, 특정 영역을 수정하거나 확장할 때 전체 시스템 영향 없이 빠르게 대응할 수 있다.

CI/CD 및 배포 전략

개발 효율성과 안정성을 위해 서비스별 CI/CD 파이프라인을 구축했다. GitHub 리포지토리에서 메인 브랜치 외에 각 서비스 이름의 브랜치를 운영하며, 브랜치로 코드가 커밋되면 해당 서비스에 대한 무중단 배포가 자동으로 수행된다. 구체적으로:

  • 각 서비스 독립 배포: 서비스별 브랜치가 머지되면 CI/CD 파이프라인이 실행되어 해당 서비스만 빌드·테스트 후 배포한다. 이를 통해 독립적인 배포 주기를 보장하고, 한 서비스의 배포나 롤백이 다른 서비스에 영향을 주지 않는다. 예를 들어 Internal 서비스에 신규 기능이 추가되었을 때 Internal 서비스만 배포하고, 다른 서비스는 그대로 유지할 수 있다. 이러한 독립 배포 구조는 “한 서비스의 버그가 전체 릴리즈를 막는” 리스크를 줄여준다.
  • 공통 모듈 업데이트: Common 서비스(공통 설정 또는 멤버 도메인)에 변경사항이 생기면, 관련 종속성이 있는 세 서비스 모두를 대상으로 재배포하도록 구성했다. 즉, 공통 라이브러리를 업데이트하면 Internal/External/Chart 서비스에도 신규 이미지를 적용하여 배포가 되어야 한다. 이를 통해 공통 기능 변경이 개별 서비스에 안정적으로 반영되도록 하고, 버전 호환성 문제를 방지한다.
  • 무중단 배포: Blue-Green 배포 전략을 활용해 서비스 가용성을 유지한다. 예를 들어 프로덕션 인스턴스를 새 버전과 병렬로 띄운 뒤 트래픽을 전환하여, 배포 중에도 기존 버전이 서비스될 수 있도록 했다. 이렇게 하면 새 버전에 문제가 생겨도 즉시 이전 환경으로 롤백할 수 있어 사용자 영향이 최소화된다.

이러한 CI/CD 자동화는 배포 속도와 신뢰도를 높여준다. 자동화된 파이프라인 덕분에 새로운 기능이나 버그 패치 배포가 빠르고 안전해졌으며, 매일 또는 수시로 여러 번 배포할 수 있는 유연성을 지켰다.

데이터베이스 및 메시징

데이터 관리는 RDS 기반의 관계형 DB와 Redis를 통해 수행한다. RDS는 마스터-슬레이브 구조로 구성하여 쓰기와 읽기를 분리한다. 쓰기 부하가 큰 트랜잭션은 마스터 인스턴스에서 처리하고, 복제된 슬레이브 인스턴스는 읽기 전용 쿼리를 소화하여 데이터베이스 병목을 줄인다. 또한 멀티 AZ 환경에서는 동기식 복제가 이루어져 장애 조치 시 자동 페일오버를 지원한다. 예를 들어 마스터에 장애가 발생하면 AWS가 보조 AZ의 인스턴스를 새 마스터로 승격하여 다운타임을 최소화한다.
Kafka는 서비스 간 이벤트 기반 통신에 사용된다. 내부/외부/차트 각 서비스는 서로 독립적이지만, 서로에게 영향을 줄 수 있는 이벤트(예: 새로운 뉴스 업데이트, 행동기반 데이터, 매매 고수 리스트 등)를 Kafka 토픽에 발행하고 구독함으로써 느슨하게 연결된다. 메시징 큐를 사용하면 서비스 간 직접 호출을 줄여 장애 전파를 막고, 필요에 따라 메시지를 재처리할 수 있어 내결함성이 높아진다.

주요 API 및 기능 개요

서비스별로 주요 기능과 API를 간략히 정리:

  • Internal 서비스 APIs:
    • 인증/회원관리: 로그인 및 사용자 정보 조회 API. (common-service가 공통 처리)
      • POST /api/v1/internal/member/login
      • GET /api/v1/internal/member/logout
        ...
    • 대시보드 데이터:
      • GET /api/v1/internal/member/trade/my-stock (보유 종목 조회)
      • GET /api/v1/internal/member/trade/type (내 성향)
        ...
    • 고수 추출
      • /api/v1/internal/expert/short
      • /api/v1/internal/expert/midium
  • External 서비스 APIs:
    • 시장 데이터:
      • 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/daily
      • GET /api/v1/insight/chart/minute
    • 주문 처리: POST /api/v1/insight/trade/buy, POST /api/v1/insight/trade/sell (매매 주문) 등을 통해 거래 일부 처리
  • Chart 서비스 APIs:
    • 유사 차트 분석:
      • GET /api/v1/insight/chart-similarity/my-stock?:{UUID} (내 보유 종목 유사 차트 신호)
      • GET /api/v1/insight/chart-similarity/unowned (미보유 종목 유사 차트 신호)
        ...

API Gateway (Nginx) 역할 상세 설명

클라이언트 요청은 Public EC2에 위치한 Nginx 기반 API Gateway를 통해 들어온다. 이 Gateway는 단일 진입점 역할을 하면서, 도메인 또는 URL 경로 기반 라우팅을 통해 내부 MSA 서비스로 요청을 전달한다.

  1. 경로/도메인 기반 라우팅
  • /api/v1/internal/... → Internal 서비스
  • /api/v1/external/... → External 서비스
  • /api/v1/insight/... → Insight 서비스
    이 방식 덕분에 클라이언트는 단일 도메인만 사용하면서, 내부적으로 서비스별 서버가 요청을 처리하도록 분리할 수 있다.
  1. 무중단 배포 환경 지원
    서비스가 Blue-Green 배포 방식으로 무중단 배포될 때, Nginx는 다음과 같이 동작한다.
  • 동시 실행 포트: 각 서비스 각 서버에 8081, 8082 등 두 개의 포트에서 실행된다. Nginx에서 이 2개의 포트 중 하나 씩 라우팅해야 한다.

  • 로드 스위칭: 새로운 버전 배포 시, 현재 운영 중인 포트(예: 8081) 외에 다른 포트(예: 8082)에 새 버전을 시작한다.
    Nginx는 요청을 번갈아 가며 두 포트로 라우팅하거나, 새 버전 포트로 완전히 전환한다. 테스트 후 문제가 없으면 이전 포트를 종료하고, 새 포트가 운영된다.

장애 격리와 내결함성

MSA의 핵심 장점 중 하나는 장애 격리다. 각 서비스가 분리되어 있으므로 한 서비스가 실패해도 다른 서비스는 계속 동작할 수 있다. 예를 들어, Chart 서비스에 장애가 발생해도 Internal/External 서비스는 계속 사용자 요청을 처리할 수 있다. 또한 Kafka와 비동기 메시징 덕분에 서비스 간 동기 호출을 최소화하여, 네트워크 지연이나 한쪽 장애가 전체 시스템을 마비시키는 리스크를 줄였다.

서비스 배포 또한 가용성을 고려하여 설계했다. 앞서 언급한 무중단 배포(Blue-Green) 전략을 통해 서비스 가용성을 확보하고, 장애 조치 시 자동 롤백으로 다운타임 없이 시스템을 유지한다. 결과적으로, 독립적인 CI/CD 파이프라인무중단 배포를 조합하여 운영 중에도 지속적인 서비스 개선이 가능해졌으며, 시스템 전반의 복원력을 강화했다.

회고 및 향후 과제

이번 설계를 통해 얻은 교훈은 MSA의 장점을 살리기 위한 올바른 분할과 자동화가 중요하다는 점이다. 서비스를 도메인별로 분리하면 각 팀이 전문성 있게 개발할 수 있고, 문제 발생 시 영향 범위를 좁힐 수 있다. 또한 서비스별 CI/CD 파이프라인과 무중단 배포는 빈번한 릴리즈와 높은 가용성을 보장해 주었다.

향후 개선점으로는, 데이터베이스를 서비스별로 분리하거나 k8s같은 컨테이너 오케스트레이션 도입을 고려할 수 있다. 이번 설계를 바탕으로, 서비스 간 결합도를 더욱 낮추고 확장 가능성을 최대한 활용함으로써 사용자 경험과 시스템 안정성, 그리고 팀단위 개발 환경을 동시에 높였다.

2개의 댓글

comment-user-thumbnail
2025년 10월 10일
  • ̗̀ෆ⎛˶'ᵕ'˶ ⎞ෆ ̖́-
답글 달기
comment-user-thumbnail
2025년 10월 11일

5959~

답글 달기