- Published on
MSA를 도입하면 얻는 장점은 무엇인가?
- Authors

- Name
- Justart
목차
- 프롤로그
- 모놀리식 구조와 MSA 구조의 차이
- API Gateway
- Microservice
- 서비스 간 통신
1. 프롤로그
사내에서 개발자의 역량 향상을 위해 팀원들과 사이드 프로젝트를 하기로 하였다. 개발이야 그냥 하면 되는거니까 개발보다도 아키텍처에 대한 이해도, 설계가 더 중요하다는 목표의식을 가지고 진행하라고 조언을 들었다.
사이드 프로젝트의 효율 보다도 앞으로 다양한 프로젝트를 만났을 때 상황에 맞게 설계하고 유연하게 대처하는 게 중점인 것 같았다. 이와 같은 상황에서 우리는 MSA(MicroService Architecture)를 채택했다.
MSA는 왜 나왔을까?
지금까지는 대부분 모놀리식 프로젝트로 진행했을 것이다. 다음과 같은 상황을 겪어 봤을 것이다.
- 코드가 커질수록 수정 하나 했는데 엉뚱한 데 터진다.
- 기능 하나 고치는데 전체 서버를 재배포 해야 한다.
- 새로운 기술을 쓰고 싶은데 전체 구조를 바꿔야 해서 힘들다.
간단하게 위와 같은 상황이 모놀리식의 본질적 한계다. MSA의 핵심 아이디어는 한 가지다.
문제 생기는 단위를 작게 쪼개자
MSA는 변경 · 배포 · 확장의 단위를 서비스 단위로 분리해서, 전체 시스템에 영향을 주지 않고 필요한 부분만 독립적으로 관리하기 위해 등장했다.
2. 모놀리식 구조와 MSA 구조의 차이
그럼 이 두 아키텍처는 정확히 어떻게 다른 걸까?
모놀리식 아키텍처
모놀리식은 한마디로 모든 걸 한 덩어리로 만드는 방식이다. UI, 비즈니스 로직, 데이터베이스가 전부 하나의 애플리케이션 안에 들어있다. 배포할 때도 통째로 배포한다.
MSA (Microservice Architecture)
반대로 MSA는 기능별로 쪼개서 독립된 서비스로 만드는 방식이다. 각 서비스는 독립적으로 배포하고 운영할 수 있으며, API로 서로 통신한다.
모놀리식 구조와 MSA 구조의 핵심 차이점
| 항목 | 모놀리식 | MSA |
|---|---|---|
| 구조 | 하나의 거대한 애플리케이션 | 독립된 작은 서비스들 |
| 배포 | 전체를 함께 배포 | 서비스별로 독립 배포 |
| 장애 영향 | 한 곳 오류 → 전체 다운 | 한 서비스 오류 → 해당 기능만 영향 |
| 기술 스택 | 전체가 동일한 기술 | 서비스별로 다른 기술 선택 가능 |
| 확장 | 전체를 스케일 아웃 | 필요한 서비스만 스케일 아웃 |
| 개발 | 초기 개발 빠름 | 초기 설계 복잡 |
3. API Gateway
왜 중간에 API Gateway가 하나 더 있는 거지?
위 다이어그램을 보면 모놀리식은 클라이언트가 서버에 바로 찌르는데, MSA는 API Gateway를 한 번 거친다. 왜 한 단계가 더 있는 걸까?
MSA의 딜레마
서비스가 독립적이라는 건 좋은데, 그럼 각 서비스마다 주소도 다르고, 인증 방식도 다를 수 있다는 얘기다.
프론트엔드 입장에서 생각해보자:
서비스 하나 추가되면? 프론트엔드 코드 수정. 주소 바뀌면? 또 수정. API 포맷이 서비스마다 다르네? 분기해야하나..?
이건 백엔드에 완전히 종속되는 거다.
그래서 나온 게 API Gateway
프론트엔드와 백엔드 서비스 사이에 딱 하나의 문을 만드는 거다. 클라이언트는 이 문만 두드리면 되고, API Gateway가 알아서 적절한 서비스로 전달해준다.
이 Gateway가 정확히 뭘 해주는데?
1. 인증 체크
User, Product, Order, Payment... 모든 서비스마다 "너 로그인했어?"를 매번 체크하는 건 비효율적이다.
API Gateway에서 한 번만 확인하면 끝난다.
흐름:
요청 들어옴 → Gateway에서 JWT 토큰 검증 → (유효하면) 서비스로 전달
각 서비스는 비즈니스 로직에만 집중하면 된다.
2. 라우팅
클라이언트는 그냥 /api/users, /api/products 이렇게만 치면 되고, Gateway가 알아서 각 서비스로 보내준다. 서비스 주소가 바뀌면? Gateway 설정만 고치면 된다. 클라이언트는 몰라도 된다.
3. 공통 처리
CORS, Rate Limiting, 로깅 같은 건 모든 API에 필요한데, 매번 구현하면 귀찮다. Gateway에서 한 번에 처리한다.
- CORS: 허용된 도메인만 API 호출 가능
- Rate Limiting: 과도한 요청 차단 (DDoS 방어)
- 로깅: 모든 API 호출 기록
- 에러 처리: 일관된 에러 형식
4. 응답 합치기
사용자 프로필 페이지를 띄우려면 사용자 정보, 주문 내역, 결제 수단이 다 필요하다. 클라이언트가 세 번 API를 때리는 대신, Gateway가 동시에 호출해서 한 번에 보내줄 수 있다.
그럼 BFF는 뭔데? API Gateway랑 뭐가 달라?
위 다이어그램을 보면 BFF(Backend for Frontend)가 점선으로 표시되어 있다. 선택사항이라는 뜻이다. 둘 다 응답을 합치는 기능이 있는데, 뭐가 다를까?
API Gateway: 단순하게 붙이기
Gateway는 그냥 데이터를 있는 그대로 합쳐준다. 가공은 안 한다.
// Gateway가 반환하는 데이터
{
"user": { "id": 1, "name": "박OO", "email": "...", ... },
"orders": [ { "orderId": 101, "status": "delivered", ... } ],
"payments": [ { "cardNumber": "****1234", ... } ]
}
필요 없는 데이터도 전부 다 온다. 클라이언트가 알아서 골라 써야 한다.
BFF: 클라이언트 맞춤 가공
BFF는 각 플랫폼에 딱 맞게 데이터를 변환해준다. 웹과 모바일이 필요한 데이터가 다르니까.
Web BFF
{
"userName": "박레고",
"recentOrders": [{ "id": 101, "summary": "MacBook Pro 외 2건" }],
"defaultPayment": "신한카드 ****1234"
}
Mobile BFF
{
"displayName": "박레고",
"orderCount": 1,
"hasPaymentMethod": true
}
API Gateway와 BFF 핵심 차이점
| 항목 | API Gateway | BFF |
|---|---|---|
| 역할 | 진입점 + 공통 처리 | 클라이언트별 데이터 가공 |
| 가공 | 단순 병합 | 변환 + 필터링 |
| 로직 | 거의 없음 | 있음 (맞춤 제공) |
| 데이터 | 전부 다 줌 | 필요한 것만 줌 |
BFF는 언제 써야 할까?
필요한 경우:
- 웹과 모바일 UI가 완전히 다를 때
- 데이터 형식을 클라이언트별로 다르게 줘야 할 때
- 프론트엔드 팀이 백엔드 로직을 일부 제어하고 싶을 때
안 써도 되는 경우:
- Gateway 조합만으로 충분할 때
- 모든 클라이언트가 비슷한 데이터를 쓸 때
- 복잡도를 더 늘리고 싶지 않을 때
간단히 말하면, Gateway는 필수, BFF는 선택이다.
4. Microservice
마이크로서비스를 기술 단위로 나누면 안 된다. "프론트엔드 서비스", "백엔드 서비스" 이런 식으로 나누는 게 아니라, 비즈니스 도메인 단위로 나눠야 한다.
예를 들면 User 서비스, Product 서비스, Order 서비스 이런 식이다.
각 서비스는:
- 자기 비즈니스 로직을 가지고
- 자기 데이터를 소유하고
- 독립적으로 배포 가능해야 한다
서비스를 어떻게 나눠야 잘 나눴다고 소문 날까?
서비스를 너무 잘게 쪼개면 관리가 힘들고, 너무 크게 뭉치면 모놀리식이랑 다를 게 없다. 어떻게 나눠야 할까?
1. 배포 영향
"이 기능 수정하면 다른 기능도 같이 배포해야 해?"
- YES → 강하게 결합됨 → 분리 필요
- NO → 독립 배포 가능 → 현재 괜찮음
2. 장애 영향
"이 기능 터지면 다른 기능도 같이 죽어?"
- YES → 장애 전파됨 → 분리 필요
- NO → 장애 격리 가능 → 현재 괜찮음
3. 데이터 주인
"이 데이터를 여러 서비스가 직접 수정해?"
- YES → 책임 불명확 → 분리 필요
- NO → 한 서비스만 소유 → 현재 괜찮음
(중요) 각 서비스는 자기 데이터만 수정해야 한다. 다른 서비스 데이터가 필요하면 API로 요청한다.
4. 트래픽 특성
"이 기능만 유독 트래픽이 많아?"
- YES → 개별 확장 필요 → 분리 고려
- NO → 함께 확장해도 됨 → 현재 괜찮음
예를 들어, 상품 조회는 엄청 많은데 결제는 적다면, Product 서비스만 스케일 아웃하면 된다.
5. 보안/권한
"이 기능은 다른 권한 체계를 가져?"
- YES → 보안 경계 필요 → 분리 고려
- NO → 동일 권한 → 현재 괜찮음
예를 들어, 관리자 기능은 일반 사용자 기능과 분리하는 게 좋다.
정리하면
서비스 분리의 핵심은 독립성이다. 배포, 장애, 데이터, 트래픽, 권한이 서로 영향을 주지 않도록 나누면 된다.
5. 서비스 간 통신
MSA에서는 서비스마다 DB가 분리되어 있고, 서로 직접 데이터 접근을 하면 안 된다. 그래서 서비스끼리는 반드시 통신을 해야 한다.
서비스 간 통신 방식에는 크게 동기 통신과 비동기 통신으로 나눌 수 있는데, 대부분의 어려움은 동기 통신에서 발생한다.
동기 통신 (REST API, gRPC)
특징:
- 요청하고 응답을 기다림
- 실시간 응답이 필요할 때 사용
문제점:
- 장애 전파: A → B → C 순서로 호출할 때, C가 죽으면 B도 죽고, A도 죽음
- 지연 누적: 각 서비스 응답 시간이 누적됨
- 트랜잭션 복잡: 여러 서비스에 걸친 트랜잭션 처리 어려움
동기 통신의 보호 장치:
동기 통신을 사용할 때는 반드시 다음 보호 장치를 넣어야 한다.
1. Timeout
응답을 무한정 기다리지 않고 일정 시간 후 실패 처리
// 3초 안에 응답 없으면 에러
fetch('/api/users', { timeout: 3000 })
2. Circuit Breaker
실패가 일정 횟수 이상 반복되면 회로 차단. 더 이상 호출하지 않고 바로 실패 응답
3. Fallback
서비스 호출이 실패하면 대체 로직 실행
try {
return await userService.getUser(userId)
} catch (error) {
// Fallback: 캐시된 데이터 반환
return cache.get(userId)
}
4. Saga 패턴
여러 서비스에 걸친 트랜잭션을 보상 트랜잭션으로 처리
예시: 주문 프로세스
- Order Service: 주문 생성
- Payment Service: 결제 처리
- Inventory Service: 재고 차감
- Shipping Service: 배송 시작
만약 4번에서 실패하면? 역순으로 보상:
- Shipping 취소
- 재고 복구
- 결제 취소
- 주문 취소
서비스 간 통신 원칙
절대 하지 말아야 할 것:
- ❌ 다른 서비스 DB 직접 조회
- ❌ DB JOIN으로 여러 서비스 데이터 조회
- ❌ 트랜잭션을 여러 서비스에 걸쳐 공유
반드시 지켜야 할 것:
- ✅
API또는Event로만 통신 - ✅ 각 서비스는 자기 데이터만 책임
- ✅ 다른 서비스 데이터가 필요하면 API 호출
Service Discovery
서비스들은 동적으로 생성/삭제된다. IP가 고정되어 있지 않다는 뜻이다. 그러므로 Service Registry를 통해 조회한다.
Service Registry란?
실행 중인 서비스들의 주소를 자동으로 등록·조회하는 시스템
동작 방식:
- User Service 시작 → Registry에 자기 주소 등록
- Order Service가 User Service 필요 → Registry에 주소 조회
- Registry가 User Service 주소 반환
- Order Service가 User Service 호출
요즘 표준:
Kubernetes(k8s)가 자체적으로 Service Discovery 기능을 제공한다. 별도의 Registry 없이 서비스 이름으로 바로 호출 가능.
# user-service를 이름으로 바로 호출 가능
http://user-service:8080/api/users
마무리
MSA는 복잡도가 높다. 하지만 그만큼 얻는 것도 많다:
- 독립 배포: 기능 하나 고쳐도 전체 재배포 불필요
- 장애 격리: 한 서비스 장애가 전체로 번지지 않음
- 기술 자유도: 서비스마다 최적의 기술 선택 가능
- 확장성: 필요한 서비스만 스케일 아웃
중요한 건 무조건 MSA가 정답이 아니라는 것이다. 팀 규모, 프로젝트 특성, 기술 역량을 고려해서 선택해야 한다.
작은 프로젝트나 스타트업 초기에는 모놀리식으로 빠르게 검증하고, 규모가 커지면 점진적으로 MSA로 전환하는 게 현실적이다.