Cloud

[Cloud] 마이크로서비스 아키텍처(MSA)란?

yongyongcoding 2026. 1. 7. 18:45

이번 주제는 MSA 아키텍처이다.

MSA에 대해 제대로 공부해보며, 과거에 MSA구조로 진행했었던 프로젝트에 많은 부족함이 있었다는 걸 알게되었다.

이번에는 MSA나 Monolitic 구조의 차이와 기본적인 개념 보다,

MSA의 개발원칙과 CRUD와 MSA의 관계성에 대해서 알아보려고한다.

 

 

MSA 개발 원칙( 12 Factors ) 

1. 코드 베이스 

 

  • 버전 관리가 가능한 하나의 코드베이스와 이를 통한 다양한 배포
  • 버전관리는 개발과 운영이 동일해야한다
  • Cloud Native인 경우 엄청나게 많은 Pod가 존재하기 때문에 이전의 버전을 확인하기 어렵기 때문에 버전 관리 필수
  • 정리: Git과 같은 버전 관리 시스템을 이용해 관리해야한다는 의미이다.

 

2.  종속성 

  • 명시적으로 선언되고 분리 된 종속성
  • 항상 재현이 가능한 빌드를 사용해야한다 (사람이 바뀌더라도 유지되어야한다)
  • 정리: 라이브러리나 도구는 모두 명시적으로 선언해 누구나 같은 환경에서 동일한 결과를 빌드할 수 있어야한다는 의미이다.

 

3. 설정

  • 환경에 저장된 설정의 이용 
  • 배포마다 달라질 수 있는 모든 것을 의미하며 소스에 상수로 저장하지 않고 반드리 분리해 관리해야한다.
    (S3, 리소스 핸들러, Database , 외부 인증 정보 등)
  • 정리: DB 주소나 비밀키 같은 설정값은 코드에 넣지 말고 환경 변수로 관리해 환경 변경 시 코드 수정이 필요 없게 한다.

 

 

4. 백엔드 서비스

  • 교체가능한 리소스는 백엔드로 넣어야한다
  • 쉽게 교체가능하게 되면 pod로 올리지 말고 백엔드에 연결해서 변경에 pod에 영향이 가지 않도록
  • 정리: 외부 리소스는 언제든 교체 가능하다고 가정하고 애플리케이션과 느슨하게 연결해야 한다.
    (DB/캐시/메시지큐/메일 같은 것은 교체 가능한 리소스로 취급하여 변경 최소화)

 

5. 빌드, 릴리즈 ,실행

  • 철저하게 분리된 빌드와 실행 단계
  • 코드베이스는 3단계를 거쳐 배포로 변환.
    1. 빌드 단계는 코드 저장소를 빌드라는 실행가능한 번들로 변환
    2. 릴리즈는 빌드 단계에서 만들어진 빌드와 배포의 현재 설정을 결합
    3. 실행에서는 선택된 릴리즈에 대한 애플리케이션 프로세스의 집합을 시작하여 실행
  • harbor를 쓰는 이유. 변경 추적, 재사용성 등.
  • 정리: 빌드, 릴리즈, 실제 실행 단계를 분리해 이미지 변경 이력과 재배포를 안전하게 관리한다

 

6. 프로세스

  • 애플리케이션을 하나 혹은 여러 개의 무상태 프로세스로 실행
  • 실행 환경은 하나 이상의 프로세스로 실행
  • 캐시등을 위한 짧은 단일 프로세스에서의 데이터 저장을 제외한 저장될 필요가 있는 모든 데이터는 데이터베이스같은 백엔드 서비스에 저장
  • 앱은 무상태(Stateless)로 ,  세션/파일/캐시 같은 상태(Stateful)은 외부 저장소로 하여 복제/장애복에 편리
  • 애플리케이션은 항상 Stateless하게 실행하고, 상태는 외부 저장소에 두어 복제와 장애 복구를 쉽게 한다.
  • 정리: 애플리케이션은 항상 Stateless하게 실행하고, 필요한 상태는 모두 외부 저장소에 둔다.

 

