목차
1. MSA란?
2. 왜 MSA를 사용하는가?
3. 어떻게 MSA를 도입하는가?
MSA란?
마이크로서비스 아키텍처는 소프트웨어를 여러 개의 작은 독립적인 서비스로 분할하는 소프트웨어 아키텍처 스타일입니다.
이것은 아래의 특징이 있습니다.
- 서비스 간에 네트워크 통신을 한다.
- 도메인 중심으로 설계한다.
- 서비스 별 최적화된 기술을 독립적으로 사용 가능하다.
- 서비스 크기는 작아지고, 독자적 개발 / 배포/ 확장/ 관리가 가능하다.
왜 MSA를 사용하는가?
Monolithic 구조의 단점들이 Business에 미치는 부정적인 영향이 크고, MSA로 얻을 수 있는 이익이 이 단점들 보다 클 경우에 사용합니다.
Monolithic 구조의 단점은 다음과 같습니다.
- 복잡성으로 인한 관리의 어려움: 하나의 애플리케이션에 기능이 다양해지게 되면, 기능 간의 의존관계가 복잡하게 얽히게 되어 유지보수가 어려워집니다.
- 확장의 어려움: 전체 코드를 한번에 배포해야함으로 불필요한 리소스 낭비가 발생할 수 있습니다.
- 기술 스택의 제한: 기능 마다 적합한 기술 스택이 다를 수 있는데, 한 애플리케이션에서는 동일한 기술 스택과 프레임워크에 의존하게 됩니다.
- 장애 전파의 위험: 하나의 장애가 전파될 위험이 큽니다.
즉, 위의 어려움은 주로 여러 기능들을 서빙해야하는 대규모 어플리케이션에서 발생하게 됩니다.
MSA의 장점은 다음과 같습니다.
- 운영 측면
- 배포가 쉽다: 배포의 단위가 작아지고, 이에 따라 배포가 주는 영향의 범위가 줄어들고, 배포 버전 관리를 독립적으로 할 수 있습니다.
- Branch 관리가 쉽다: 마이크로 서비스마다 독립적으로 운영하기 때문에, 브랜치 간에 충돌이 발생할 가능성이 줄어듭니다.
- 기술 특면
- 각 서비스 별로 기술 선택의 의존성이 낮아져서, 최적의 기술 선택이 가능합니다.
- 설계 변경의 부담이 줄어듭니다.
- 디버깅 포인트를 고립시킬 수 있습니다.
반면, 단점은 아래와 같습니다.
- 운영 측면
- 관리해야할 서비스가 많아집니다.
- 서비스간의 연결관계가 복잡하게 얽혀서 관리하게 어려워집니다.
- 기술 측면
- 함수 호출이 Network I/O 호출로 바뀌어서 서비스 상태 동기화가 어려워집니다.
- DB 분리 시에 Join이 어려워집니다.
클라우드와 MSA
추가적으로 클라우드 환경은 MSA가 인기를 얻게 된 데에 큰 몫을 하는데 이유는 다음과 같습니다.
- 클라우드의 가상 인스턴스로 인해 물리적 이슈를 해방 -> 작은 서비스 단위로 나누기 쉬워짐
- 인스턴스 사용이 편리 -> 많은 인스턴스 배포관리가 쉬워짐
어떻게 MSA를 적용하는가?
1. 작은 서비스 단위로 쪼개기(DDD)
MSA의 각 서비스들이 도메인을 기준으로 나눠지기 떄문에, 이 과정은 DDD(Domain Deriven Design, 도메인 주도 설계)를 통해 이뤄집니다.
2. 분리된 서비스의 통합 관리 방안 수립
서비스 메쉬 (네트워크를 통한 서비스간 통신을 통제하는 인프라 레이어) 기반의 아우터 아키텍처를 선정해야합니다.
이 서비스가 갖춰야할 주요한 기능들이 있고, 비즈니스 요구사항에 따라 적절한 기술을 적용해서 사용합니다. 주요한 기능들은 다음과 같습니다.
- Configuration Management: 서비스의 재빌드·재부팅 없이 설정사항을 반영(Netflix Archaius, Kubernetes Configmap)
- Service Discovery: MSA 기반 서비스 배포 시 서비스 검색 및 등록(Netflix Eureka, Kubernetes Service, Istio)
- Load Balancing: 서비스 간 부하 분산(Netflix Ribbon, Kubernetes Service, Istio)
- API Gateway: 클라이언트 접근 요청을 일원화(Netflix Zuul, Kubernetes Ingress)
- Service Security: 마이크로서비스 보안을 위한 심층 방어메커니즘 적용(Spring Cloud Security)
- Centralized Logging: 서비스별 로그의 중앙집중화(ELK Stack)
- Centralized Monitoring: 서비스별 메트릭 정보의 중앙집중화(Netflix Spectator, Heapster)
- Distributed Tracing: 마이크로서비스 간의 호출 추적(Spring Cloud Sleuth, Zipkin)
- Resilience & Fault Tolerance: MSA 구조에서 하나의 실패한 서비스가 체인에 연결된 전체 서비스들에 파급 효과를 발생시키지 않도록 하기 위한 계단식 실패 방지 구조(Netflix Hystrix, Kubernetes Health check)
- Auto-Scaling & Self-Healing: 자동 스케일링, 복구 자동화를 통한 서비스 관리 효율화
- Build/Deploy Automation: 서비스별 빌드·배포 자동화(Netflix Spinnaker, Kubernetes Scheduler, Jenkins)
- Rest Automation: 서비스에 대한 테스트 자동화
- Image Repository: 컨테이너 기반 서비스 배포를 위한 이미지 저장소
또한 서비스 메쉬의 적용 방안은 크게 세 가지가 있습니다.
- REST API 호출 방식으로 서비스를 결합시키는 스프링 클라우드(Spring Cloud) 기반 넷플릭스 OSS
- 쿠버네티스(Kubernetes) 기반 클라우드 네이티브(Cloud Native) 서비스
- 사이드카 프록시(Sidecar Proxy) 패턴의 쿠버네티스 기반 이스티오(Istio) 솔루션
3. DB 관리
서비스마다 각자의 DB가 있음으로 DB를 관리하는 게 어려워집니다. 기존의 모놀로식한 방법과 다른 트랜젝션과 쿼리를 보내는 방법을 도입해야합니다.
트랜젝션 관리 : SAGA 패턴
SAGA는 SEC(Saga Execution Coordinator)가 로컬 트랜잭션을 관리해주는 방식으로 하나의 로컬 트랜잭션 단위로 실행됩니다. 트랜잭션이 종료될 때 완료 이벤트를 수신하고 순차적으로 다음 로컬 트랜잭션을 실행하는 방식입니다. 이 때 중앙의 SEC 노드가 다음에 실행할 로컬 트랜잭션을 결정합니다.
트랜잭션 실행 중 실패가 발생하면 원래 트랜잭션에 대한 로그를 남기고 취소 상태를 설정한 후 보상 트랜잭션을 실행합니다. 만일 보상 트랜잭션마저 실패한다면, 일정 횟수만큼 혹은 일정기간 동안 보상 트랜잭션을 반복적으로 재시도하게 됩니다. 각 마이크로서비스는 자신의 로컬 원자적 트랜잭션(Atomic Transaction)에만 집중하기 때문에 보류(Pending) 상태가 없습니다. 따라서 오래 걸리는(Long-Lived) 트랜잭션에 적합합니다.
서비스별로 분산된 데이터 쿼리
API 조합기 또는 CQRS패턴을 통해 해결할 수 있습니다. 간단히 말하자면, 흩어져 있는 DB를 API 조합기를 통해 하나의 데이터로 합치는 것입니다. 하지만, 이런 방법은 오버헤드가 크다는 단점이 있습니다.
CQRS 패턴은 명령과 조회의 책임을 분리하는 패턴으로, 복잡해진 로직을 조회와 변경으로 나눠서 처리할 수 있습니다.
나가며
MSA가 정말 방대한 내용이라는 것을 알았고, 이번 기회에 전체적으로 훑어보면서 어떤 것을 공부해볼지 생각해보는 좋은 기회였습니다.
참조
'General' 카테고리의 다른 글
[DDD] 값객체와 엔티티, 도메인 서비스 (0) | 2023.06.03 |
---|---|
[Google Java Convention] 구글의 자바 컨벤션 정리 (1) | 2023.01.26 |
객체지향 설계 원칙 - SOLID (0) | 2022.11.14 |
TDD(테스트 주도 개발) 시작하는 방법 (0) | 2022.11.06 |
[로깅 전략] 로그는 어떻게 남겨야할까? (중앙집중식 로깅) (0) | 2022.10.26 |