Education/신한투자증권 프로 디지털 아카데미

MSA 아키텍처 설계해보기🔧

마이캣호두 2025. 10. 11. 22:56
반응형

 

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


 

 

 

0.  MSA vs 모놀리식

아키텍처 설계를 시작할 때, "하나의 서버에 모든 기능을 담을 것인가, 아니면 역할을 분리할 것인가?" 에 대한 고민을 하게 된다.
그래서 먼저 모놀리식 아키텍처와 MSA의 차이에 대해 알아보고자 했다.

 

 

1.  두 아키텍처의 기본 개념

모놀리식 (Monolithic Architecture)

  • 모든 기능이 하나의 서버 안에서 통합적으로 실행하는 구조
  • 예시: 하나의 스프링 부트 프로젝트 안에 모든 API와 로직이 들어 있음
  • 특징: 단일 빌드, 단일 배포, 단일 DB 구조

MSA(Microservice Architecture)

  • 기능 단위를 서로 다른 독립 서비스(모듈) 로 나누고, 각 서비스는 API로 통신하며 동작하는 구조
  • 예시: user-service, strategy-service, execution-service가 각각 독립적으로 동작
  • 특징: 서비스 간 통신(API, 메시지 큐 등), 개별 배포, 다양한 기술 스택 조합 가능

 

2.  각 설계의 장단점 비교

모놀리식 (Monolithic Architecture)

  • 장점
    • 개발·배포가 단순하고 구조가 직관적
    • 인프라, 인력 비용이 적게 듦
    • 초기 개발 속도가 빠름
  •  단점
    • 장애 전이 가능성 (하나의 오류로 전체 중단)
    • 단일 서버 배포 방식으로 이루어져있기 때문에 서비스 규모가 커질수록 배포에 시간이 많이 걸림
    • 코드 의존성 복잡해짐

 

MSA(Microservice Architecture)

  • 장점
    • 장애가 서비스 단위로 격리되어 전체 다운 방지
    • 서비스별 단일 배포 가능
    • 빌드·테스트·배포 속도 향상
    • 각 팀이 독립적으로 개발 가능
    • 다양한 기술 스택 사용 가능
  • 단점
    • 관리 복잡도와 운영 비용 증가
    • 통신 오버헤드(API 호출, 메시지 큐 등)
    • 모니터링, 로깅, 보안 관리 난이도 상승

 

3.  우리 팀에 더 잘 어울리는 설계는 무엇일까?

우리 팀의 서비스는 '블록을 조합하여 사용자가 손쉽게 전략을 생성하고 실행할 수 있는 자동감시주문 서비스'로

  • 실시간으로 시세를 받아와서 지표를 계산해야 하고,
  • 기능별로 역할이 명확하게 분리되어 있으며,
  • 장기적으로 확장성과 유지보수성이 중요한 프로젝트

물론, 모놀리식으로도 충분히 설계가 가능하지만

  • 자동매매/데이터 수집형 시스템으로서
  • Java의 안정성이 높고 확장성이 좋다는 장점과
  • Python(FastAPI)의 데이터 수집, 보조 지표 연산에 특화된 장점을 모두 가져가고자 했음

이런 특성상 MSA가 더 적합한 구조라고 생각했다.

  • 데이터 수집, 전략 생성, 전략 실행, 주문 체결 모듈 등이 서로 다른 주기와 리소스 요구사항을 가지기 때문에 분리 운영이 유리함
  • 장애 발생 시 한 모듈만 재시작하거나 교체할 수 있어 서비스 전체 중단 위험이 적음
  • Kafka, Redis, 다양한 언어 스택(Java, Python) 등을 병행할 때 기술 선택의 유연성을 가질 수 있음

→ 모놀리식이 단기적으론 단순하고 빠르지만, 장애 격리·독립 배포·팀 단위 협업·장기적 확장성을 고려했을 때 MSA가 더 적합하다고 판단했다!

 

 

 

1.  아키텍처 소개

모듈을 통합해서 응집도를 높여봅시다!

 

 

 