7. 포트 바인딩

  • 포트를 바인딩하여 서비스를 공개한다
  • 실행되는 단위는 포트를 가져야한다. (컨테이너의 철학)
    즉, 앱 = 실행 가능한 서비스 단위로 ( 컨테이너의 철학 )
  • 애플리케이션은 특정 포트를 열어 스스로 서비스를 제공하는 실행 단위여야 한다.
  • 정리: 애플리케이션은 특정 포트를 통해 스스로 서비스를 제공하는 독립적인 실행 단위여야 한다.

 

8. 동시성

  • 프로세스 모델을 통한 확장
  • 동시에 다양한 작업 부하를 처리 할 수 있도록 설계
  • Pod의 Thread를 늘리는 것이 아닌 Pod를 늘려 로드밸런서로 해결하는 것.
  • 동시성은 내부 쓰레드 확장이 아니라 프로세스를 복제해서 해결한다.
  • 정리: 작업 부하는 내부 쓰레드 확장이 아니라 프로세스 단위로 나누어 스케일아웃과 로드밸런싱이 잘 되게 설계한다.

 

9. 폐기 기능

  • 빠른시작과 그레이스풀 셧다운을 통한 안정성 극대화
  • 생성된 pod가 참조되는 곳이 너무 많으면 기능을 나눠서 최대한 빠르게 실행될 수 있도록
  • 문제 발생에 대해 종료 시  우아하게(그레이스풀) 문제 없이 종료될 수 있도록
  • 그레이스풀 셧다운을 통해 처리중인 작업을 큐로 되돌리는 방법으로 구현
  • 정리: 애플리케이션은 빠르게 시작되고 종료 시에도 처리 중이던 작업을 안전하게 마무리할 수 있어야 한다.

 

10. Dev/Prod 일치

  • 개발환경과 운영환경을 최대한 비슷하게 유지해야한다
  • 개발 환경과 운영 환경의 백엔드 서비스를 동일하게 유지하여 애플리케이션이 서로 다른 환경에서 백엔드 서비스의 차이로 오류가 나지 않도록 유지
  • 정리: 개발, 테스트, 운영 환경의 차이를 최소화해야 배포 후에만 발생하는 문제를 줄일 수 있다.

 

11. 로그

  • 로그를 이벤트 스트림으로 취급해라
  • 로그는 모든 실행중인 프로세스와 백그라운드 서비스의 아웃풋 스트림
  • 로그를 파일로 관리하지 말고, 모니터링/수집/검색 시스템이 담당하도록 
    > 컨테이너/분산환경에서의 표준
  • 정리: 로그는 파일로 보관하지 말고 이벤트 스트림처럼 수집 시스템으로 보내 분산 환경에서도 일관되게 관리한다.

 

12. Admin 프로세스

  • 정리: 관리자적인 프로세스, batch/crontab/schedule/migraion 등의 일회성은 admin 프로세스에서 진행하라 

 

 

 

MSA 아키텍처와 CRUD의 연계성

 

MSA에서는 CRUD를 분리해야 서비스 안정성/성능/확장/운영 효율이 모두 극대화된다.

우리는 CRUD의 성격을 이해하고 어떻게 서비스를 분리하고 MSA 아키텍처를 구성할지를 이해해보려고한다.

 

1) 조회와 쓰기의 성격이 다르다

  • 조회는 전체 트래픽의 대부분(대략 80%)으로 
       빠른 응답/고확장성이 중요함
      캐시/검색엔진/Read Replica 등 속도 중심 구조 필요
  • 쓰기(Create/Update/Delete)는 정확성과 비즈니스 규칙을 우선
    → 트랜잭션, 데이터 정합성, 검증, 이벤트 처리 필요
  • 두 성격이 너무 달라 한 서비스에 섞으면
    → 성능 튜닝 방향이 충돌하고 전체 품질이 떨어질 수 있다.

 

