단일 서버
- 웹 앱, 데이터베이스, 캐시 등이 전부 한 대의 서버에서 실행되는 것
데이터베이스
- 사용자가 늘면 서버 하나로는 충분하지 않다
- 웹/모바일 트래픽 처리 용으로 하나, 데이터베이스 용으로 하나를 분리한다.
- 관계형
- 비관계형
- 네가지 분류
- 키-값 저장소
- 그래프 저장소
- 컬럼 저장소
- 문서 저장소
- 아주 낮은 응답 지연시간(Latency)
- 다루는 데이터가 비정형
- 데이터를 직렬화/역직렬화 할수만 있으면 됨
- 아주 많은 양의 데이터를 저장해야함
- 위의 경우 NoSQL을 고려
수직적 규모 확장 vs 수평적 규모 확장
- 스케일 업 : 서버에 고사양 자원을 추가하는 것
- 스케일 아웃 : 더 많은 서버를 추가하여 성능 개선
- 트래픽 양 적을 때 → 스케일 업이 좋음
- 스케일 업의 한계
- 한 대의 서버에 CPU, 메모리를 무한대로 증설할 수는 없음
- 장애에 대한 자동복구(Failover)나 다중화(redundancy) 방안이 없음
- 따라서 대규모 어플리케이션에는 스케일 아웃이 효과적
로드밸런서
- 부하 분산 집합에 포함된 서버들에게 트래픽의 부하를 고르게 분산하는 것
- 사용자가 로드밸런서의 IP로 접속하고, 사설 IP 주소로 로드밸런서가 웹 서버들과 통신
- 장애 대응
- 서버 1이 다운되면 서버 2로 모든 트래픽 전송
- 트래픽이 계속 증가하면 단순히 서버를 한대 더 추가함으로써 대처 가능
- 그러나 여전히 데이터베이스는 한 대의 서버로 운영하고 있음
데이터베이스 다중화
- 주(Master)-부(Slave) 관계를 설정 → 원본은 마스터, 사본은 슬레이브에
- insert, delete, update 등은 마스터 데이터베이스에, select 등 읽기 연산은 슬레이브로
- 이점
- 병렬로 처리 가능한 쿼리가 늘어남 → 성능 향상
- 하나의 데이터베이스가 장애가 나도 다른 서버에 있는 데이터를 가져와 계속 서비스 가능 → 가용성(availability)
- 장애 대응
- 슬레이브 한대인데 장애나면 → 읽기 연산까지 모두 마스터로 감
- 이후 새로운 슬레이브를 증설하여 장애 서버를 대체
- 마스터가 장애나면 → 슬레이브 중 하나가 마스터로 승격 - 슬레이브 증설
- 문제 : 슬레이브에 저장된 데이터가 최신이 아닐 수 있다 - 없는 데이터는 복구 스크립트를 돌려 추가하거나, 다중 마스터, 원형 다중화 방식을 도입할 수도
- 응답 시간 개선 → 캐시를 붙이고 정적 컨텐츠를 CDN으로 옮기면 가능
캐시
- 값비싼 연산 결과나 자주 참조되는 데이터를 메모리 안에 두고, 뒤이은 요청이 빨리 처리될 수 있도록 하는 저장소
캐시 계층
- 데이터가 잠시 보관되는 곳 → 웹 서버와 데이터베이스 사이에 둔다
- 저장되어있다면 바로 리턴
- 없다면 데이터베이스에 쿼리 날려 캐시에 저장한 뒤 반환
- 읽기 주도형 캐시 전략 (Read-through caching strategy)
- 주의할 점
- 갱신은 별로 없고, 읽기가 많을 때 유용
- 영속적으로 보관할 데이터는 캐시에 두면 안됨 ← 캐시 서버가 재시작 시 캐시 내 모든 데이터가 사라지므로
- 만료 정책을 수립해야함 → 너무 짧으면 데이터베이스 호출이 많고, 너무 길면 원본과 차이가 날 가능성이 높음
- 일관성은 어떻게? ← 원본과 사본이 같은지의 여부 - 원본 갱신 연산과 사본 갱신 연산이 단일 트랜잭션으로 이루어지지 않으면 보장이 안됨
- 장애 대응 어떻게? - 캐시 서버가 한대만 있으면 단일 장애 지점(SPOF)이 될수도 있다. 따라서 여러 지역에 걸쳐 캐시 서버를 분산해야함
- 얼마나 크게 → 케시 메모리 과할당(overprovision)하면 됨
- 방출 정책은? - LRU(가장 오래 안 쓰인 것 버리기), LFU(가장 덜 빈번한 데이터), FIFO(선입선출)
콘텐츠 전송 네트워크(CDN)
- 정적 콘텐츠를 저장하고, 지리적으로 분산된 서버의 네트워크
- 정적 콘텐츠가 있으면 바로 리턴
- 없으면 원본 서버에서 가져온 뒤 리턴
- 고려사항
- 비용 : 자주 사용되지 않는 콘텐츠는 CDN에서 제거
- 적절한 만료 시점
- 장애 대처 : CDN에 장애가 발생한 경우, 이를 감지하여 원본 서버로부터 받아오도록
무상태(stateless) 웹 계층
- 웹 계층을 수평적으로 확장하는 방법
- 이를 위해서는 상태 정보 (사용자 세션 데이터 등)를 웹 계층에서 제거해야함
- 상태 정보를 RDB나 NoSQL 같은 지속성 저장소에 저장하는 것
상태 정보 의존적인 아키텍처
- 특정 서버에 세션같은 상태 정보가 있는 경우 해당 사용자는 반드시 그 서버로만 연결이 가야한다.
- 로드밸런서가 이를 지원하기 위해 고정된 세션(Sticky Session)을 지원하지만, 부담이 됨
무상태 아키텍처
- 사용자의 HTTP 요청은 어느 웹 서버로도 다 갈수있음
- 상태 정보가 필요하다면 공유 저장소로부터 데이터를 가져옴
- 상태 정보가 웹 서버로부터 분리 → 확장이 쉬워짐
- 공유 저장소는 관계형일수도, Redis/Memcached 같은 캐시일수도, NoSQL일수도 있다
데이터 센터
- 장애가 없는 상황에서 사용자가 가장 가까운 데이터 센터로 안내됨 → 지리적 라우팅
- 데이터 센터 하나에 장애가 발생하면 모든 트래픽은 장애 없는 데이터 센터로
- 문제
- 트래픽 우회 : 올바른 데이터 센터로 보내야함 → GeoDNS가 해결해줌
- 데이터 동기화 : 데이터 센터마다 별도의 데이터베이스를 사용한다면 장애 복구를 해도 해당 데이터센터에는 해당 데이터가 없을 수 있음 → 데이터를 여러 데이터 센터에 걸쳐 다중화
- 테스트와 배포 : 여러 데이터 센터마다의 테스트가 이루어져야하고, 배포 또한 자동 배포 도구를 통해 모든 데이터 센터에 동일하게 서비스가 설치되도록
메시지 큐
- 시스템을 더 큰 규모로 확장하기 위해서는 시스템 컴포넌트를 분리하여 독립적 확장이 가능해야함 → 이 때 메시지 큐를 사용
- 생산자/발행자(Producer, Publisher)가 메시지를 만들어 메시지 큐에 발행(publish) → 소비자/구독자(consumer, subscriber)가 이 메시지를 받아 동작 수행
- 서버간 결합이 느슨해진다. → 생산자는 소비자 프로세스가 다운되어 있으도 메시지 발행 가능, 소비자는 생산자가 가용한 상태가 아니더라도 메시지 수신 가능
데이터베이스의 규모 확장
수직적 확장
- CPU, 메모리, 디스크 등을 추가하는 것
- 단점
- 무한 증설 불가능
- SPOF로 인한 위험성이 큼
- 비쌈 → 고성능 서버로 갈수록 비쌈
수평적 확장
- 샤딩(sharding)이라고도 함
- 더 많은 서버를 추가함으로써 성능 향상
- 데이터베이스를 샤드(shard)라고 하는 작은 단위로 분할함
- 모든 샤드는 같은 스키마를 쓰지만 중복 데이터가 없음
- 샤딩 키를 어떻게 정하느냐가 매우 중요
- 문제
- 데이터의 재 샤딩 - 하나의 샤드로는 감당 못할 너무 많은 데이터가 있을 때
- 이러한 경우 샤드 키를 계산하는 함수를 변경하고 데이터 재배치해야함
- 유명인사(celebrity) 문제 : 핫스팟 키 문제라고도 함, 특정 샤드에 쿼리가 집중되는 것 - 해당 샤드를 더 잘게 쪼개야함
- 조인과 비정규화 : 하나의 데이터베이스를 여러 샤드 서버로 쪼개면 조인이 어렵다. → 데이터를 비정규화(하나의 큰 뭉텅이로 만들기)하여 하나의 테이블에서 쿼리가 전부 가능하도록
https://product.kyobobook.co.kr/detail/S000001033116