1. 빌드 시간, 테스트 시간이 길어진다.
처음에는 전혀 문제가 되지 않던 빌드와 테스트가 서비스가 커짐에 따라 점점 오래 걸립니다.
CI / CD (지속적 통합 / 지속적 배포)가 강조되고 있고, 페이스북 같은 경우는 하루에도 수십 번을 프로덕션에 배포를 한다고 합니다. (참고)
CI / CD란
CI/CD는 애플리케이션 개발 단계를 자동화하여 애플리케이션을 보다 짧은 주기로 고객에게 제공하는 방법입니다. CI/CD의 기본 개념은 지속적인 통합, 지속적인 서비스 제공, 지속적인 배포입니다. CI/CD는 새로운 코드 통합으로 인해 개발 및 운영팀에 발생하는 문제(일명 "통합 지옥(integration hell)")를 해결하기 위한 솔루션입니다.
특히, CI/CD는 애플리케이션의 통합 및 테스트 단계에서부터 제공 및 배포에 이르는 애플리케이션의 라이프사이클 전체에 걸쳐 지속적인 자동화와 지속적인 모니터링을 제공합니다. 이러한 구축 사례는 “CI/CD 파이프라인”이라 부르며 개발 및 운영팀의 애자일 방식 협력을 통해 지원
2. 개발 언어에 종속적이다.
상황에 맞게 기술을 유연하게 적용하지 못합니다. Java + Spring으로 구현이 되어있다면, 선택의 여지없이 Java + Spring으로 구현을 해야 합니다.
3. 선택적으로 확장할 수 없다.
이벤트 서비스와 주문 서비스의 사용률 90 : 10이더라도, 원하는 서비스만 확장할 수 없고, 프로젝트 하나를 통째로 확장해야 합니다.
4. 하나의 서비스가 모든 서비스에 영향을 준다.
하나의 서비스에 문제가 생기면 Monolithic은 구조상 모든 서비스에 영향을 줄 수밖에 없습니다. 이벤트 서비스에 트래픽이 몰려 해당 서버가 죽게 된다고 가정을 해보겠습니다.
Monolithic에서는 하나의 서버에 모든 서비스가 있기 때문에 하나의 서비스의 트래픽 폭주로 인해 다른 서비스도 마비되는 상황이 옵니다.
100명 정도가 모여 하나의 앱을 서비스한다고 가정해보자. 하나의 앱이므로 monolithic하다는 것은 하나의 프로젝트에 모든 기능을 담고 서빙하는 것으로 생각하면 된다. 하나의 레포지터리에 100 명의 개발자가 붙어서 여기저기 수정하고 배포한다면 어떨까?
마이크로 서비스 아키텍처 스타일은 단일 응용 프로그램을 나누어 작은 서비스의 조합으로 구축하는 방법이다.
이전에 본 Monolithic으로 구현된 프로젝트입니다. MSA로 변경하게 되면
1. 빌드 및 테스트 시간을 단축시킬 수 있다.
30개의 서비스를 가진 Monolithic 의 빌드 시간이 30분이었다면, MSA는 각각의 서비스를 1분 만에 빌드 할 수 있습니다. 이는 CI / CD를 추구하는 기업에서는 좀 더 적합한 모델이 됩니다. 왜냐하면 하루에도 몇 번을 빌드 및 배포를 해야 하는데 그때마다 많은 시간을 소모하게 된다면 낭비이기 때문입니다.
2. 폴리글랏 아키텍처 구성이 가능하다.
상황에 맞게 기술을 유연하게 적용할 수 있습니다. 예를 들어 TPS(시간당 트랜잭션)가 높고, 읽기 작업이 많은 서비스에는 Node + Redis로 구현을 하고, 트랜잭션 및 안정성이 중요한 서비스에는 Spring + RDB를 적용할 수 있습니다.
플리글랏 아키텍처
미국 개발자들 사이에서 ‘폴리글랏 프로그래밍’은 하나의 대세가 되었다. 폴리글랏(polyglot)은 여러 언어를 구사하는 것을 말한다. 즉, 폴리글랏 프로그래밍은 ‘패러다임을 달리 하는 여러 개발 언어를 자유롭게 구사하는 것’이라고 할 수 있다.
일반적으로 프로그래머는 하나의 언어를 배우게 된다. 하나의 언어를 배우면서 문법이나 API만 배우는 것이 아니라, 패러다임이나 아이디어까지 함께 배운다. 여러 개의 프로그래밍 언어를 배운다는 것은 그만큼 다양한 패러다임을 접하고, 많은 아이디어를 만들 수 있는 기반을 다진다는 뜻이다. 다양한 패러다임과 많은 아이디어는 개발자가 직면한 다양한 문제를 해결하는데 도움이 된다.
TPS
Transaction Per Second(TPS)는 초당 트랜잭션의 개수입니다. 실제 계산하는 방식은 일정 기간 동안 실행된 트랜잭션의 개수를 구하고 다시 1초 구간에 대한 값으로 변경합니다
3. 탄력적이고 선택적인 확장이 가능하다.
MSA는 작은 단위의 작업이라 필요한 서비스만을 선택적으로 확장할 수 있습니다. 만약, 주문 서비스와 이벤트 서비스의 사용률이 90 : 10 이라면 이벤트 서비스만을 선택적으로 확장(scale out) 할 수 있습니다.
4. 하나의 서비스가 다른 서비스에 영향을 주지 않습니다.
이전 글처럼 책을 무료로 주는 이벤트를 한다고 가정을 해보겠습니다. 이벤트 서비스에 트래픽이 몰려 해당 서버가 죽더라도 다른 서비스에는 영향이 가지 않습니다. 각 서버마다 서비스를 놓기 때문이죠.
물론, 죽은 서비스를 타 서비스가 호출하게 되면 문제는 생깁니다. 이는 Circuit Breaker에서 좀 더 알아보도록 하겠습니다.
- 성능 이슈가 있다.
Monolithic은 다른 서비스 간의 상호작용이 필요할 시에는 Method 호출을 이용합니다. 즉 이러한 행위는 메모리 안에서 일어나죠. 그러나 MSA와 같은 경우에는 주로 HTTP를 사용합니다. 이는 Network IO를 통하여 다른 서버까지 갔다 다시 와야 됨을 의미합니다. '첫 번째 문제점이 성능이라니...'라고 생각이 들 법도 하지만 요즘은 하드웨어나 기술이 많이 발전했고 성능보다는 유지 보수에 좀 더 무게중심을 둔다는 점을 미뤄볼 때, 개인적으로는 Client가 크게 체감하지 못할 정도면 MSA의 장점에 좀 더 손을 들어줘도 될 거 같습니다.
2. 트랜잭션이 불편하다.
Spring에서는 @Transactional이라는 어노테이션하나만 달아주면 자동적으로 트랜잭션 처리를 해줍니다. 그러나 서비스가 각각으로 나뉘게 되면 불편함이 따르긴 합니다. 그래서 MSA에서는 서비스 간에 Global 트랜잭션이 일어나는 상황보다는 Local 트랜잭션이 주로 이루어지게 경계를 나누고, 불가피하게 서비스 간에 트랜잭션이 필요하면 트랜잭션 로직을 추가합니다.
3. 관리 포인트가 늘어난다.
Monolithic은 간단한 경우 어플리케이션서버와 DB 서버 두 개를 관리하면 되지만, MSA에서는 기본적으로 서비스 수 * 인스턴스만큼의 서버 (경우에 따라 DB)가 존재하고 서버가 늘어난 만큼 로깅, 모니터링, 배포, 테스트, 클라우드 환경에서의 관리들은 부담스럽습니다. 이러한 문제는 관리에 들어가는 비용을 줄이기 위해 자동화와 간단하게 모니터링할 수 있는 환경을 권장합니다.
spring boot admin - 모니터링
jenkins - 테스트, 빌드, 배포 자동화 (CI)
MSA의 경계의 기준
- 자율적인 기능
- SRP
- 배포 단위의 크기
부연설명
- 관리할 수 있는 수준 이내로 유지할 수 있어야 함
- 서브도메인
- 폴리글랏 아키텍처
- 선택적 확장
부연설명
- 모든 기능 모듈이 모두 동일한 수준의 확장성을 필요로 하지는 않는다
- 확장에 관한 요구사항을 기준으로 마이크로서비스의 경계를 결정
- 자원소모량, 소유비용, 비즈니스 효용성, 유연성 등이 분석 기준
- 작고 애자일한 팀
부연설명
- 전체 중에서 서로 다른 일부를 개발하는 데 집중할 수 있는 작고 집중력 있는 팀 구성을 통해 애자일 방식의 개발을 가능하게 해준다
- 트랜잭션
서비스간의 상호작용은 어떻게 이뤄져야 할까?
주문이 일어날 때는 간략하게 유저와 책 정보를 주문 테이블에 넣고, 배송 서비스에 유저와 책에 대한 정보까지 전달을 합니다. 유저, 책은 동기적으로 일어나야겠지만 배송은 비동기적으로 일어날 수 있습니다.
동기 : REST/JSON
비동기 : MQ 프로토콜
MSA가 다른 Architecture과 마찬가지로 모든 상황에 적합한 것은 아닙니다. 각 기업마다 갖가지 상황이 존재할 것이고, 이를 기반으로 뭐를 내주고 뭘 얻을 것인지 이해타산을 잘 따져야 합니다. 특히 상황에 맞는 설계가 가장 중요할 것 같습니다
가령. Monolithic을 메인으로 삼고 유연성이 필요한 서비스들만을 분리하는 것도 하나의 방법이 됩니다.
대규모의 복잡한 기능을 서빙하는 수십, 수백명의 개발자가 달려들어야 하는 서비스를 만드는 것이 아니라면 MSA는 오히려 개발을 더 복잡하게 만들 수 있다. Monolithic architecture와 MSA가 내게 필요한 순간인지를 알아야 한다.