
모듈형 모놀리스와 Streaming SSR로 완성한 당근 커뮤니티실의 영리한 생존기
당근의 눈부신 성장 이면에는 1,000만 MAU와 20,000 RPS라는 엄청난 트래픽 폭풍을 유연하게 받아내고 있는 숨은 시스템이 있습니다. 당근 커뮤니티실은 무분별하게 마이크로서비스로 찢는 대신, 코드 경계를 극한으로 관리하는 '모듈형 모놀리스'와 프론트엔드의 성능 체감을 혁신하는 'Streaming SSR'을 선택했습니다. 소수의 엔지니어로도 대규모 트래픽 속에서 복잡한 정책을 안정적으로 유지할 수 있었던 비결과 아키텍처 원칙을 가감 없이 공유합니다.
단순히 유행을 쫓아 MSA(마이크로서비스 아키텍처)를 도입하기 전에, 제한된 인적 자원으로 대규모 트래픽과 도메인 확장성을 잡고 싶은 백엔드 및 풀스택 엔지니어들에게 적극 추천합니다.
당근 커뮤니티 서비스는 1,000만 MAU 달성과 최대 20,000 RPS에 달하는 트래픽 급증을 겪으며 시스템 복잡성이 임계점에 도달했습니다. 또한 동네생활, 모임, 카페 등 각 서비스별로 상이한 지역성 및 인증 정책을 처리하면서 중복 코드와 결합도를 제어해야 하는 과제가 있었습니다.
여러 서비스의 백엔드 기능을 단일 코드베이스로 묶되 도메인 간 경계를 모듈화하여 제어하는 '모듈형 모놀리스(Modular Monolith)' 아키텍처를 채택하고, 웹앱 영역에는 초기 기동 성능 개선을 위해 Streaming SSR을 구현했습니다. 서버앱은 하나의 릴리스 단위로 배포하되 런타임 환경에서 api, worker, batch, console의 4개 프로세스로 실행 격리하였으며, OpenAPI 스펙 기반의 API Design-First 기법 및 자동화된 아키텍처 테스트를 통해 결합도와 호환성을 지속적으로 검증했습니다.
초기 100 RPS 수준에서 출발하여 대형 이벤트 및 지속적인 서비스 성장에도 무리 없이 최대 20,000 RPS를 안정적으로 처리하는 성과를 거두었습니다. 아울러 중앙화된 계약 관리와 모듈 간 분리를 통해 소수의 인원으로도 다수의 커뮤니티 서비스를 안정적이고 효율적으로 유지보수할 수 있는 개발 및 운영 환경을 구축했습니다.
Trade-off
모든 기능을 단일 릴리스로 통합 배포하기 때문에 아무리 사소한 변경 사항이더라도 4개의 실행 단위를 포함한 서버앱 전체의 빌드 및 통합 검증 프로세스를 감수해야 합니다. 또한 논리적으로는 데이터 경계를 구분하였으나 일부 물리 데이터베이스 공유 상태가 지속되고 있고, 추천 피드 정렬이나 세부 조립 로직이 백엔드에 다소 쏠려 있어 역할 조정이 필요하다는 한계가 있습니다.
단일 애플리케이션 및 하나의 배포 단위를 유지하면서도, 코드베이스 내부에서 도메인 및 관심사를 비즈니스 경계별 모듈로 명확하게 나누어 결합도를 낮추는 아키텍처 스타일입니다.
화면을 그릴 때 필요한 전체 데이터 조회가 끝날 때까지 렌더링을 미루지 않고, 기본 구조(뼈대)를 먼저 클라이언트로 흘려보낸(Streaming) 뒤 동적 데이터가 채워지는 대로 점진적으로 전송하는 최적화 기법입니다.
코드 구현에 앞서 프론트엔드와 백엔드 개발자가 API 명세서(계약)를 먼저 정립하고 검토한 뒤, 이를 토대로 양측의 코드를 자동으로 제너레이션하여 병렬 개발을 진행하는 기법입니다.




