- 마이크로서비스를 기본값처럼 도입하는 문화는 실제 규모 문제가 아니라 없는 문제를 풀기 위해 비용과 복잡도를 키워 왔다는 비판임
- JavaScript/Node.js 생태계의 폐쇄성, FAANG식 관행, 풍부한 벤처 자금이 맞물리며 스타트업도 web-scale 아키텍처를 흉내 내는 분위기가 생김
- Docker와 Kubernetes가 있어도 개발, 디버깅, 배포, 테스트, 회복력 확보 같은 분산 시스템의 난점은 사라지지 않음
- Dropbox, Twitter, Netflix, Facebook, GitHub, Instagram, Shopify, StackOverflow, WhatsApp 등은 모놀리식 코드베이스로 시작했거나 지금도 핵심에 모놀리스를 두고 있음
- 대부분의 회사는 진짜 분산 시스템이 필요한 규모에 도달하지 않으므로, 명확히 분리·확장해야 하는 부하가 있을 때만 서비스로 떼어내는 편이 현실적임
복잡도를 숭배하는 문화
- 사용자 생일 하나를 얻기 위해 복잡한 마이크로서비스 미로를 설명하다 실패하는 풍자는 현재 기술 문화의 과잉 설계를 겨냥함
- 당면 과제를 푸는 대신 없는 문제를 해결하느라 돈을 태우는 쪽으로 목표가 바뀐 것이 문제임
- JavaScript와 Node.js 비판은 특정 기술만의 문제가 아니라, 이미 배운 교훈을 다시 배우게 만드는 폐쇄적 소프트웨어 생태계의 위험과 연결됨
- 업계는 과거에도 CORBA와 SOAP 같은 복잡도 벽에 부딪힌 뒤 방향을 되돌린 경험이 있음
마이크로서비스 유행을 만든 조건
- 브라우저용 JavaScript를 쓰던 개발자들이 “full-stack”을 자처하며 서버 개발과 비동기 코드로 들어왔고, 초기 Node는 개인의 학습 프로젝트에 가까웠으며 초기 JavaScript는 서버 개발에 문제가 많은 선택지였음
- Node 바깥 세계가 사실상 없는 것처럼 받아들여지면서, Node 방식만이 유일한 방식이라는 독단적 사고가 생김
- 이후 FAANG 출신 인력들이 스타트업으로 들어와 “Google에서 하던 방식”을 맥락과 규모에 상관없이 정답처럼 전파함
- 별도
User Preferences Service가 없으면 확장되지 않는다는 식의 압박이 대표적 예시임
- 별도
- 벤처 자금이 풍부하던 시기에는 매출보다 투자자에게 폭발적 성장을 보여주는 일이 중요해졌고, 회사는 비싼 소프트웨어 엔지니어를 빠르게 채용해 “무언가”를 하게 만들었음
분산 시스템은 여전히 어렵다
- 마이크로서비스는 “확장 가능한 소프트웨어를 쓰는 새 방식”처럼 포장됐지만, 본질적으로 오래전부터 존재한 분산 시스템 문제와 맞닿아 있음
- 과거의 분산 시스템은 어렵고 위험한 도구로 여겨졌고, 특히 까다로운 문제를 위한 마지막 수단에 가까웠음
- 분산 시스템에서는 다음 작업이 모두 더 어렵고 오래 걸림
- 개발
- 디버깅
- 배포
- 테스트
- 회복력 확보
- 마이크로서비스 기반 개발에는 표준 도구나 공통 프레임워크가 없으며, 2020년대에도 분산 시스템 작업은 조금 쉬워졌을 뿐임
- Docker와 Kubernetes는 분산 설정의 본질적 복잡도를 마법처럼 제거하지 못함
단순함이 더 좋은 결과를 낸 사례
- 5년간의 스타트업 코드 감사 요약은 잘된 스타트업일수록 거의 뻔뻔할 정도로 Keep It Simple 접근을 취했다고 정리함
- 조기 마이크로서비스 전환, 분산 컴퓨팅에 의존한 아키텍처, 메시징 중심 설계는 여러 회사를 곤란하게 만든 주요 함정이었음
- 많은 스타트업은 단순하고 성능 좋은 시스템을 만들면서도 “첫날부터 마이크로서비스를 하지 않는다”는 데 가짜 열등감을 느낌
- “몇 명의 엔지니어가 유지하는 Django 모놀리스와 MySQL 인스턴스뿐인데 무엇이 잘못됐나”라는 질문의 답은 거의 항상 “잘못된 것이 없다”임
- 경험 많은 엔지니어도 오늘날의 기술 문화에서 부적절함을 느끼지만, 실제 문제는 부당한 과신과 낭비, Dunning-Kruger가 섞인 환경일 수 있음
모놀리스로도 성장한 회사들
- 모놀리스 없이는 성장할 수 없다는 생각은 신화에 가까움
- Dropbox, Twitter, Netflix, Facebook, GitHub, Instagram, Shopify, StackOverflow 등은 모놀리식 코드베이스로 시작했으며, 일부는 지금도 핵심에 모놀리스를 유지함
- StackOverflow는 대형 사이트를 적은 하드웨어로 운영하는 점을 성능 페이지에서 자랑거리로 삼음
- Shopify는 여전히 Rails 모놀리스를 사용하며, 검증된 Resque로 수십억 개 작업을 처리함
- WhatsApp은 Erlang 모놀리스와 약 50명의 엔지니어로 크게 성장함
- 엔지니어링 조직을 약 50명으로 작게 유지함
- 개별 팀은 1~3명 규모이며 높은 자율성을 가짐
- 서버는 적은 수를 선호하고 각 서버를 가능한 한 수직 확장함
- Instagram은 12명 규모 팀으로 수십억 달러에 인수됐고, Threads도 Instagram 모델을 따름
없는 문제를 풀지 말아야 함
- 핵심 질문은 “어떤 문제를 해결하는가”임
- 규모가 문제라면 무엇을 왜 별도 서비스로 나눠야 하는지 보여주는 데이터가 필요함
- 분산 시스템은 규모와 회복력을 위해 만들어지지만, 서비스 하나가 느려지거나 죽었을 때 다른 서비스로 트래픽이 몰리는 상황까지 고려해야 함
- 필요한 고려 요소는 시스템의 사용 패턴과 부하 특성에 따라 달라짐
- 백프레셔
- 서킷 브레이커
- 큐
- 지터
- 모든 엔드포인트의 합리적 타임아웃
- 작은 변경이 전체 장애를 만들지 않도록 하는 보호 장치
- 대부분의 회사는 진짜 분산 시스템이 필요한 거대한 규모에 도달하지 않음
- Amazon과 Google의 규모, 전문성, 자원을 갖추지 않은 채 그 방식을 흉내 내면 시간과 돈을 낭비하기 쉬움
- 나쁜 분산 시스템은 분산 시스템 자체보다 더 어렵다는 경고가 남음
팀별 서비스와 API라는 이상과 현실
- 회사 구조에 분산 토폴로지를 맞추려는 시도는 문제를 작은 조각으로 나누면 쉬워진다는 생각에서 출발함
- 이상적인 마이크로서비스는 전담 팀이 엄격히 유지하고, 아름답고 하위 호환되는 버전 API 뒤에 숨으며, 다른 팀과 거의 소통하지 않아도 되는 형태임
- 현실에서는 Slack 채널이 릴리스, 버그, 설정 변경, 깨지는 변경, 공지로 넘쳐남
- 모두가 항상 모든 상황을 파악해야 하며, 이미 바쁜 팀이 여러 마이크로서비스를 어설프게 맡는 일이 흔함
- 사람의 이동에 따라 서비스 소유권도 바뀌며, 하나의 좋은 경주차 대신 여러 대의 형편없는 골프 카트를 만드는 상황이 됨
마이크로서비스가 잃게 만드는 것들
-
DRY의 약화
- 마이크로서비스는 기본적으로 DRY하지 않으며, 각 서비스에 중복 보일러플레이트가 들어감
- 작은 마이크로서비스에서는 배관 코드의 비중이 커져 평균 서비스 인스턴스가 제품 코드보다 “서비스” 코드에 가까워질 수 있음
- 공통 코드를 빼내려 해도 선택지는 모두 고통을 동반함
- 공통 라이브러리를 만들면 버전과 업데이트 전략을 정해야 함
- 모든 저장소에 정기적으로 pull request를 만들어 강제 업데이트할 수 있음
- 모노레포로 묶으면 그 자체의 문제가 생김
- 일부 코드 중복을 허용하거나, 팀마다 매번 바퀴를 다시 만들게 됨
-
개발자 경험의 악화
- 개발자 경험은 새 기능 개발이나 버그 수정에 필요한 마찰과 노력의 크기임
- 마이크로서비스 환경에서는 특정 작업에 어떤 서비스를 띄워야 하는지, 어떤 팀과 누구에게 무엇을 물어야 하는지 알기 위해 전체 시스템의 정신 지도가 필요함
- Spotify는 수많은 시스템과 서비스를 목록화하기 위해 Backstage를 만들었고, 이는 이 게임의 비용이 높다는 단서가 됨
- Spotify가 아닌 회사들은 자체 솔루션을 임시방편으로 만들게 되며, 견고성과 이식성을 기대하기 어려움
- 새 서비스를 시작하려면 자동화해야 할 항목도 많음
- GitHub/GitLab 개발자 권한
- 기본 환경 변수와 설정
- CI/CD
- 코드 품질 검사
- 코드 리뷰 설정
- 브랜치 규칙과 보호
- 모니터링과 관측성
- 테스트 하네스
- 코드형 인프라
- 여러 프로그래밍 언어를 쓰면 이 목록은 언어 수만큼 늘어남
- 이런 자동화를 다듬는 데는 몇 달이 걸릴 수 있으며, 제품을 만들지 도구를 만들지 선택해야 하는 상황이 됨
-
통합 테스트의 어려움
- 단일 서비스 테스트와 단위 테스트가 통과해도 각 커밋 뒤 핵심 경로가 여전히 유지되는지는 별개 문제임
- 분산 설정의 통합 테스트는 거의 불가능에 가까운 문제로 다뤄지며, 그 자리를 관측성이 대체하게 됐다고 봄
- 관측성은 새로운 산업 영역이 되었고, 비용뿐 아니라 개발자 시간도 요구함
- 관측성은 플러그인처럼 바로 작동하지 않으며, 카나리 릴리스와 기능 플래그 등을 이해하고 구현해야 함
- 문제를 쪼갠다고 해결이 쉬워지는 것이 아니라, 더 어려운 문제 묶음을 얻게 됨
모놀리스가 자동으로 좋은 코드는 아니다
- 모놀리스 옹호가 “모놀리스는 좋은 코드이고 마이크로서비스는 나쁜 코드”라는 뜻은 아님
- 현실에는 성급한 팀이나 평범한 팀이 만든 평범한 모놀리스가 많음
- 다만 분산 시스템은 대충 넘어간 부분, 나쁜 결정, 놓친 실패 모드에 훨씬 가혹함
- 항상 높은 수준으로 운영하지 않으면 분산 시스템에서는 대가를 치르게 됨
마이크로가 아니라 그냥 서비스면 충분할 수 있음
- 서비스가 꼭 “micro”일 필요는 없으며, 그냥 서비스로 충분한 경우가 있음
- 일부 스타트업은 함수마다 서비스를 만드는 수준까지 갔고, 검증되지 않은 카고 컬트가 얼마나 멀리 갈 수 있는지 보여줌
- 모놀리스로 시작하는 것은 명확한 선택지임
- “trunk & branches” 패턴도 여러 경우에 맞을 수 있음
- 핵심 기능은 “고기와 감자” 같은 메인 모놀리스가 담당함
- 명확히 식별 가능하고 별도 확장이 필요한 부하는 branch 서비스가 맡음
- CPU를 많이 쓰는
Image-Resizing Service는User Registration Service보다 별도 서비스로 더 말이 됨 - 초당 등록 수가 독립 수평 확장을 요구할 정도로 많은지 묻는 질문이 서비스 분리 판단 기준이 됨
유행의 후퇴와 현실적 선택
- 마이크로서비스 과열은 식어가는 것으로 보이며, 벤처 자금 흐름이 조여지면서 기업들이 더 상식적인 결정을 하도록 시장에서 조정되고 있음
- web-scale 문제가 없는데 web-scale 아키텍처에 돈을 쓰는 방식은 지속 가능하지 않음
- 뉴욕에서 필라델피아로 가야 한다면 복잡한 우주선을 만들기보다 90분짜리 Amtrak 기차표를 사는 편이 문제에 맞는 해법임