대규모 트래픽을 준비한다는 이유로 처음부터 서비스를 잘게 나누고 많은 인프라를 도입하는 경우가 있습니다. 그러나 초기 단계에서 필요한 것은 거대한 구조가 아니라 어디에 부하가 생기고, 어떤 기능을 독립적으로 확장해야 하며, 실패했을 때 무엇을 포기할지 판단할 수 있는 기반입니다.
피크 트래픽과 요청 형태
월간 사용자 수만으로 서버 규모를 정할 수 없습니다. 트래픽 모델에는 적어도 다음 값이 필요합니다.
- 평시와 이벤트 시점의 초당 요청 수
- 읽기와 쓰기의 비율
- 한 요청이 만드는 내부 호출과 쿼리 수
- 응답과 업로드 파일의 평균·최대 크기
- 로그인, 알림, 피드처럼 집중되는 시간대
- 특정 사용자나 콘텐츠에 몰리는 핫키 가능성
- 허용 가능한 응답 시간과 오류율
예상값에는 근거와 범위를 함께 기록합니다. 숫자가 틀릴 수 있다는 사실보다 어떤 지표를 관찰하고 언제 구조를 바꿀지 정하지 않은 것이 더 위험합니다.
핵심 경로와 부가 기능의 분리
로그인, 주문 확정, 결제처럼 반드시 성공 여부를 알려야 하는 경로와 추천, 통계, 알림처럼 지연돼도 되는 작업을 같은 요청에서 처리하면 부가 기능의 장애가 전체 서비스 장애가 됩니다.
사용자 응답 전에 꼭 끝나야 하는 작업만 동기 경로에 남기고 나머지는 큐나 후속 작업으로 분리합니다. 다만 비동기화했다고 해서 책임이 사라지는 것은 아닙니다. 작업 상태, 재시도, 실패 큐, 운영자 재처리 기능이 함께 있어야 합니다.
수평 확장 가능한 애플리케이션
서버 로컬 메모리나 디스크에 세션과 업무 상태를 저장하면 인스턴스를 늘릴 때 요청이 서로 다른 상태를 보게 됩니다. 서버 인스턴스는 가능한 한 상태를 갖지 않고, 공유해야 할 상태의 원본을 데이터베이스나 목적에 맞는 저장소에 둡니다.
무조건 외부 저장소를 사용하는 것이 답은 아닙니다. 캐시, 세션, 작업 상태, 영구 업무 데이터는 수명과 일관성 요구가 다릅니다. 각각의 원본과 장애 시 복구 방법을 문서화해야 합니다.
성능 계층이자 장애 지점인 캐시
캐시를 넣으면 평균 응답은 빨라지지만 오래된 값, 동시 만료, 원본 과부하라는 문제가 생깁니다. 캐시를 설계할 때는 적중률보다 다음 질문이 먼저입니다.
- 이 값의 원본은 어디인가
- 얼마 동안 오래된 값을 허용할 수 있는가
- 갱신은 삭제 후 조회인가, 직접 쓰기인가
- 인기 키가 만료될 때 동시에 원본을 조회하지 않게 할 수 있는가
- 캐시가 완전히 중단되면 기능을 제한할 것인가, 원본으로 우회할 것인가
금액, 재고, 권한처럼 잘못된 값의 비용이 큰 데이터는 단순 캐시 조회 결과만으로 확정하지 않습니다.
쿼리 경로 중심의 데이터베이스 최적화
데이터가 커질 것이라는 이유만으로 샤딩을 먼저 도입하면 개발과 운영 복잡도가 커집니다. 실제 핵심 쿼리, 인덱스, 잠금 경합, 커넥션 사용량을 측정한 뒤 병목에 맞는 수단을 선택합니다.
초기에도 지켜야 할 기준은 있습니다.
- 목록 API는 무제한 조회를 허용하지 않는다
- 정렬과 필터에 필요한 복합 인덱스를 쿼리와 함께 검토한다
- 긴 트랜잭션 안에서 외부 API를 호출하지 않는다
- 대량 작업은 작은 단위로 나누고 진행 상태를 남긴다
- 스키마 변경은 이전 버전과 함께 동작하는 순서로 배포한다
읽기 복제본이나 검색엔진은 원본과의 지연을 사용자 기능이 받아들일 수 있을 때 도입해야 합니다.
과부하 제어
시스템이 처리할 수 있는 양보다 많은 요청을 계속 받으면 모든 요청의 응답 시간이 늘고 결국 전체가 실패합니다. 사용자, API 키, 기능별 제한을 두고 중요도가 낮은 기능부터 품질을 낮추는 전략이 필요합니다.
예를 들어 추천 영역을 숨기거나 오래된 캐시를 사용하면서 주문 경로는 유지할 수 있습니다. 큐에도 최대 적체량과 생산 속도 제한이 필요합니다. 거절할 요청과 보존할 요청을 사업 기준으로 정해야 기술적인 백프레셔가 동작합니다.
초기 버전부터 필요한 관측 가능성
장애 이후 로그를 추가하는 것은 늦습니다. 최소한 요청 수, 응답 시간 분포, 오류율, 데이터베이스 쿼리 시간, 커넥션 풀, 캐시 적중률, 큐 대기 시간과 외부 API 지연을 볼 수 있어야 합니다.
평균값은 피크를 숨길 수 있으므로 백분위 지연 시간을 함께 봅니다. 배포 버전과 기능 플래그를 로그에 넣으면 특정 변경 이후의 오류를 좁힐 수 있습니다. 기술 지표와 함께 로그인 성공률, 주문 완료율 같은 핵심 업무 지표도 측정해야 합니다.
부하 테스트의 목적
최대 초당 요청 수 하나를 얻는 것보다 목표 부하에서 어떤 자원이 먼저 포화되고, 오류가 어떻게 증가하며, 부하를 줄였을 때 회복되는지 확인하는 것이 중요합니다.
실제 사용자 비율을 반영한 시나리오, 충분한 데이터 크기, 외부 연동의 지연을 포함하고 단계적으로 부하를 올립니다. 테스트 전후 데이터 정합성을 확인해야 빠르게 응답했지만 일부 쓰기가 유실되는 문제를 발견할 수 있습니다.
초기 설계에서 남겨야 할 결정
- 예상 트래픽과 근거, 다시 측정할 시점
- 핵심 동기 경로와 비동기 작업의 구분
- 각 데이터의 원본, 캐시와 허용 가능한 지연
- 장애 시 유지할 기능과 제한할 기능
- 확장 단위와 분리 기준
- 성능 목표, 경보 기준과 부하 테스트 시나리오
- 다음 구조 변경을 시작할 측정 조건
좋은 초기 아키텍처는 미래의 모든 규모를 미리 구현한 구조가 아닙니다. 현재는 단순하게 운영하면서도 병목을 관찰하고 필요한 부분만 분리할 수 있는 구조입니다. 실제 모바일 서비스 운영 범위는 대규모 모바일 서비스 사례에서 확인할 수 있습니다.