앞선 챕터까지해서 Monolithic 구조였던 개인 프로젝트를 MSA 구조로 전환해보는 전환기의 기술적인 부분은 마치고,
이번 챕터에서 MSA 전환 후 비교 및 느낀점을 통해 전환기 기록을 마무리하려고 합니다! 🙃🙃
최종적으로 마무리한 제 개인 프로젝트의 MSA Flow는 다음과 같습니다! 😁
- Eureka Server에 API Gateway, Config Server를 포함한 모든 마이크로 서비스 등록 후 관리
- Config Server에 각 마이크로 서비스의 프로필별 설정 파일 등록 (Github Private Repository에 등록 후 Load)
- API 요청 시 API Gateway가 라우팅할 마이크로 서비스 판단 후 Eureka Server에 등록된 마이크로 서비스로 요청
- 마이크로 서비스 간의 통신은 OpenFeign으로 처리
- 그림에는 없지만, 요청 실패 시 Circuit Breaker 패턴 및 Fallback, Bulkhead를 구현을 통해 실패 후 처리 OK
1. 전환 후 느낀 MSA의 장점
앞서 챕터 1에서 MSA가 무엇인지를 살펴봤을 때 간단하게 MSA의 장점을 모놀리식 구조와 함께 비교해봤었습니다.
이전에 MSA 구조를 경험하기 전에 이론적으로 언급했었던 MSA의 장점은 다음과 같았습니다.
- 도메인 하나의 장애가 서비스 전체에 전파되지 않는다.
- 모놀리식 구조에 비해 상대적으로 각 도메인의 유지보수가 쉽다.
- 빌드 및 배포 시간을 줄여서 생산성을 높일 수 있다.
- 도메인별로 Scale-out이 쉽다.
위의 경험해보기 전에 생각했었던 장점들을 경험하면서 어떻게 느꼈는지 기록해보겠습니다.
1-1. 도메인 하나의 장애가 서비스 전체에 전파되지 않는다.
MSA 구조를 경험해보기 전에는 여러 도메인이 하나의 프로젝트로 구성되어 있는 모놀리식 구조를
각 도메인으로 분리하는 MSA 구조로 전환하면 각 도메인이 분리된 환경을 가지니, 장애 전파도 이루어지지 않을 것이라고 생각했습니다.
이러한 생각은 MSA 전환을 경험해보니 부분적으로 맞는 말이었고, 다음과 같이 정리할 수 있습니다.
- 기존 모놀리식 구조에서 연관관계가 없었던 도메인이면, 장애가 전파되지 않는다.
- 기존 모놀리식 구조에서 연관관계가 있던 도메인이면, 장애가 전파될 수 있다.
- 장애가 전파되지 않게 하기 위해서는 Circuit Breaker 패턴을 별도로 구현해야하는 리소스가 든다.
저의 프로젝트에서 Member와 Board 도메인의 관계를 생각해보면 모놀리식 구조에서 1:N으로 관계를 맺고 있었습니다.
그래서 MSA 구조로 전환했을 때 해당 연관관계가 끊기면서,
애플리케이션 단에서나 요청 단에서 그에 따른 적절한 처리를 해줘야했습니다.
제가 선택한 각각의 처리는 다음과 같았습니다.
- Application 단의 처리 : 엔티티 간접 참조 대신 Snapshot 엔티티 생성하여 참조
- 요청 단의 처리 : OpenFeign을 통해 Member 마이크로 서비스로 요청
이렇게 처리하는 과정에서 OpenFeign이라는 요청 기술을 사용함에 따라서 해당 지점이 장애 전파 지점이 될 수 있었습니다.
직접적인 연관관계는 끊어서 독립적인 마이크로 서비스는 구축되었지만,
OpenFeign 요청이 실패하면 해당 서비스도 장애가 발생하는 문제가 발생했었습니다.
이러한 상황에서 Circuit Breaker 패턴 및 Fallback을 사용해서 장애 전파를 막았지만 별도의 리소스가 드는 것을 알 수 있었습니다.
저는 생각해봤을 때 실무에서는 거의 대부분의 도메인들이 연관관계를 맺고 있다고 생각했기 때문에 단순히 MSA로 전환하기만 해서
장애 전파가 되지 않는다는 것은 불가능하다고 느끼게 되었습니다.
하지만 모놀리식 구조에서는 아예 장애 전파를 막는 것이 불가능하기 때문에 MSA 구조의 장점은 맞다고 생각합니다.
따라서 '도메인 하나의 장애가 서비스 전체에 전파되지 않는다'는 장점을 정리해보면 다음과 같이 말할 수 있을 것 같습니다.
'Circuit Breaker 패턴'을 사용하면 다른 마이크로 서비스로의 장애 전파를 막을 수 있다.
그래서 별도의 리소스가 들긴 하지만 모놀리식 구조에서는 장애 전파를 막는 것이 불가능하기 때문에 충분히 장점인 것 같다.
1-2. 모놀리식 구조에 비해서 상대적으로 각 도메인의 유지 보수가 쉽다.
단순히 모놀리식 구조와 MSA 구조의 측면에서 벗어나서 다음과 같은 말을 주변에서 많이 들었던 기억이 있습니다.
도메인 간 강결합을 하게 되면 유지보수가 어렵다.
이런 말을 들었을 때, 유지보수 경험이 적어서인지 유지 보수를 위한 도메인 간 강결합 분리는 사실 저에게 와닿지 않았었습니다.
저는 도메인 간 강결합을 분리하기 위해서 '스프링 이벤트'를 사용해서 분리한 적이 있습니다.
하지만 그때도 분리 목적은 '유지보수를 쉽게 하기 위해'가 아닌 '의미적으로 도메인이 알 필요 없는 도메인을 참조하기 때문'이었습니다.
제가 했던 오해? 아닌 오해의 사고 과정을 제 프로젝트로 예를 들면 다음과 같았습니다.
단순하게 Board 도메인이 Member 도메인을 의존해서 강결합이 되는게 그렇게 유지보수성이 안 좋나?
결합이 적은게 변경점을 해당 도메인에서만 봐도 돼서 괜찮을 것 같은데, 결합 끊는게 그정도로 유지보수성을 높여주나?
두 도메인이 강결합을 가져도 변경점이 어디인지 그래도 빠르게 파악이 가능한게 아닌가?
결국 도메인 간 강결합을 끊을 때 항상 두 도메인을 대상으로만 작업을 해왔었기 때문에
저는 도메인 간 강결합을 위의 그림처럼 단순하게 두 도메인으로 예시를 들어서 항상 생각했었습니다.
하지만 이렇게 두 도메인이 아니라, 아래의 그림처럼 여러 도메인으로 생각을 넓혔을 때 해당 말의 의미를 깨닫게 되었습니다.
이처럼 여러 도메인 간 강결합을 가질 때는 어떤 도메인의 변경에 대해서 영향을 미치는 범위가 엄청나게 커져서
해당 변경에 영향을 받는 도메인과, 변경점들이 많아지고 변경점을 파악하기가 엄청나게 어려울 것 같다고 생각이 들게 되었습니다.
그래서 개발을 할 때 도메인 별로 결합을 끊지 않으면 스노우볼이 크게 굴러서 위와 같은 변경점이 많은 구조를 야기할 것 같았습니다.
이러한 측면에서, 도메인 간 강결합을 가질 수 있는 모놀리식 구조에서 MSA로 전환 시에는
마이크로 서비스 간 통신을 할 때의 논리적? 참조 이외에는 아예 결합이 없는 독립된 마이크로 서비스로 구성되므로
확실히 코드 단의 유지보수 측면에서 MSA가 유리할 것이라고 생각이 들었습니다.
여러 도메인이 존재하는 실무에서 하나의 기능이 변경되었을 때 독립된 마이크로 서비스 내에서 코드를 변경하는 것과
여러 도메인이 연관되어 있는 종속적인 모놀리식 구조에서 코드를 변경하는 것을 생각해봤을 때,
고려할 요소들이 MSA 구조가 더 적은 느낌을 받을 수 있었습니다.
1-3. 빌드 및 배포 시간을 줄여서 생산성을 높일 수 있다.
이는 간단하게 빌드 시간을 수치와 그림으로 표현하면 더 쉽게 이해할 수 있습니다.
아키텍쳐별 빌드 시간 측정 결과, 모놀리식 구조와 MSA 구조에서의 빌드 시간은 다음과 같았습니다.
(프로젝트는 실제 배포 환경까지는 구성하지 않고 로컬에서만 전환했기 때문에 배포 시간은 기록에서 제외하겠습니다!)
- 모놀리식 구조(Member + Board) 빌드 시간 : 14s
- MSA 구조 빌드 시간
- Member-Service : 4s
- Board-Service : 6s
※ 총 빌드 시간 비교
하나의 프로젝트를 처음 배포한다고 가정하고, 모든 서비스의 빌드 과정이 진행되는 시나리오일 때
총 빌드 시간으로 비교를 해봤을 때는 다음과 같은 결과를 도출할 수 있습니다.
- 모놀리식 구조 총 빌드 시간 : 14s
- MSA 구조 총 빌드 시간 : 4s + 6s = 10s
이렇게만 비교해봤을 때는 4s 정도는 별 차이 안 나지 않나? 라고 생각할 수 있습니다.
이러한 무의미한 차이는 제 프로젝트의 규모가 작기 때문이라고 생각합니다.
서비스의 규모가 커서 기존 모놀리식 구조에서 도메인 자체가 많고,
여러 연관관계를 맺고 있었다면 훨씬 유의미한 결과가 도출되었을 것 같습니다.
※ 서비스별 빌드 시간 비교
배포 후에, 리팩토링을 거친 코드만 빌드하여 배포하는 상황을 가정하고, 하나의 서비스의 빌드만 진행되는 시나리오일 때
멤버 서비스를 기준으로 빌드 시간으로 비교를 해봤을 때는 다음과 같은 결과를 도출할 수 있습니다.
- 모놀리식 구조에서의 총 빌드 시간 : 14s
- MSA 구조 총 빌드 시간 : 4s
이러한 차이 또한 마찬가지로 10s 정도는 무의미한 차이라고 생각할 수 있습니다.
이는 앞서 본 상황과 마찬가지로 제 프로젝트의 규모가 작기 때문이라고 생각합니다.
실제로 우아콘 2023의 '모놀리식에서 점진적 서비스 분리' 세션에서도 개별 빌드 시간이 10배 이상 줄었다고 언급한 것으로 보아,
서비스가 크다면 유의미한 결과가 있는 것을 알 수 있습니다.
서비스가 확장된다고 생각해보면 차이는 확연하게 커지는 것을 알 수 있습니다.
도메인이 많아질 때마다 모놀리식 구조는 선형적으로 빌드 시간이 증가할 것이지만,
MSA 구조에서는 각 마이크로 서비스 별로 독립된 빌드를 진행하기 때문에 영향을 받지 않고 빌드 시간이 증가하지 않을 것입니다.
예를 들어, 모놀리식 구조의 도메인 1개당 빌드 시간이 5s라고 했을 때 10개 도메인 추가 후 멤버 빌드 상황을 생각해봅시다.
이때, 모놀리식 구조의 빌드 시간은 모든 도메인이 빌드되기 때문에 14s + 추가한 도메인 빌드 50s = 64s가 걸릴 것입니다.
하지만, MSA 구조에서는 멤버 마이크로 서비스가 독립적으로 구성되어있기 때문에 빌드 시간은 그대로 4s가 걸릴 것입니다.
이처럼 서비스 확장 시에 빌드 및 배포 시간 단축으로 인한 생산성이 훨씬 더 높아질 것이라고 생각합니다.
1-4. 도메인별로 Scale-out이 쉽다.
이 부분의 장점은 마이크로 서비스들이 독립적으로 배포되면서 얻을 수 있는 장점입니다.
제 프로젝트에서 모니터링 시 Member와 Board 중에 Board 트래픽이 Member보다 3배 이상 몰리는 것을 확인했다고 해봅시다.
이때, 모놀리식 구조에서는 Scale-out 시에 모든 도메인을 통째로 Scale-out 해야합니다.
따라서 리소스 측면에서도 상당히 비효율적임을 알 수 있습니다.
반면 MSA 구조에서는 독립된 Board 마이크로 서비스만 Scale-out 하여 배포하면 되기 때문에
리소스 측면에서 훨씬 효율적이고 쉽게 배포가 가능한 것을 알 수 있습니다.
이 부분은 로컬 환경에서 전환이 끝나고 실제 배포 환경은 경험하지 못했기 때문에 경험할 수 없었지만,
이론적으로도 충분히 생각 가능한 장점이라고 생각합니다.
2. 전환 후 느낀 MSA의 단점
이번에는 MSA로 전환 후에 느낀 MSA의 단점을 기록해보려고 합니다!
현재 전환 후에 제가 느낀 MSA의 단점은 다음과 같습니다.
- 전환 리소스가 예상했던 것보다 훨씬 많이 든다.
- 서비스별로 격리되면서 유지보수 시 커뮤니케이션 리소스가 추가적으로 발생할 것 같다.
- 테스트 시 추가 리소스가 발생한다.
- 서비스 관리 및 운영 측면의 유지보수는 더 어려워질 것 같다.
2-1. 전환 리소스가 예상했던 것보다 훨씬 많이 든다.
MSA로의 전환을 경험하고 나서 든 생각은, 다음과 같았습니다.
처음 보는 기술이 너무나도 많고 고려할 점이 너무나도 많고 어렵다 😭
MSA 전환을 경험해보지 않은 입장에서 MSA 전환에 사용되는 기술들과 고려할 점은 다음과 같았습니다.
- MSA 전환에 사용한 기술들
- 멀티 모듈
- Spring Cloud 기술들
- Spring Cloud Eureka
- Spring Cloud Gateway
- Spring Cloud OpenFeign
- Spring Cloud Config
- Spring Cloud Contract WireMock
- Apache Kafka
- MSA 전환 고려한 점
- 서비스 간 통신 시 장애 대응 : Circuit Breaker 패턴, Fallback, Bulkhead 사용(Resilience4J)
- 분산 트랜잭션 처리 : 2PC, Saga 패턴, Kafka
- 서비스 간 통신 테스트 처리 : WireMock 사용
이렇게 엄청나게 많은 리소스가 들어간 것을 알 수 있습니다.
저는 멀티 모듈 환경 이외에는 모두 다 처음 접한 기술, 개념들이라서 상당히 어렵고 시간이 오래 걸리게 되었습니다.
또한 전환을 배포 환경까지 마무리한 것이 아니라 로컬 환경까지밖에 안했는데도 이렇게 리소스가 많이 드는 것으로 보아
배포 환경까지 전환하고 운영할 때도 전환 리소스가 발생하므로 총 전환 리소스가 엄청나게 크다고 생각하게 되었습니다.
2-2. 서비스별로 격리되면서 유지 보수 시 커뮤니케이션 리소스가 추가적으로 발생할 것 같다.
MSA로 전환하면서 도메인 간의 결합도가 낮아져서 결합도 측면의 유지보수성이 좋아진 것은 맞지만,
실무 환경을 생각해봤을 때 커뮤니케이션 리소스가 추가적으로 발생할 것 같다고 생각이 들었습니다.
서비스 규모가 큰 실무 환경에서는 도메인별로 팀이 나눠져있다고 많이 들었었습니다.
그래서 실무 환경이라면 도메인별로 회원팀, 게시글팀 이렇게 나뉘어질 수 있을 것 같습니다.
이러한 상황에서 MSA 구조로 전환이 되면, 각자 도메인 개발 시 자신의 도메인 개발에 더욱 집중이 되기 때문에
서비스 운영 시에 점점 유지보수가 되어 도메인별 컨텍스트가 달라졌을 때 해당 컨텍스트를 실시간으로 공유하기가 힘들어질 것 같습니다.
따라서 서비스 전체 또는 작업하는 기능의 다른 도메인 컨텍스트 이해를 위해서
추가적인 커뮤니케이션 리소스가 들 수 있을 것 같다는 생각이 들었습니다.
2-3. 테스트 시 추가 리소스가 발생한다.
모놀리식 구조에서는 도메인 간에 연관관계를 맺고 있었기 때문에 다른 도메인 간의 상호작용은 메소드 콜이었습니다.
하지만 MSA 구조로 전환되면서 서비스 간의 통신이 네트워크 통신을 수반하기 때문에 테스트 또한 추가적인 리소스가 필요했습니다.
일부 객체를 Mocking 하는 것이 아닌, 실제 통신을 Mocking하기 위해 Mock Server를 띄워야 하고
또 Spring Cloud Contract와 같은 별도의 라이브러리도 필요하게 되었습니다.
이렇게 테스트 시 추가 리소스가 발생하는 점이 단점이라고 생각합니다.
2-4. 서비스 관리 및 운영 측면의 유지보수는 더 어려울 것 같다.
이 부분은 배포를 하지 않아서 경험하진 못했지만, 모놀리식 구조와 MSA 구조의 운영을 비교해보겠습니다.
- 모놀리식 대비 MSA 구조에서 관리 컴포넌트(서비스)가 1개에서 여러 개로 늘어난다.
- 서비스가 분리됨에 따라서 로깅 및 모니터링 환경이 분산되고 그에 따라 에러 추적 및 트러블 슈팅이 힘들다.
- 이는 분산된 로깅 및 모니터링을 한 곳에서 관리하는 기술을 사용하면 된다고 하는데, 이 또한 리소스가 발생한다.
이러한 측면에서 서비스 운영 시에는 모놀리식 구조보다 더 많은 리소스가 발생하고 유지보수가 어려운 단점이 있는 것 같습니다.
3. 회고 및 후기
이제, 길고 길었던 모놀리식 구조를 MSA 구조로 전환한 후기? 회고?를 적으면서 전환기를 마무리해보겠습니다.
좋았던 점
- 귀로 듣기만 했던 MSA를 코드로, 손으로 직접 경험해봤다는 것이 좋았습니다.
- 원래 경험하지 않으면 절대 이해가 안되는 성격이라서 처음 경험하는 것은 한번 경험해보는 것이 개인적으로 중요하다고 생각하는데, MSA를 직접 경험해봤다는 점이 뜻깊은 것 같습니다.
- 아직 경력이 없는 신입이라서 당장 MSA 환경에서 개발할 것 같지는 않지만, 개발자로 취업한다면 한번쯤은 MSA 환경을 경험할 것이라고 생각하기 때문에 그때 이번 경험이 많이 도움이 될 것 같습니다.
- 처음 사용해보는 기술들을 직접 적용하는 연습을 할 수 있어서 좋았습니다.
- MSA에 국한되지 않고 앞으로 개발자로 일하면서 많은 새로운 기술들을 접할 텐데, 새로운 기술을 접하더라도 잘 적용할 수 있겠다는 자신감이 생긴 것 같습니다.
- 개인적으로 기나 긴 적용기를 블로그에 기록했다는 점이 뿌듯합니다.
- 기록하지 않았다면 단순 경험으로 머릿속에만 남을텐데, 모든 과정을 기록함으로써 평생 남는 글로 존재한다는 것이 뿌듯한 것 같습니다.
- 시간이 좀 지나서 '이때 어떻게 이렇게 기록했지..?'라고 추억할 수도 있을 것 같습니다 ㅎㅎ
아쉬운 점
- 깊은 Depth로 기술들을 적용한 것 같지는 않아서 아쉽습니다.
- 여러 기술을 사용했었는데 다 어떤 기술인지 정도만 이해하고 더 나아가지는 못한 것 같아서 아쉽습니다.
- 하지만, 아예 처음 보는 기술이기도 했고 물리적으로 시간이 많았던 것도 아니라서 어쩔 수 없었다고 생각합니다.
- 다만 다음에는 처음 보는 기술이라도 하나 기술만 깊게 파보는 경험을 해보고 싶다는 생각을 했습니다.
- 서비스를 배포 환경까지 전환한 것은 아니라서 아쉽습니다.
- 앞서 몇 번 언급했듯이 로컬 환경까지만 전환을 진행했는데, 배포까지 진행했다면 더 많은 어려움 속에서 더 많은 인사이트들을 얻을 수 있을 것 같았는데 시간이나 환경 상 진행하지 못한 부분이 아쉽습니다.
🎯 Github Repository 링크 (전체 코드)
https://github.com/sh111-coder/sh-board-msa
📘 Monolithic to MSA 전체 목차
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (1) MSA란?
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (2) 멀티 모듈 구성하기
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (3) Service Discovery 패턴 적용하기(feat. Spring Cloud Eureka)
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (4) API Gateway 구현(feat. Spring Cloud Gateway)
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (5) 서비스 간 통신하기(feat.Spring Cloud OpenFeign)
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (6) 각 서비스의 설정 파일 관리하기(feat. Spring Cloud Config)
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (7) 서비스 장애 대응 Circuit Breaker 구현(feat. Resilience4J)
[MSA] 개인 프로젝트 Monolithic to MSA 전환기 - (10) MSA 전환 후 비교 및 회고 + 마무리