MSA(Microservices Architecture)는 단순한 유행이 아니라, **"거대한 진흙 덩어리(Monolithic)를 관리 가능한 작은 단위로 쪼개어 비즈니스의 민첩성을 극대화하는 전략
1. MSA 환경의 핵심 정의
기존의 모놀리틱(Monolithic) 이 모든 기능(주문, 결제, 회원, 상품)을 하나의 실행 파일(.jar)로 배포했다면,
MSA는 이 기능들을 각각 독립적인 서비스로 떼어내어 별도의 서버에 배포하고, 네트워크(주로 HTTP API나 메시지 큐)를 통해 통신하는 환경입니다.
왜 이렇게 하는가?
- 부분 배포 가능: 결제 로직 하나 고치려고 전체 서버를 내릴 필요가 없습니다.
- 기술 다양성: 상품 서비스는 Java/JPA로, 실시간 알림 서비스는 WebFlux로, 데이터 분석은 Python으로 짤 수 있습니다.
- 개별 확장(Scaling): 이벤트 기간에 '주문' 서비스에만 사람이 몰리면 주문 서버만 10대 늘리면 됩니다.
2. MSA 환경에서 꼭 마주하게 되는 구성 요소
① API Gateway (입구)
클라이언트는 수십 개의 서비스 주소를 알 필요가 없습니다. 모든 요청은 게이트웨이로 모입니다.
- 연결 고리: 여기서 WebFlux가 주로 쓰입니다. 수만 명의 요청을 각 서비스로 빠르게 '전달'만 해야 하므로 논블로킹 엔진이 최적입니다.
② Service Registry & Discovery (전화번호부)
서비스들이 클라우드 환경에서 IP가 계속 바뀔 때, "지금 주문 서비스 어디 있어?"라고 물어보면 알려주는 시스템(Netflix Eureka 등)입니다.
③ Database per Service (데이터 격리)
각 서비스는 자기만의 DB를 가집니다. 서비스 A가 서비스 B의 DB를 직접 쿼리하는 것은 MSA에서 '금기'입니다. 무조건 API나 메시지를 통해서만 소통합니다.
3. MSA 환경의 고충
- 트랜잭션의 한계: 모놀리틱에서는
@Transactional하나로 로그 저장과 스냅샷 생성을 묶을 수 있었지만, MSA에서 로그 서비스와 스냅샷 서비스가 분리된다면 원자성을 보장하기 매우 어렵습니다. - 네트워크 오버헤드: 예전엔 내부 메서드 호출이었던 것이 이제는 HTTP 호출(네트워크)이 됩니다. 이때 스레드가 차단되지 않도록 WebClient(WebFlux) 같은 논블로킹 통신이 필수가 됩니다.
- 로그 추적의 어려움: 사용자 요청 하나가 서비스 5개를 거쳐가면 어디서 에러가 났는지 찾기 힘듭니다. 그래서 Distributed Tracing(예: Zipkin, Sleuth) 같은 기술이 필요해집니다.
1. 서비스의 성장과 MSA 도입 (Scalability)
덩치가 커지면 코드 수정 하나가 전체 시스템에 영향을 주는 '모놀리틱의 저주'가 시작됩니다.
이를 해결하기 위해 서버를 유동적으로 늘리고 줄일 수 있는 MSA(Microservices Architecture) 도입은 필연적인 선택이 됩니다.
2. WebFlux와 MVC의 공존 (Mixed Model)
모든 서비스를 WebFlux로 바꿀 필요는 없습니다.
- Gateway/Edge: 외부 요청을 제일 먼저 받아 여러 서비스로 뿌려주는 입구(Gateway)나, 실시간 알림(SSE) 서버는 WebFlux로 구축하여 자원 효율을 극대화합니다.
- Core Business: 복잡한 도메인 로직과 JPA 기반의 RDB를 사용하는 핵심 서비스들은 익숙하고 안정적인 Spring MVC로 유지합니다.
- 이 두 세계를 연결하는 통로로 아까 보신 코드처럼 WebClient를 사용하여 비동기 통신을 수행하게 됩니다.
3. DB 분리와 메시징 시스템 (Event-Driven)
서비스가 쪼개지면 DB도 쪼개지는데, 이때 가장 큰 문제가 "A 서비스가 데이터를 바꿨는데 B 서비스도 알아야 한다"는 점입니다.
- Kafka / RabbitMQ: 서비스 간에 직접 API를 호출(HTTP)하면 상대방이 죽었을 때 나도 죽는 강한 결합이 생깁니다. 이를 막기 위해 메시지 큐를 도입합니다.
- 비동기 전파: "주문이 완료됐어!"라는 이벤트를 Kafka에 던져두면, 배송 서비스나 포인트 서비스가 각자 자기 속도에 맞춰 그 메시지를 가져가서 처리합니다. 여기서 시스템의 유연성이 완성됩니다.
※ "주문은 성공했는데, 결제 서비스가 죽어서 결제가 실패했다면? 주문을 어떻게 취소하지?" 이때 등장하는 것이 앞서 언급한 Saga 패턴(보상 트랜잭션)입니다.
- 마치
git revert를 날리는 것과 같습니다. 결제 실패 이벤트를 Kafka에서 확인하면, 주문 서비스가 다시 주문을 취소하는 '보상 작업'을 수행하여 데이터의 최종적인 일관성을 맞추는 것이죠.
4. MSA 성공을 위한 추가 고려 요소 (Observability)
서비스가 잘게 쪼개질수록 '관리의 영역'이 기하급수적으로 늘어납니다. 이를 위해 다음 두 가지 개념이 보완되면 좋습니다.
- Config Management (설정 중앙화): 수십 개의 서비스 설정(DB 주소, API 키 등)을 일일이 수정할 수 없습니다. Spring Cloud Config처럼 설정을 한곳에서 관리하고 실시간으로 배포하는 시스템이 필요합니다.
- CI/CD 자동화: 서비스가 많다는 것은 배포할 대상이 많다는 뜻입니다. 수동 배포는 불가능에 가깝기에, Jenkins나 GitHub Actions를 통한 완전 자동화된 파이프라인은 MSA의 전제 조건입니다.
- Circuit Breaker (장애 전파 방지): 특정 서비스(예: 결제)에 과부하가 걸렸을 때, 시스템 전체가 마비되지 않도록 연결을 잠시 끊어주는 Resilience4j 같은 안전장치가 필수적입니다.
정리: "은탄환은 없다 (No Silver Bullet)"
MSA는 모든 문제를 해결해 주는 마법의 지팡이가 아닙니다. 오히려 모놀리틱보다 훨씬 복잡한 인프라 관리 능력과 네트워크 비용을 요구합니다.
결국 중요한 것은 "우리 비즈니스의 규모와 복잡도가 이 비용을 감수할 만큼 큰가?"를 판단하는 것입니다.
- 작은 규모에서는 모놀리틱으로 빠르게 제품을 출시하고(Time to Market),
- 성장함에 따라 병목이 생기는 부분부터 점진적으로 MSA로 전환해 나가는 전략,
즉, 기술의 화려함보다 비즈니스의 성장에 발맞추어 진화하는 아키텍처가 진정으로 건강한 MSA의 모습일 것입니다.
'관련_배경_지식' 카테고리의 다른 글
| Soap방식과 Restful 방식의 차이점 (0) | 2024.11.24 |
|---|---|
| 암/복호화시 "Given final block not properly padded" 에러 (3) | 2024.11.11 |
| 유니캐스트, 브로드캐스트, 멀티캐스트, 애니캐스트의 차이점 (4) | 2024.09.26 |
| DevOps와 SRE(Site Reliability Engineering) (0) | 2024.06.24 |
| iCloud 비공개 릴레이 (icloud private relay) 란? (0) | 2024.03.31 |