사용자가 늘어나면 서버도 늘려야 하고, DB 부하도 줄여야 하고, 배포도 좀더 고급스럽게 해야 한다. 이를 위한 핵심 기술 4가지를 알아보자.
1. 로드밸런서 (Load Balancer)
서버가 감당할 수 있는 트래픽에는 한계가 있다. 이때 우리는 '수평적 확장(Scale-out)'을 선택하게 되는데, 단순히 서버 개수만 늘린다고 해결되지 않는다. 들어오는 요청을 여러 서버에 골고루 뿌려줄 교통정리 요원이 필요하다.
- 트래픽 분산: 여러 대의 서버(Instance)가 요청을 나눠서 처리하게 해 준다.
- 고가용성 확보: 이게 핵심이다. 헬스 체크(Health Check)를 통해 주기적으로 서버 상태를 확인한다. 만약 서버 A가 죽었다? 로드밸런서가 이를 감지하고 트래픽을 서버 B, C로만 보낸다. 사용자는 서버 장애를 눈치채지 못한다.
- 주의점: 만약 세션을 사용한다면, 요청을 받는 서버가 계속 달라지기 때문에 세션 유지가 안되는 대참사가 발생한다. sticky session을 설정하거나, jwt를 이용하자.
2. 캐싱 (Caching)
"가장 빠른 요청 처리는 DB에 가지 않는 것이다."
데이터를 미리 복사해 놓은 임시 저장소(Cache)를 활용해서 속도를 높이고 서버 부하를 줄이는 기술이다.
무엇을 캐싱할까?
- 대상: 조회 빈도는 높은데, 데이터 변경은 잘 안 일어나는 것들. (예: 인기 상품 목록, 공지사항, 카테고리 정보 등)
- TTL: 영원한 데이터는 없다. 반드시 TTL(Time To Live, 만료 시간)을 설정해야 한다. 이 데이터가 조회되면 TTL을 갱신시키고, 만료되면 캐싱이 풀리고 다른 데이터가 들어올 자리를 내 줄 것이다.
갱신 전략: Update vs Delete?
DB 내용이 바뀌었을 때 캐시는 어떻게 할까?
- Update: DB 데이터가 바뀔 때 캐시 값도 수정한다. (두 번 쓰기 작업 발생, 동시성 이슈로 데이터 불일치 확률 높음)
- Delete (Eviction): DB 데이터가 바뀔 때 그냥 캐시를 날려버린다.
- 이게 훨씬 깔끔하고 안전하다. 다음 조회 요청 때 DB에서 최신 데이터를 가져와서 다시 캐싱(Lazy Loading)하게 두는 편이 정합성 맞추기에 유리하다.
캐시의 종류와 위치
- 애플리케이션 내부 캐시 (Local Cache):
- 스프링의 @Cacheable 등 사용. 메모리 접근이라 제일 빠르다.
- 단점: 서버가 여러 대면 서버 A의 캐시와 서버 B의 캐시 내용이 달라서 데이터 불일치가 생긴다.
- 분산 캐시 서버 (Global Cache):
- Redis, Memcached 등 외부 저장소 사용. 모든 서버가 같은 캐시를 보므로 일관성 유지 가능.
- 주의: Redis가 뻗어버리거나 응답이 늦어지면? 타임아웃 설정을 안 해두면 API 요청 전체가 블로킹되어 서버가 같이 죽는다. (Fail-fast 설정 필수)
- 웹 캐시 / CDN:
- HTML, JS, 이미지 같은 정적 파일은 서버까지 오지도 않게 한다. 사용자와 가까운 CDN 엣지 서버에 캐싱해두고 거기서 바로 내려준다.
- 나는 Aws의 CloudFront를 잘 사용중이다.
3. 메시지 큐 (Message Queue)
서버 컴포넌트 간에 데이터를 주고 받는 것이 아니라, 공통으로 접근하는 큐에 편지를 넣어두는 방식이다. (MSA)
- 핵심: 비동기(Asynchronous) 처리와 결합도(Coupling) 낮추기.
- 활용 예시: 회원가입 버튼을 눌렀을 때, '가입 처리'는 바로 하고 '환영 이메일 발송' 같은 무거운 작업은 큐에 던져놓는다. (RabbitMQ, Amazon SQS, Kafka 등)
- 사용자는 이메일이 1초 뒤에 오든 1분 뒤에 오든 신경 안 쓴다. 가입 완료 페이지만 빨리 뜨면 된다.
- 복잡성 관리: 큐를 도입하면 시스템이 복잡해진다.
- 메시지 처리에 실패하면? 무한 루프에 빠지지 않게 실패 큐(Dead Letter Queue)를 만들어서 따로 재시도(Retry) 처리를 해야 한다.
4. 컨테이너와 쿠버네티스 (Kubernetes)
컨테이너 (Docker)
- 애플리케이션 실행에 필요한 모든 것(코드, 라이브러리, 설정 파일 등)을 하나의 '이미지'로 만든다.
- "내 로컬에선 되는데 서버에선 안 돼요"라는 말이 사라진다. 어디서든 똑같이 돌아간다. 이거 진짜 편함

쿠버네티스 (K8s)
- 도커 컨테이너가 1~2개면 그냥 수동으로 띄우면 된다. 근데 100개라면? 이걸 관리(Orchestration) 해주는 선장이 쿠버네티스다.
- 왜 쓸까?
- 오토 스케일링 (HPA): 트래픽 늘어나면 알아서 컨테이너 개수 늘리고, 줄어들면 다시 줄인다.
- 자가 치유 (Self-healing): 컨테이너가 오류로 죽으면? 알아서 감지하고 다시 띄운다. 좀비처럼 되살려냄.
- 무중단 배포: 블루-그린 배포, 롤링 업데이트 같은 고급 배포 전략을 손쉽게(?) 사용할 수 있다.
- 인프라 추상화: 이게 중요한데, 밑단이 AWS든 Azure든 온프레미스든 상관없이 개발자는 yaml 파일 하나로 똑같은 환경을 구성할 수 있다. (표준화)
- 필자는 아직 써본적 없다...
'항해 Lite' 카테고리의 다른 글
| 데이터 정합성 확보 (1) (1) | 2025.11.30 |
|---|---|
| 서버 구조 설계(3) - 콘서트 예약 서비스 만들기 리뷰 (1) (0) | 2025.11.20 |
| 서버 구조 설계(1) - 애플리케이션 구조 설계 (0) | 2025.11.19 |
| TDD(3) - 완성 (1) | 2025.10.22 |
| TDD(2) - 첫 작성해보기 (0) | 2025.10.16 |