2) 서비스 비대화(모놀리식화)를 방지

  • CRUD를 한 서비스에 모두 넣으면 기능이 계속 붙어 작은 모놀리식이 됨
  • 도메인 경계가 흐려지고, 서비스 간 결합도가 높아짐
  • 설계 의도와 다르게 “하나의 거대한 서비스”가 됨
    → 유지보수, 테스트, 확장성 모두 악화
  • CRUD를 분리하면 서비스가 맡은 역할이 자연스럽게 명확해짐
    → 팀 단위 개발도 수월, 코드 품질도 안정적

 

3) 변경 주기와 배포 빈도가 다르기 때문

  • Write 로직(CUD)은 정책 변경·검증 변경 등 변화가 잦은 영역 
  • Read 로직은 데이터 형태가 고정적이라 변경이 매우 적음
  • 한 서비스에 묶여 있으면 Write 변경 시 → Read API까지 함께 재배포해야 해서 안정성 감소
  • 분리해두면
    → Read 서비스는 안정·무정지 운영 가능
    → Write 서비스만 독립 배포하며 리스크 최소화

 

4) 확장 방식이 CRUD 별로 다르기 때문

  • Read는 Scale-out에 최적화
    서버 수 늘리면 조회 속도·처리량이 바로 증가
  • Write는 트랜잭션 때문에 Scale-out 효과가 제한적
    변경은 일관성 유지가 핵심, 무조건 확장 불가
    → 일관성 유지가 중요하기 때문에 대기열을 만드는게 오히려 나음.
  • Read와 Write를 혼합하면
    → 둘 중 하나에 맞춘 확장 전략만 가능해서 비효율
  • 분리하면
    → 각자의 특성에 맞는 독립 확장 전략 적용 가능

 

5. 보안 규칙이 CRUD별로 다르다.

  • 조회(Read)는 다양한 클라이언트가 접근할 수 있고 정책이 비교적 단순
  • 쓰기(Write)는 더 강한 인증·인가·입력값 검증이 요구됨
    → 잘못된 데이터가 들어가면 전체 시스템 문제가 되기 때문
  • 한 서비스에 CRUD가 섞여 있으면 접근 제어 정책도 복잡해짐
  • 분리하면
    → 보안 정책을 목적별로 단순하게 적용 가능
    → 운영 및 검증 절차가 훨씬 쉬워짐

 

6. 장애전파를 막아 시스템의 안정성을 높이기 위해

  • Write 작업은 무겁고 오류·지연 가능성이 높음 (예: DB Lock, Deadlock, 트랜잭션 Timeout 등)
  • CRUD가 함께 있으면 Write 장애가 Read까지 전파됨
    → 전체 앱에서 조회가 한꺼번에 느려지거나 장애로 이어짐
  • 분리하면
    → Read 서비스는 캐시/복제DB 활용으로 안정적 유지
    → Write 장애가 전체 서비스로 번지지 않음 (장애 격리)

핵심: 조회는 “속도·확장성 중심”, 쓰기는 “정확성·정합성 중심”

 

 

 

 

이처럼 오늘은 MSA의 아키텍처에 대해 이해해보았다.

이전까지는 어떤 구조다 MSA는 서비스를 분리하는거니까 트래픽이 많은 얘들을 따로 분리하면 된다 정보도 이해했다.

하지만 이번에 CRUD와의 연계성을 이해해보니 MSA 아키텍처가 내가 알던 것보다 더 많은 고려사항이 필요하다는 것을 알게되었다. CRUD는 당연히 한 서비스에서 진행되어야한다고 생각했는데 대부분의 트래픽이 이루어지는 READ를 개별 서비스로 진행했을 때 성능 증가와 보안 관리에도 편리하다는 것은 아키텍처를 구성할 때 새로운 시각으로 다가왔다.