초기 설계 단계에서는 각 모듈을 '기능 + 요구되는 리소스'별로 분리하고자 했다.

  • 공통 모듈 은 인증/인가, API 라우팅 등 외부와 맞닿은 보안 경계
  • 정보 수집 모듈 은 데이터 수집 파이프라인으로 데이터 수집과 지표 계산을 수행하여 Kafka에 게시
  • 전략 관리(생성) 은 json으로 정의된 전략을 생성하여 MongoDB에 저장
  • 전략 실행 은 실행되는 전략을 pod로 띄우고 컨슈머로서 해당 토픽을 구독해 실행
  • 주문/체결 은 전략 시그널 정보를 받아서 한국투자증권 api로 주문을 전송하고 체결 이벤트를 수신

 

1.  전략 관리 + 전략 실행 모듈을 통합하다

전략 관리 모듈과 전략 실행 모듈을 분리했었지만, 개발 과정에서 두 모듈이 항상 같은 데이터를 사용하고 같은 DB를 공유한다는 것을 깨달았다. MSA의 원칙에 따라 같이 변하는 것은 같이 둬야 한다고 생각해서 하나의 모듈로 통합하여, 현재 우리 팀의 아키텍처는 아래의 그림처럼 변경되었다. 짜잔!✨

 

 

 

2.  고민했던 POINT

1)  1전략 1파드 vs 1전략 N파드

  • 1전략 1파드 : 하나의 투자 전략에 1개의 파드를 할당
    • 전략 간 완전 격리로 높은 안정성이 보장되고 구현이 간단
    • 100개의 전략을 실행하려면 100개의 파드가 필요하기 때문에 관리를 위한 운영 비용이 증가
  • 1전략 N파드 : N개의 투자 전략에 1개의 파드를 할당
    • 하게 되면 더 많은 사용자를 수용 가능
    • 전략별 시작/중지/업데이트 시 파드를 재시작해야 해서 라이프사이클 관리가 복잡해짐

→ 파드는 오류가 발생하면 자동으로 재실행하게 되므로 1파드 N전략을 적용할 경우, 1개의 전략에서 에러가 발생해도 오류가 발생하지 않은 전략들도 실행 상태가 종료된다는 문제가 있었다. 그래서 1파드 1전략을 채택하여 개발 진행 중에 있다.

 

 

2)  Kafka 로 실시간 시세 발행

자동주문감시는 틱 단위로 내려오는 시세를 받아서 전략을 실행하고 곧바로 매매로 이어지기 때문에 실시간 시스템에 가깝다. 우리 서비스에서는 이 데이터들을 모든 전략 파드에 동시에 전달해야 하기 때문에 Kafka를 선택했다.

 

정보수집 모듈에서 한국투자증권 API에서 시세 데이터를 수집한 뒤, 실시간으로 보조 지표를 계산해서 Kafka에 발행한다. 토픽은 stockCode.timeframes 형태로 설계되어, 각 전략 파드는 자신에게 필요한 토픽만 consume한다. 즉, 동일한 시세 데이터가 여러 전략 파드에 동시에 전달되어도, 각 파드는 독립적인 컨슈머로 동작하므로 서로 간섭 없이 동일한 데이터를 각자의 전략 로직에 따라 처리할 수 있다.

 

또한, Kafka의 2~3ms의 낮은 지연이라는 특징은, 실시간성이 중요한 우리 서비스 환경에서 즉각적인 데이터 처리를 가능하게 하고 있다. 결과적으로, Kafka는 정보 수집 → 지표 계산 → 전략 실행이라는 실시간 데이터 파이프라인으로서 전략의 안정적 실행을 뒷받침해주고 있다.

 

 

3)  Redis 에 캐싱해두기

