1. 사용자 수에 따른 규모 확장성
Last updated
Last updated
가장 기본이 되는 서버 시스템 구조이다.
다음 순서를 통해 사용자의 UI와 서버가 통신하게 된다.
1️⃣ 웹 브라우저에 도메인 주소를 입력
2️⃣ 도메인을 기반으로 IP 주소를 획득
3️⃣ 실제 해당 IP로 요청을 보냄
4️⃣ 서버로부터 응답을 받아 웹 브라우저가 표현
사용자 단말
서버에 실제 요청을 보내는 근원이다.
웹 앱
비즈니스 로직, 데이터 저장 등을 처리하기 위해 서버 구현용 언어를 사용
뷰를 위해 클라이언트 구현용 언어를 사용
모바일 앱
웹 서버와 통신하기 위해 HTTP 프로토콜을 사용
응답 데이터의 포맷으로 보통 JSON(JavaScript Object Notation)을 사용
여러 서버를 두고 웹 계층과 데이터 계층을 분리해 독립적으로 확장할 수 있다.
Relational DB
자료를 테이블, row, column 으로 표현한다.
여러 테이블의 데이터를 join하여 합칠 수 있다.
NoSQL
종류: key-value 저장소, 그래프 저장소, column 저장소, 문서 저장소
필요한 상황
낮은 응답 latency가 필요할 때 (빠른 속도가 필요할 때)
다루는 데이터가 비정형이라 관계형 데이터가 아닐 때
데이터를 직렬화/역직렬화 할 수 있기만 하면 될 때
아주 많은 양의 데이터를 저장해야 할 때
수직적 확장 (Scale Up)
더 좋은 사양의 자원(CPU, RAM 등)을 기존 서버에 추가하는 방식
장점
서버로 유입되는 트래픽 양이 적을 때 좋다.
비교적 단순하게 확장 가능
단점
한 대의 서버에 사용 가능한 사양에는 한계가 있으며, 확장 시 비용이 비싸다.
장애에 대한 failover(자동복구)나 redundancy(다중화) 방안을 제시하지 않으므로 서비스가 중단될 수 있다.
수평적 확장 (Scale Out)
비슷한 사양의 더 많은 서버를 추가하여 성능을 개선하는 방식
수직적 확장의 단점을 해결한다.
부하 분산 집합에 속한 웹서버들에게 트래픽 부하를 고르게 분산하는 방식
클라이언트의 접속을 부하 분산 집합에 분배하기 때문에 failover가 가능하며 웹 계층의 가용성이 향상된다.
트래픽이 가파르게 증가하는 경우 웹 서버 계층에 많은 서버를 추가하면 로드밸런서가 자동으로 트래픽을 분산하여 장애 발생을 막을 수 있다.
데이터의 원본은 master 서버에, 복제본은 slave 서버에 저장한다.
master 서버에서만 write 연산을 처리할 수 있도록 하며, read 연산은 어디서든 처리 가능하다. 일반적으로 대부분의 요청이 read 연산이기 때문에 요청을 분산하여 처리할 수 있게 된다.
장점
성능 완화: 병렬로 처리될 수 있는 질의의 수가 늘어 성능이 좋아진다.
안정성: 데이터 서버 중 일부가 파괴되어도 데이터가 보존될 가능성이 커진다.
가용성: 하나의 데이터베이스 서버에 장애가 발생해도 서비스가 가능하다.
프로덕션 환경에서는 slave 서버에 보관된 데이터가 최신 상태가 아닐 수 있어, 없는 데이터는 따로 추가해주어야 한다. 혹은 다중 마스터, 원형 다중화 방식을 도입할 수 있다.
캐시를 붙이고 정적 콘텐츠를 CDN으로 옮긴다.
값비싼 연산 결과 또는 자주 참조되는 데이터를 메모리 안에 두고, 요청이 빨리 처리될 수 있도록 하는 저장소
캐시 계층
데이터가 잠시 보관되는 곳
데이터베이스보다 훨씬 빠르고 DB 부하를 줄일 수 있다.
읽기 주도형 캐시 전략
캐시에 저장되어 있다면 캐시 데이터를 클라이언트에 반환하고 없는 경우에는 데이터베이스 질의를 통해 데이터를 찾아 캐시에 저장하고 클라이언트에 반환
유의할 점
어떤 상황에 캐시가 필요한지 파악해야 한다. 데이터 갱신이 자주일어나지 않지만 참조는 빈번하게 일어나는 경우에 적합하다.
중요한 데이터는 지속적인 데이터 저장소에 두어야 한다.
캐시 데이터의 만료 기한을 적절하게 설정해야 한다.
데이터 저장소의 원본이 갱신될 때 캐시 내의 사본도 갱신되지 않는다면 일관성이 유지되지 않는다.
캐시 서버 하나만 사용할 경우 단일 장애 지점(SPOF)이 되어 전체 시스템의 동작을 중단시킬 수 있다. 따라서 여러 캐시 서버를 사용해 분산시켜야 한다.
캐시 메모리의 크기를 적당히 크게 잡아야 캐시 eviction이 자주 발생하지 않을 것이다.
캐시 eviction 정책을 적절히 적용해야 한다. (LRU, LeastFrequentlyUsed, FIFO 등)
정적 컨텐츠 (이미지, 비디오, CSS 등) 를 전송하는데 쓰이는 지리적으로 분산된 네트워크
자주 사용되는 컨텐츠를 CDN에 캐싱하여 빠른 응답성을 얻도록 한다.
서버가 위치한 데이터센터와 거리가 먼 사용자들이 많은 경우 응답 속도가 매우 낮아질 수 있으므로, 사용자가 많은 지역 별로 CDN에 컨텐츠를 캐싱해 어디서나 응답 속도가 빠른 서비스를 제공받을 수 있도록 한다.
object versioning 기능을 이용해 기존 컨텐츠의 버전 번호와 컨텐츠를 함께 업데이트할 수 있다.
❎ 상태 정보 의존적 아키텍처
상태 정보를 서버에 저장해두는 방식이다. 따라서, 같은 클라이언트로부터의 요청은 항상 같은 서버로 전송되어야 유지된 상태 정보를 확인할 수 있다.
로드밸런서의 고정 세션 기능을 사용하면 구현 가능하지만, 로드밸런서에 부담을 주고 서버를 추가/제거하거나 장애를 처리하기도 복잡해져서 대규모 시스템에서는 사용하지 않는다.
✅ 무상태 아키텍처
상태 정보를 웹 계층이 아닌 RDB/NoSQL 에 보관하고 필요할 때마다 가져오게 한다.
상태 정보: 사용자 세션 데이터 등을 의미
어떤 웹서버로든 요청이 들어갈 수 있다.
상태 정보가 필요한 경우 공유 저장소로부터 데이터를 가져온다.
상태 정보를 저장하는 공유 저장소는 규모 확장이 간편한 NoSQL을 사용하거나 캐시를 사용할 수 있다.
지리적 라우팅
장애가 없는 상황에서 가장 사용자에게 가까운 데이터 센터로 안내되는 것을 의미한다.
geoDNS
사용자의 위치에 따라 도메인 이름을 어떤 IP 주소로 변환할지 결정하도록 해주는 DNS 서비스
UltraDNS에서 이를 지원해준다.
올바른 데이터 센터로 트래픽 우회시키는 효과적인 방법을 찾아야 한다.
여러 데이터 센터에 걸쳐 데이터를 다중화하지 않을 경우, failover에 의해 트래픽이 우회되어야 하는 상황이 발생하였을 때 요청하는 데이터가 해당 데이터 센터에 없을 수 있다.
여러 위치에서 프로그램을 테스트해보는 것이 중요하다.
자동화된 배포 도구를 사용해 모든 데이터센터에 동일한 서비스가 설치되도록 해야 한다.
메시지의 무손실을 보장하고 비동기 통신을 지원하는 컴포넌트
생산자는 시간이 오래 걸리는 작업들을 메시지 큐에 넣고, 이 작업을 수행하는 프로세스(소비자)가 메시지 큐에서 꺼내 비동기적으로 처리하도록 한다.
생산자와 소비자 서비스 규모는 각기 독립적으로 확장될 수 있다.
로그
에러 로그 모니터링을 통해 시스템의 오류/문제를 찾아낼 수 있다.
단일 서비스로 모아주는 도구를 활용해 편리하게 검색/조회를 할 수 있다.
메트릭
시스템의 현재 상태를 손쉽게 파악 가능, 사업 현황에 유용한 정보를 얻을 수 있다.
호스트 단위 메트릭: CPU, 메모리, 디스크 I/O 에 관한 메트릭
종합 메트릭: 데이터베이스/캐시 계층의 성능
핵심 비즈니스 메트릭: daily active user, 수익, 재방문 등
자동화
생산성을 높이기 위해 자동화 도구를 활용해 빌드, 테스트, 배포 등의 절차를 자동화
지속적 통합을 도와주는 자동화 도구의 경우, 개발자가 만드는 코드를 검증 절차를 거치도록 해 쉽게 문제를 감지할 수 있다.
대규모 데이터베이스를 shard 라는 작은 단위로 분할하는 기술
모든 샤드는 같은 스키마를 쓰지만, 샤드에 보관되는 데이터 사이에는 중복이 없다.
문제점
하나의 샤드로 감당할 수 없는 만큼 데이터가 늘어나거나, 샤드 간 데이터 분포가 불균형해 특정 샤드에만 데이터 소모가 빠르게 이뤄질 때 재샤딩이 필요하다.
샤드 키를 계산하는 함수를 변경하거나 consistent hashing을 사용해 이러한 문제를 해결할 수 있다.
hotspot key 가 존재할 경우 특정 샤드에 요청량이 과도하게 몰릴 수 있어 이러한 키들이 여러 샤드에 적절히 분배되도록 해야 한다.
데이터베이스를 샤딩할 경우 여러 샤드에 걸친 조인 처리를 하기 어렵기 때문에 비정규화하여 하나의 데이터베이스에서 질의가 수행되도록 해야 한다.
수백만 이상의 사용자를 지원하려면 지속적으로 시스템을 최적화하고 더 작은 단위의 서비스로 분할해야 할 것이다.