Chapter 11

로드 밸런싱과 데이터 스토리지

  • 11.1 DNS load balancing
  • 11.2 Transport layer load balancing
  • 11.3 Application layer load balancing
  • 11.4 Replication
  • 11.5 Partitioning
  • 11.6 NoSQL

수평 확장(horizontal scaling)에는 두 얼굴이 있어. 상태 없는 서비스는 로드 밸런서로 쉽게 스케일 아웃하지만, 상태가 있는 서비스(DB)는 복제와 파티셔닝이라는 훨씬 어려운 문제를 풀어야 해. 둘 다 이해해야 시스템 전체를 확장할 수 있지.

먼저 상태 없는 쪽부터. 여러 서버를 두고 로드 밸런서가 요청을 분산하면 서버 2대면 용량 2배야. 이게 가능한 이유는 상태를 전용 서비스에 밀어냈기 때문이지. DNS 로드 밸런싱은 가장 단순해 — 도메인에 여러 IP를 매핑하고 클라이언트가 골라. 근데 DNS 서버는 서버 죽음을 모르고 캐싱 때문에 변경 전파가 느려서, 실무에서는 리전 간 분산에만 써.

L4 로드 밸런서는 TCP 수준에서 동작해. **VIP(Virtual IP)**를 노출하고 연결 튜플을 해싱해서 서버에 배정하지. **DSR(Direct Server Return)**로 서버가 로드 밸런서를 우회해서 직접 응답하면 부하를 크게 줄일 수 있어. 매우 빠르지만 바이트만 셔플할 뿐 내용을 이해 못 해. L7 로드 밸런서는 HTTP 수준의 리버스 프록시야. 헤더 기반 rate limiting, TLS 종료, 쿠키 기반 스티키 세션, HTTP/2 스트림 분리까지 가능하지. 처리량은 낮아서 DDoS 방어에는 L4가 적합해. 밸런싱 알고리즘도 중요한데, "두 개의 랜덤 선택(power of two random choices)" — 랜덤 2개 중 덜 바쁜 쪽에 보내는 게 정교한 부하 메트릭보다 실무에서 더 잘 동작해.

이제 어려운 쪽, 상태가 있는 서비스야. 읽기 용량을 늘리는 가장 일반적인 방법은 리더-팔로워 복제지. 쓰기는 리더에만, 팔로워가 WAL 변경을 스트리밍으로 가져가. 완전 비동기는 빠르지만 데이터 유실 위험이 있고, 완전 동기는 팔로워 하나 불능이면 전체 불가용이라 실무에서는 혼합 방식을 써. 팔로워를 읽기 전용으로 로드 밸런서 뒤에 두면 읽기 용량이 늘어나지. 단, 복제는 읽기만 스케일해.

쓰기와 데이터 크기 한계를 넘으려면 파티셔닝이 필요해. 근데 전통 RDBMS는 네이티브 지원이 없어서 애플리케이션 레이어에서 구현해야 해 — 데이터 분배, 리밸런싱, 크로스 파티션 쿼리, 분산 트랜잭션까지 매우 도전적이야. 근본 문제는 전통 RDBMS가 "하나의 강력한 머신에 담긴다"는 가정으로 설계됐다는 거거든. 그래서 2000년대 초 대형 테크 기업들이 처음부터 확장성을 고려한 NoSQL을 만들었어. 강한 일관성 대신 최종/인과적 일관성, join 없이 비정규화, 네이티브 파티셔닝이 특징이지. DynamoDB를 보면 파티션 키가 데이터 분배를, 소트 키가 파티션 내 정렬을 결정하고, 파티션당 3개 복제본을 상태 머신 복제로 동기화해. 핵심 교훈 — NoSQL은 RDBMS보다 유연한 게 아니라 접근 패턴에 훨씬 더 단단히 결합돼. 접근 패턴을 모르고 쓰면 양쪽의 최악을 얻어.


정리

11장 읽고 기억할 거 세 가지:

  1. L4는 빠르지만 바보, L7은 스마트하지만 느려 — 실무에서는 L4 → L7 계층으로 조합하고, "power of two random choices"가 놀랍도록 잘 동작해
  2. 복제는 읽기만 스케일해 — 쓰기와 데이터 크기를 넘으려면 파티셔닝이 필요하고, 그 복잡성은 상당하지
  3. NoSQL은 "더 좋은 DB"가 아니라 다른 트레이드오프야 — 접근 패턴을 먼저 파악하고 데이터를 모델링하는 게 가장 중요한 원칙이지