한국투자증권 API의 웹소켓을 통해 틱 단위의 실시간 시세 데이터를 받아오고 있다. 들어오는 데이터는 초 단위로 갱신되며, 이를 내부에서 분봉과 일봉 단위로 계산한다. 이렇게 생성된 봉 데이터를 기반으로 RSI, MACD, 이동평균선, 볼린저 밴드 등의 보조 지표를 실시간으로 계산하고, 계산된 결과는 곧바로 Redis에 캐싱된다.

 

Redis에 저장된 데이터는 프론트엔드와 전략 실행 모듈이 지연 없이 최신 시세와 지표를 조회할 수 있도록 하며, DB 쿼리나 재계산 과정을 거치지 않아도 되기 때문에 응답 속도가 매우 빠르다. 이 구조 덕분에 실시간으로 수집된 시세 데이터가 곧바로 전략 판단과 매매 트리거로 이어질 수 있고, 서비스 전체가 밀리초 단위로 반응하는 실시간 환경을 유지할 수 있다.

 

 

4)  Kubernetes 사용하기

사용자가 설정한 투자 전략을 하나의 파드로 실행하게 되는데, 이를 안정적으로 운영하기 위해 Kubernetes를 선택했다. 자동매매 시스템은 실시간으로 시세를 감지하고 즉시 매매를 수행해야 하므로, 단 한 번의 장애나 지연도 곧바로 손실로 이어질 수 있다. 따라서, 서비스의 기본 전제는 고가용성과 자동 복구였다.

 

쿠버네티스는 이러한 요구에 완벽히 부합한다. 각 전략은 독립된 파드로 실행되어 다른 전략과 완전히 분리된 환경에서 동작한다. 즉, 하나의 전략이 오류로 종료되더라도 다른 전략에는 아무런 영향을 주지 않으며, 쿠버네티스의 셀프 힐링(Self-Healing) 기능을 통해 비정상 파드를 자동으로 재시작해 즉시 복구할 수 있다. 이런 구조는 '한 전략의 실패가 전체 시스템의 장애로 이어지지 않는다'는 안정성을 보장한다.

 

또한, 쿠버네티스의 오토스케일링 기능을 통해 사용자가 전략을 추가 실행하면 필요한 만큼의 파드가 자동으로 생성되고, 전략이 종료되면 자원이 즉시 회수된다. 덕분에 인프라 비용을 최소화하면서도 서비스의 유연성과 확장성을 모두 확보할 수 있었다.

 

 

5)  전략 JSON 을 MongoDB 에 저장하기

사용자가 생성한 투자 전략을 JSON 형태로 저장하고 있으며, 이를 관리하기 위한 데이터베이스로 MongoDB를 사용하고 있다. 전략은 다양한 조건 블록들이 계층적으로 연결된 트리 구조 형태를 띄는데, 사용자가 만든 전략은 모두 서로 다른 구조를 가질 수 있으며, 필드 개수나 중첩 깊이도 일정하지 않다.

 

이러한 비정형 데이터는 스키마가 고정된 관계형 데이터베이스(RDB)로 관리하기 어렵다. RDB에 저장하려면 JSON을 여러 테이블로 쪼개고 조인해야 하는데, 이는 쿼리 복잡도와 연산 비용을 급격히 높인다. 반면, MongoDB는 스키마가 자유로운 문서 기반 DB이기 때문에 전략을 하나의 문서로 그대로 저장하고 버전 관리나 조회를 훨씬 간단히 수행할 수 있다.

 

MongoDB를 사용함으로써 우리는 사용자 맞춤형 전략을 손실 없이 저장하고, 구조 변경이 필요한 경우에도 유연하게 대응할 수 있는 환경을 구축할 수 있었다. 또한, 전략의 버전 정보나 실행 상태 등 메타데이터를 함께 저장하여, 각 사용자의 전략을 빠르게 불러오고 수정할 수 있도록 했다.

 

결과적으로, MongoDB는 전략 관리의 핵심 스토리지로서 다양한 전략 구조를 그대로 유지하면서도 높은 유연성과 확장성을 제공하고 있으며, 실시간 자동매매 시스템의 동적 로직 관리에 최적화된 데이터베이스로 기능하고 있다.

반응형