Monolith vs Microservices (초기선택, 전환신호, 전환비용)

소프트웨어 아키텍처를 설계할 때 Monolith와 Microservices는 가장 대표적인 두 가지 접근 방식입니다. Monolith는 하나의 통합된 애플리케이션으로 구성되어 모든 기능이 하나의 코드베이스에서 동작하는 구조이며, Microservices는 기능을 여러 개의 독립된 서비스로 분리하여 각각이 독립적으로 배포되고 운영되는 구조입니다.

처음 서비스를 만들 때 Microservices 구조로 시작하면 뭔가 더 "제대로" 하는 것 같은 기분이 들었습니다. 그런데 막상 해보니, 배포 파이프라인 잡는 것만으로 몇 주가 날아갔습니다. Monolith와 Microservices 중 어느 쪽이 낫냐는 질문은 사실 잘못된 질문입니다. 시스템이 어느 단계에 있느냐가 먼저입니다.

초기 단계, Monolith를 고집하는 데는 이유가 있다

Microservices를 처음부터 도입하는 게 맞다고 생각하는 분들도 있는데, 도메인 경계, 즉 서비스를 어떤 기준으로 나눌지가 명확하지 않은 상태에서 억지로 분리하면, 나중에 구조를 통째로 갈아엎어야 하는 상황이 생깁니다. 초반에 "결제"와 "주문"을 별도 서비스로 쪼갰다가 비즈니스 요구사항이 바뀌면서 두 서비스 사이에 의존성이 뒤엉켜버린 적이 있습니다. 결국 다시 합쳤습니다.

Monolith(단일 애플리케이션 구조, 즉 모든 기능이 하나의 코드베이스 안에서 동작하는 방식)는 초기에 분명한 장점이 있습니다. 코드 공유가 쉽고, 로컬에서 전체 시스템을 바로 띄울 수 있으며, 팀원 한 명이 전체 흐름을 머릿속에 넣고 다닐 수 있습니다. 트래픽이 적은 초반에는 확장성 문제도 거의 발생하지 않으니, 복잡성을 굳이 끌어들일 이유가 없습니다.

Martin Fowler도 이 점을 강조한 바 있습니다. "마이크로서비스 프리미엄"이라는 개념인데, Microservices는 분명히 비용이 따르고 그 비용을 감당할 수 있을 만큼 시스템이 성장했을 때 선택해야 한다는 시각입니다. 이와 관련한 내용은 출처: martinfowler.com에서 확인할 수 있습니다.

전환 신호, 느낌이 아니라 증상으로 판단

Monolith가 한계에 부딪히는 시점은 보통 "느낌"으로 오지 않습니다. 아주 구체적인 증상으로 옵니다. 막연히 "코드가 많아졌으니 슬슬 나눠야겠다"는 생각으로 전환을 시도했다가 오히려 더 복잡해진 경우를 주변에서 여럿 봤습니다.

경험상 전환을 진지하게 고려해야 하는 신호는 다음과 같습니다.

  1. 특정 기능 하나 때문에 전체 서비스가 느려지거나 다운되는 일이 반복된다. 예를 들어 대용량 파일 처리 모듈이 CPU를 독점해서 결제 API 응답까지 지연되는 상황.
  2. 작은 버그 수정 하나에도 전체 시스템을 다시 배포해야 해서, 배포 빈도를 줄이게 된다.
  3. 팀이 3~4개 이상으로 나뉘었는데, 모두가 같은 저장소(Repository)에서 작업하면서 머지 충돌이 일상이 되었다.
  4. 특정 모듈에 다른 언어나 프레임워크를 쓰고 싶은데 단일 코드베이스 구조가 발목을 잡는다.

이 중 하나라도 해당된다면 구조 전환을 검토할 시점입니다. 반드시 네 가지 모두 해당돼야 하는 건 아닙니다. 특히 배포 주기 문제는 조직 문화 전체에 영향을 미치기 때문에, 이것이 가장 강력한 신호라고 봅니다. 코드 품질은 리팩터링으로 개선할 수 있지만, 배포 공포심은 구조를 바꾸지 않으면 해결이 안 됩니다.

반대로 "팀원이 5명을 넘었다", "코드가 10만 줄을 넘었다" 같은 숫자 기준을 절대적으로 믿는 분들도 있는데, 실제로 써보니 이런 기준은 조직마다 너무 달라서 그대로 적용하기 어렵습니다. 상황을 보는 눈이 숫자보다 중요합니다.

전환 비용, 기술만의 문제가 아니다

Microservices(각 기능을 독립적으로 배포하고 운영하는 분산 서비스 구조)를 도입하면 해결되는 것만큼 새롭게 감당해야 할 것들이 생깁니다. 이걸 과소평가하는 경우가 정말 많습니다. 기술적인 준비보다 조직적인 준비가 훨씬 더 어려웠습니다.

기술적으로는 서비스 간 통신 방식(REST, gRPC, 메시지 큐 등)을 정해야 하고, 분산 트랜잭션(여러 서비스에 걸친 데이터 처리를 일관성 있게 유지하는 문제) 처리도 새롭게 설계해야 합니다. 하나의 DB에서 모든 걸 해결하던 방식에서 벗어나, 각 서비스가 자체 데이터 저장소를 갖는 구조로 바뀌면서 데이터 정합성 문제가 생깁니다. 분산 트레이싱(여러 서비스에 걸친 요청의 흐름을 추적하는 기술) 도구 없이는 장애 원인을 찾는 것 자체가 고통이 됩니다.

운영 비용도 선형적으로 늘어납니다. 서비스가 10개면 모니터링, 로깅, 알림 설정을 10번 해야 합니다. CI/CD 파이프라인(코드 변경을 자동으로 빌드, 테스트, 배포하는 자동화 흐름)도 서비스 수만큼 구성해야 하고, 이를 안정적으로 관리하려면 DevOps 전담 인력이 필요합니다. DevOps 역량이 부족한 조직에서 Microservices를 도입하면 오히려 시스템 안정성이 떨어지는 결과로 이어지는 경우를 여럿 봤습니다.

CNCF(Cloud Native Computing Foundation, 클라우드 네이티브 기술 생태계를 이끄는 국제 재단)의 조사에 따르면, Kubernetes 같은 컨테이너 오케스트레이션 도구를 도입한 조직의 상당수가 초기 운영 복잡성 증가를 가장 큰 어려움으로 꼽았습니다. (출처: CNCF Annual Survey 2023) 기술 자체보다 그 기술을 운영할 사람과 문화가 먼저라는 뜻입니다.

결국 Monolith에서 Microservices로의 전환은 "더 나은 구조로의 업그레이드"가 아니라 "다른 종류의 문제를 선택하는 것"에 가깝습니다. 어느 쪽이 절대적으로 옳다는 시각보다는, 지금 우리 팀이 어떤 문제를 더 잘 다룰 수 있는지를 먼저 점검하는 것이 현실적인 출발점이라고 생각합니다. 전환을 결정했다면 한 번에 다 바꾸려 하지 말고, 병목이 되는 서비스부터 하나씩 분리하는 Strangler Fig 패턴(기존 시스템을 점진적으로 교체해 나가는 방식)을 권합니다. 저는 그게 가장 덜 고통스러운 방법이었습니다.


관련 글

댓글

이 블로그의 인기 게시물

HTTP 메서드의 필요성 (GET과 POST, PUT과 DELETE, API 보안)

API 없는 세상의 불편함 (로그인 연동, 서비스 구조, 디지털 인프라)

API 이해하기 (서비스 연결, 시스템 협력, 디지털 구조)