대규모 시스템 설계 기초 - 사용자 수에 따른 규모 확장성
대규모 시스템 설계 기초
내가 어느정도 알고 있는지 점검하기.
대개 웹 애플리케이션은 클라이언트 서버 패턴이다.
옛날에는 거의 단일 서버(PHP, JSP, etc)에서 클라이언트 / 서버 애플리케이션을 실행했다.
하지만 근래에는 사용자 경험을 향상시키기 위해서 CSR(Client Side Rendering)이 나왔고, 그 다음엔 CSR 문제를 해결하기 위해 SSR(Server Side Rendering)이 나왔다.
SSR은 NextJS가 나오면서 옛날과는 다르게 렌더링만 담당하는 서버를 두고, HTML을 렌더링하기 위해 API 서버를 두는 방식으로 발전하였다.
그러므로 프론트엔드 개발자도, 서버 개발자도 지속적으로 인프라 레벨을 공부해야한다.
- 단일 웹서비스 서버 구조
- 서버에서 모든 것을 처리한다.
- 웹 애플리케이션 서버, 데이터베이스 서버, 캐시 서버 등을 하나의 서버에서 처리한다.
- 병목 지점 발생시 스케일 업이라는 하드웨어 성능을 높이는 방법밖에 없다. - SPOF(Single Point of Failure)가 발생할 수 있다.
- 웹 서버 + 데이터베이스 서버 구조
- 웹 서버와 데이터베이스 서버를 분리한다.
- 이렇게 되면 스케일 아웃(서버 병렬 확장)이 가능하다.
- LB, ALB 가 필요해진다.
- RDBMS를 사용하면 자체적으로 Master-Slave 구조를 지원한다.
책 내용 정리
수직적 규모확장 vs 수평적 규모 확장
스케일 업: 단순 하드웨어 성능을 높이는 방법 스케일 아웃: 서버를 병렬로 늘리는 방법
수직적 규모 확장에는 한계가 있다. 한 대의 서버에 CPU나 메모리를 무한대로 증설할 방법은 없다. 수직적 규모 확장법은 장애에 대한 자동복구(failover) 방안이나 다중화(re-dundancy) 방안이 없다. 서버에 장애가 발생하면 웹사이트/앱은 완전히 중단된다.
로드밸런서
- 로드밸런서는 서버에 들어오는 트래픽을 분산시켜주는 장치이다.
- 사용자는 로드밸런서로 접근해(public IP) 서버로 접근한다.
- 서버는 private IP를 사용한다. 따라서 서버는 외부에서 직접 접근할 수 없다.
데이터베이스 다중화
- Master, Slave 구조를 대부분의 RDBMS가 지원한다. 데이터 원본은 주 서버에, 사본은 부 서버에 저장하는 방식이다.
- 쓰기 연산은 Master에서만 지원한다. 부 데이터베이스는 주 데이터베이스로부터 그 사본을 전달받으며, 읽기연산만을 지원한다.
웹 계층과 데이터 계층에 대한 부분은 위의 글을 참조.
아래는 응답시간(la-tency)을 개선해 볼 순서다. 응답 시간은 캐시를 붙이고 정적 콘텐츠를 콘텐츠 전송 네트워크(Content Delivery Network, CDN)으로 옮기면 개선.
캐시
캐시는 값비싼 연산 결과 또는 자주 참조되는 데이터를 메모리 안에 두고, 다음에 같은 데이터를 요청할 때 빠르게 응답할 수 있도록 하는 기술이다.
캐시 계층
캐시 계층(cache tier)은 데이터가 잠시 보관되는 곳으로 데이터베이스보다 훨씬 빠르다.
캐시 사용시 유의할 점
- 데이터 갱신은 자주 일어나지 않지만, 참조는 자주 일어나는 데이터에 캐시를 건다.
- 영속적으로 보관할 데이터를 캐시에 넣지 말자.
- 캐시 만료 정책을 설정하는 건 좋은 습관이다.
- 일관성은 어떻게 유지되는가? 저장소의 원본을 갱신하는 연산과 캐시를 갱신하는 연산이 단일 트랜잭션으로 처리되지 않는 경우 이 일관성은 깨질 수 있다.
- 이에 관련하여 Fackbook 논문 (Scaling Memcache at Facebook)을 참조하자.
- 장애에는 어떻게 대처할 것인가? 캐시 서버를 한 대만 두는 경우 해당 서버는 단일 장애 지점(Single Point of Failure, SPOF)이 되어버릴 가능성이 있다.
- 캐시 메모리는 얼마나 크게 잡을 것인가? 캐시 메모리가 너무 작으면 액세스 패턴에 따라서는 데이터가 너무 자주 캐시에서 밀려나버리므로 캐시의 성능이 떨어진다. 해결할 방법은 캐시 메모리를 과할당 하는 것이다.
- 데이터 방출 정책은 무엇인가? 캐시 데이터 방출 정책 중 LRU(Least Recently Used)가 가장 많이 사용된다. 다른 정책도 있으므로 적절하게 선택해야한다.
CDN
- CDN은 콘텐츠 전송 네트워크(Content Delivery Network)의 약자로, 전 세계에 분산된 서버에 콘텐츠를 저장해두고 사용자가 접근할 때 가장 가까운 서버에서 콘텐츠를 제공하는 기술이다.
- CDN은 콘텐츠를 캐시하는 역할을 한다. 콘텐츠를 캐시하면 웹 서버에 대한 요청이 줄어들어 응답 시간이 단축된다.
무상태 웹 계층
- 웹 계층을 수평적으로 확장하는 방법을 고민해보자. 이를 위해서는 상태 정보(사용자 세션 데이터와 같은)를 웹 계층에서 제거한다.
- 이렇게 하지 않으면 수평적으로 확장되었을 때 A 서버에 저장되어 있는 상태 정보가 B 서버로 이동되지 않아 사용자가 로그인 상태를 유지하지 못하는 문제가 발생한다.
데이터 센터
- 가용성을 높이고 전 세계 어디서도 쾌적하게 사용할 수 있도록 하기 위해서 여러 데이터 센터를 지원하는 것이 필수다.
- 사용자는 장애가 없는 상황에서 가장 가까운 데이터 센터로 안내되는데, 통상 이 절차를 지리적 라우팅(geographic routing)이라고 한다.
다중 데이터센터 아키텍처를 만들려면 몇 가지 기술적 난제를 해결해야 한다.
- 트래픽 우회: 올바른 데이터 센터로 트래픽을 보내는 효과적인 방법을 찾아야한다. GeoDNS, Anycast IP, BGP Anycast 등이 있다.
- 데이터 동기화
- 테스트와 배포: 여러 데이터 센터를 사용하도록 시스템이 구성된 상황이라면 웹 사이트 또는 애플리케이션을 여러 위치에서 테스트해보는 것이 중요하다.
시스템을 더 큰 규모로 확장하기 위해서는 시스템의 컴포넌트를 분리하여, 각기 독립적으로 확장될 수 있도록 하여야 한다. 메시지 큐는 많은 실제 분산 시스템이 이 문제를 해결하기 위해 채용하고 있는 핵심적 전략 가운데 하나다.
메시지 큐
- 메시지 큐는 시스템의 컴포넌트 간에 비동기적으로 메시지를 주고받을 수 있게 해주는 시스템이다.
- 메시지 큐는 시스템의 컴포넌트를 독립적으로 만들어준다. 컴포넌트 간의 결합도를 낮추어 시스템을 확장하기 쉽게 만들어준다.
- 보통 메시지 큐는 pub/sub 모델을 사용한다. 이 모델은 메시지를 발행하는 쪽(publisher)과 메시지를 구독하는 쪽(subscriber)으로 나뉜다.
- 발행하는 쪽, 구독하는 쪽이 분리되었기 때문에 독립적으로 확장할 수 있다.
로그, 매트릭 그리고 자동화
- 로그와 매트릭은 시스템의 건강 상태를 확인하는 데 필수적이다.
- 로그는 시스템의 동작을 추적하고, 매트릭은 시스템의 성능을 측정한다.
- 로그와 매트릭을 수집하고 분석하는 것은 시스템의 성능을 개선하는 데 중요한 역할을 한다.
데이터베이스의 규모 확장
수직적 확장
하드웨어 성능을 높이는 이 접근법에는 몇가지 심각한 약점이 있다.
- 하드웨어를 무한으로 증설할 수 없다.
- SOF로 인한 위험성이 크다
- 비용이 많이 든다. 고성능 서버로 갈수록 가격이 기하급수적으로 올라간다.
수평적 확장
수평적 확장은 서버를 병렬으로 늘리는 방법이다.
- 수평적 확장은 샤딩이라고도 부른다.
- 샤딩은 데이터베이스를 여러 부분으로 나누어 각 부분을 별도의 서버에 저장하는 방식이다.
샤딩 전략을 구현할 때 고려해야 할 가장 중요한 것은 샤딩 키(sharding key)를 어떻게 정하느냐 하는 것.
- 샤딩 키는 파티션 키(partition key)라고도 부른다.
- 데이터가 어떻게 분산될지 정하는 하나 이상의 컬럼으로 구성된다.
샤딩 키를 선택할 때 고려해야 할 사항
- 데이터의 재 샤딩(resharding)
- 유명인사 문제
- 조인과 비정규화
요약
- 웹 계층은 무상태 게층으로
- 모든 계층에 다중화 도입
- 가능한 많은 데이터를 캐시할 것
- 정적 콘텐츠는 CDN을 통해 서비스할 것
- 데이터 계층은 샤딩을 통해 그 규모를 확장할 것
- 각 계층은 독립적 서비스로 분할할 것
- 시스템을 지속적으로 모니터링하고, 자동화 도구들을 활용할 것