[MSA] MSA 전환 프로젝트 - 1. MSA란?
현재 진행중인 게시판 프로젝트의 버전업을 위해 기능 추가 말고 어떤 걸 할 수 있을까 고민하다가 예전에 얼핏 듣고 넘어갔던 MSA를 현재 프로젝트에 적용해 보기로 했다.
Board와 Member 그리고 인증을 위한 JWT와 OAUTH로 이루어진 아주 작은 프로젝트지만 이 상태에서 MSA로 전환을 해보는 것이 MSA를 이해하는 데도 분명히 도움이 될 것이고 새로운 기능을 추가하고 확장해 나가는 것도 좋은 경험이 되리라 생각해서 지금 한 번 해보기로 했다.
이제 실전으로 들어가기 전에 현재 프로젝트에서 사용중인 Monolithic Architecture는 무엇이고 MSA는 또 무엇인지 알아보는 것으로 시작해보자
1. Monolithic Architecture란?
지금 만들어진 프로젝트와 같이 규모가 작고 트래픽이 적은 간단한 서비스의 애플리케이션 같은 경우엔 모든 소스 코드가 하나의 애플리케이션에 통합되어 빌드되고 배포되는 경우가 많다.
즉 소프트웨어의 구성 요소가 한 프로젝트에 통합되어 있는 형태로, 쉽고 빠르게 구축이 가능하고 관리가 수월하다는 장점이 있다.
현재 애플리케이션에는 Member와 Board 두 개의 도메인이 존재하고 그 두 개의 도메인이 하나의 애플리케이션으로 결합돼있는 상태다.
또한 DB 역시 하나의 DB에 두 개의 도메인에 관한 테이블을 통해 데이터를 저장하고 있다.
여기서 중요한 부분은
하나의 애플리케이션 안에서 모든 도메인과 DB가 서로 결합되어 있다는 부분이다.
이러한 결합 상태가 애플리케이션의 규모가 작을 때는 드러나지 않던 Monolithic Architecture의 단점을 만든다.
1) Monolithic Archtecture의 단점
(1) 빌드 및 배포시간이 길어진다.
모놀리식 구조에서는 하나의 애플리케이션에 포함된 모든 서비스가 하나의 빌드 과정으로 처리된다.
현재와 같은 작은 프로젝트에서는 빌드와 배포 시간이 크게 문제되지 않지만,프로젝트 규모가 커지고 서비스가 많아질수록 이 시간이 점차 길어지게 된다.
이는 지속적인 빌드와 배포가 요구되는 웹 서비스에서 리소스 낭비와 생산성 저하를 초래할 수 있다.
(2) 조그마한 수정사항이 있어도 전체를 다시 빌드하고 배포해야 한다.
모놀리식 애플리케이션은 모든 서비스가 하나로 묶여있기 때문에, 특정 서비스에 사소한 수정 사항이 있어도 전체 애플리케이션을 빌드하고 배포해야 한다.
이는 빌드와 배포 시간이 긴 모놀리식 구조에서 상당한 비효율을 초래하며, 수정 범위가 작더라도 전체 시스템의 재배포가 필요해 리소스의 낭비가 발생한다.
(3) 서비스 하나의 장애가 전체 서비스에 영향을 미친다.
모놀리식 애플리케이션에서는 하나의 서비스에 발생한 장애가 전체 시스템에 영향을 미칠 수 있다.
예를 들어, 게시글 서비스에 트래픽이 몰려 장애가 발생할 경우, 같은 애플리케이션 안에 있는 회원 서비스에도 문제가 발생할 수 있다.
서비스 규모가 커질수록 하나의 장애가 더 많은 서비스에 영향을 미치며, 이는 사용자 경험에 부정적인 결과를 초래할 수 있다.
(4) 각 서비스의 유지보수가 어렵다.
모놀리식 구조에서는 여러 서비스들이 하나의 애플리케이션으로 강하게 결합되어 있어, 특정 서비스를 수정할 때 연관된 다른 서비스까지 함께 고려해야 한다.
이로 인해 유지보수 시 고려해야 할 사항이 늘어나며, 수정 사항이 다른 서비스에 미칠 영향을 예측하기 어려워 유지보수가 복잡해진다.
(5) 특정 서비스만 Scale-Out 하기가 힘들다.
Scale-Out은 서버의 수를 늘려 시스템을 확장하는 방법인데, 서버를 양적으로 늘려 성능을 향상시키는 것을 의미한다.
프로젝트의 규모가 커지고 많은 사용자들이 서비스를 이용하다 보면, 전체 서비스에 트래픽이 고르게 분배되기보다는 특정 서비스에 트래픽이 집중되는 경우가 많다.
예를 들어, 현재 프로젝트에서는 회원 서비스보다 게시판 서비스에 더 많은 트래픽이 몰릴 가능성이 높다.
이럴 때 게시판 서비스만 별도로 확장하고 싶지만, 애플리케이션이 하나로 통합되어 있기 때문에 전체 애플리케이션을 확장해야 하는 비효율이 발생한다.
적고보니 장점도 물론 있지만 꽤 많은 단점이 존재하는데 이러한 단점들을 해결하기 위해 고안된 것이 SOA와 앞으로 알아볼 MSA다.
2. SOA와 MSA
1) SOA(Service-Oriented Architecture)
SOA(Service-Oriented Architecture)는 말 그대로 서비스 지향 아키텍처로,
기업의 소프트웨어 인프라에서 정보를 독립적인 서비스로 간주하여 연동과 통합을 전제로 개발된 서비스들을 공유함으로써 재사용성을 극대화하고 유연성을 확보하는 것을 목표로 한다.
2) MSA(Microservices Architecture)
MSA(Microservices Architecture)는 SOA의 개념을 더욱 작은 단위로 세분화하여, 마이크로 서비스라는 독립적인 서비스로 시스템을 구축하는 아키텍처다.
MSA는 각 서비스를 최소한의 단위로 나누어 개발하고, 서비스 간의 의존성을 줄여 시스템의 민첩성과 확장성을 극대화한다.
각 서비스는 독립적으로 배포, 확장 및 유지보수가 가능하며, 주로 경량화된 통신 프로토콜(예: REST API)을 사용하여 서로 통신한다.
2) SOA vs MSA
SOA와 MSA는 모두 서비스 지향적인 설계 방식으로, 서비스 간의 느슨한 결합을 유지하며 필요한 서비스를 조립하여 사용할 수 있다는 공통점을 가지고 있다.
그러나 두 아키텍처는 규모와 설계 방식에서 중요한 차이점을 가지고 있다.
(1) 서비스의 규모
- SOA : SOA에서는 서비스가 비교적 큰 단위로 묶여 있으며, 여러 비즈니스 기능을 통합한 서비스가 하나의 구성 요소로 작동할 수 있다. 이때 서비스는 재사용과 공유를 목표로 설계된다.
- MSA : MSA는 SOA보다 더 작은 마이크로 단위의 서비스를 중심으로 구성된다.
각 마이크로 서비스는 하나의 특정 비즈니스 기능에 집중하며, 다른 서비스와 최대한 독립적으로 작동하도록 설계된다.
이러한 소규모 서비스 구조 덕분에 서비스 간 의존성이 낮아지고, 더욱 유연하고 민첩한 배포 및 확장이 가능하다.
(2) 서비스 간 통신 방식
- SOA: SOA는 ESB(Enterprise Service Bus)라는 중앙 집중식 미들웨어를 사용하여 각 서비스를 연결하고 통합한다.
ESB는 여러 서비스 간의 통신을 조정하고 관리하는 역할을 하지만, 이로 인해 시스템의 복잡성이 증가할 수 있으며, ESB 자체가 성능 병목 현상을 일으킬 수 있습니다. - MSA: MSA는 ESB 같은 중앙 집중식 미들웨어 대신, 경량화된 메시징 시스템(예: REST, HTTP, gRPC)을 통해 서비스 간 통신을 수행한다.
이러한 방식은 서비스 간의 독립성을 높이고, 중앙 집중적인 통합 지점을 제거함으로써 시스템의 유연성과 성능을 높일 수 있다.
(3) 재가용성 vs 독립성
- SOA : SOA의 주요 목표 중 하나는 재가용성이다. 서비스는 재사용이 가능한 방식으로 설계되며, 다양한 애플리케이션에서 동일한 서비스를 사용할 수 있도록 공유된다.
그러나 여러 애플리케이션에서 하나의 서비스를 공유할 경우, 서비스 간 결합도가 증가할 수 있고, 서비스 수정 시 모든 관련 시스템에 영향을 미칠 수 있다. - MSA : MSA는 서비스 간의 결합도를 낮추기 위해 독립성을 강조한다. 각 마이크로 서비스는 다른 서비스와 독립적으로 배포 및 운영될 수 있으며, 서비스를 독립적으로 확장할 수 있다.
(4) 확장성
- SOA : SOA에서는 전체 시스템 또는 여러 서비스를 통합한 애플리케이션 단위로 확장하는 경우가 많다.
즉, 특정 서비스에 대한 확장보다는 애플리케이션 전체를 확장해야 할 때가 많아, 세밀한 확장은 어려울 수 있습니다. - MSA : MSA는 각 마이크로 서비스가 독립적으로 확장될 수 있기 때문에, 트래픽이 몰리는 특정 서비스만 선택적으로 확장할 수 있다.
이를 통해 자원을 효율적으로 사용할 수 있고, 필요에 따라 특정 기능에만 서버를 추가하거나 성능을 조정할 수 있다.
3. MSA 고려사항
앞서 SOA와 MSA를 비교하며 MSA가 어떤 특징을 가지고 있는지 살펴봤다.
이를 토대로 생각해보면 MSA는 Monolithic Architecture가 가지고 있는 단점들을 완벽하게 보완할 수 있는 설계 방식으로 보인다.
1. 빌드 및 배포 시간을 줄여서 생산성을 높일 수 있다.
2. 서비스 하나의 장애가 전체에 영향을 미친다. -> 서비스 하나의 장애가 애플리케이션 전체에 전파되지 않는다.
3. 각 서비스의 유지보수가 어렵다. -> 상대적으로 각 서비스의 유지보수가 쉽다.
4. 특정 서비스만 Scale-out 하기가 힘들다. -> 서비스별로 Scale-out이 쉽다.
그렇다면 기업은 기존의 레거시 시스템들을 MSA로 전환하거나 신규 프로젝트를 MSA로 개발해야 할까?
MSA를 도입할 때 고려해야할 점은 없을까?
1) 구축 전 고려사항
(1) Multiple Rates of Change
어느 정도 변화가 생길 것인가
기존 개발 대비 비용이라든가 시간이 더 투자해야 되는 것은 분명하다.
그럼에도 불구하고 도입해야 한다고 하면 어느정도의 공수를 고려하고도 받아들일 수 있을 것인가에 대한 문제를 말한다.
(2) Independent Life Cycles
독립 라이프 사이클
애플리케이션을 구성하고 있는 각각의 서비스들이 독립적으로 개발되고 운영될 수 있도록 서비스 경계가 잘 만들어 져 있는가를 고려해야 한다.
(3) Independent Scalability
독립적인 확장성
각각의 서비스를 운영함에 있어서 서비스 유지 보수 및 확장이 가능한가? 스케일링이 쉬운 구조로 되어 있는가를 고려해야 한다.
(4) Isolated Failure
격리된 오류
오류 자체가 발생하지 않는 것이 가장 좋겠지만 현실적으로 불가능하기 때문에 그러한 오류가 발생했을 때 오류사항들이 독립적인가에 대한 문제를 말한다.
즉 마이크로 서비스의 부분적인 오류가 발생되었다 하더라도 해당 서비스에 대해서만 오류가 영향을 받도록 설계 되었는지,
다른 마이크로 서비스들은 오류에 최소한의 영향을 받으면서 해당서비스를 우회할 수 있는 대체 서비스가 준비되어 있는지를 고려해야 한다.
(5) simplify Interactions with External Dependencies
외부 종속성과의 상호작용의 단순화
물론 외부 뿐 아니라 종속성, 커플링, 결합도라는 건 좋지 않기 때문에 시스템이나 서비스 간의 종속성을 최소화하고 반대로 응집력을 높일 수 있도록 서비스 경계가 잘 구분이 되어 있는가를 고려해야 한다.
2) 구축 중 고려사항
앞선 고려사항들을 충분히 고려하고 MSA로의 전환을 결정했다면 이제 구축을 위한 기술적인 부분들을 고려해야 한다.
(1) 외부의 요청을 알맞는 애플리케이션에 어떻게 전달할 것인가?
Monolithic Architecture에서는 하나의 애플리케이션만 존재했기 때문에 모든 요청이 하나의 애플리케이션에 전달되면 되었다.
그러나 MSA에서는 서비스 별로 애플리케이션이 분리되었기 때문에 클라이언트의 요청에 대해서 분기 처리가 필요하게 되었다.
이러한 처리를 MSA에서는 API Gateway를 도입하여 해결할 수 있다.
(2) 서비스 간 통신을 어떤 방식으로 할 것인가?
Monolithic Architecture에서는 하나의 애플리케이션 안에 여러 서비스들이 강결합을 맺고 있었다.
그래서 비즈니스 로직 상 서비스 간 참조가 필요하다면 애플리케이션 내에서 직접 참조하여 추가적인 리소스 없이 다른 서비스의 데이터를 가져오면 되었다.
하지만 MSA에서는 추가적인 리소스를 들여 다른 서비스와의 통신을 통해 데이터를 가져와야만 한다.
이렇게 추가적인 리소스로 다른 서비스와의 통신을 하는 방법의 종류는 다음과 같다.
- RestTemplate
- WebClient
- OpenFeign
- Message Broker(Kafka, RabbitMQ 등)
(3) 하나의 기능에서 트랜잭션을 어떻게 유지할 것인가?
Monolithic Architecture에서는 하나의 애플리케이션에 여러 테이블이 존재하는 통합 DB를 구성해 데이터를 저장하고 조회했다.
그러나 MSA에서는 각 서비스가 분리됨에 따라 DB 또한 서비스 별로 분리된다.
이렇게 DB가 분리됨에 따라서 여러 DB가 동작하게 되는 서비스를 실행할 때 트랜잭션 관리가 힘들어 진다.
이러한 문제를 해결하기 위한 트랜잭션 패턴이 크게 2가지 존재한다.
- 2PC 패턴(Two-Phase Coomit)
- Saga 패턴
(4) 서비스들의 정보를 어떻게 관리할 것인가?
앞서 MSA에서 외부에서 오는 요청은 API Gateway를 통해 전달되고, 서비스간 통신도 이루어진다고 했다.
이때, API Gateway는 어떻게 애플리케이션의 정보를 알아서 전달하고, 각 서비스들도 어떻게 다른 애플리케이션들의 정보를 알아서 통신하는 걸까?
API Gateway에 모든 애플리케이션 정보를 수동으로 등록하고 각 서비스에서도 다른 서비스들의 정보를 수동으로 등록하면 간단(?)하게 해결된다.
그러나 이것은 너무 비효율적인 방법이며 애플리케이션을 운영하다보면 생길 수 있는 서비스의 확장이나 축소에도 너무 많은 리소스가 들어가게 된다.
그렇기 때문에 MSA에서는 이러한 과정들을 각 서비스들의 정보를 등록/관리하는 Service Discovery 패턴을 통해 처리한다.
Monolithic Architecture와 SOA, MSA에 대해 알아보았다.
MSA는 워낙 복잡하고 고려해야할 것이 많기 때문에 이 외에도 고려해야할 사항들이 있고 이론적으로 풀어내야 할 것도 많을 것이라 생각한다.
그런 것들을 여기서 다 풀어내기는 어렵기 때문에 간략하게만 살펴보고 직접 예제를 구현하고 하나하나씩 바꿔나가보면서 공부해야 할 것 같다.