-
웹 앱, 데이터베이스, 캐시 등이 전부 한 대의 서버에서 실행
- 도메인 이름(api.mysite.com)을 이용하여 웹 사이트 접속
- 도메인 이름을 DNS에 질의하여 IP 주소로 변환
- 해당 IP 주소로 HTTP 요청 전달
- 웹 서버에서 HTML 페이지 혹은 JSON 형태의 응답 반환
-
실제 요청은 웹 애플리케이션 혹은 모바일 앱에서 전달됨
- 웹 애플리케이션
- 비즈니스 로직 및 데이터 저장 등을 처리하기 위한 서버 구현용 언어(자바, 파이썬 등) 사용
- 프레젠테이션 용으로는 클라이언트 구현용 언어(HTML, 자바스크립트 등) 사용
- 모바일 앱
- 모바일 앱과 웹 서버 간 통신을 위해서는 HTTP 프로토콜을 이용
- HTTP 프로토콜을 통해 반환될 응답 데이터의 포맷으로는 보통 JSON이 간결함에 널리 사용됨
- 웹 애플리케이션
-
웹/모바일 트래픽 처리 서버(웹 계층)와 데이터베이스 서버(데이터 계층)를 분리하여 독립적 확장이 가능하도록 함
-
데이터베이스의 종류
- 관계형 데이터베이스(RDBMS)
- MySQL, 오라클, PostgreSQL 등이 존재
- 자료를 테이블과 열, 컬럼으로 표현
- SQL을 사용하여 여러 테이블에 있는 데이터를 관계에 따라 join 하여 합칠 수 있음
- 40년 이상 사용되어 온 시스템으로, 대부분 관계형 데이터베이스가 사용됨
- 비 관계형 데이터베이스(NoSQL)
- CouchDB, Neo4j, Cassandra, HBase, Amazon DynamoDB
- 키-값 저장소, 그래프 저장소, 칼럼 저장소, 문서 저장소 4가지로 분류할 수 있음
- 일반적으로 조인 연산은 지원하지 않음
- 비 관계형 데이터베이스를 선택해야 하는 경우
- 아주 낮은 응답 지연시간(latency)이 요구됨
- 다루는 데이터가 비정형이라 관계형 데이터가 아님
- 데이터(JSON, YAML, XML 등)를 직렬화하거나 역직렬화 할 수 있기만 하면 됨
- 아주 많은 양의 데이터를 저장할 필요가 있음
- 관계형 데이터베이스(RDBMS)
- 스케일 업 : 수직적 규모 확장 프로세스는 서버에 고사양 자원(CPU, RAM)을 추가하는 행위
- 스케일 아웃: 수평적 규모 확장 프로세스는 더 많은 서버를 추가하여 성능을 개선하는 행위
- 서버로 유입되는 트랙픽 양이 적을 때애는 수직적 확장이 좋음. 수직적 확장의 가장 큰 장점은 단순함
- 수직적 확장의 단점
- 수직적 규모 확장에는 한계가 존재하여 한 대의 서버에 CPU나 메모리를 무한대로 증설할 수 없음
- 장애에 대한 자동복구 방안이나 다중화 방안을 제시하지 않아 서버 장애가 발생하면 웹 사이트/앱은 완전히 중단됨
- 대규모 애플리케이션을 지원하는 경우 수평적 규모 확장법이 보다 적절
-
로드밸런서를 사용하는 이유
- 사용자가 웹 서버에 바로 연결되는 경우, 웹 서버가 다운되면 사용자는 웹 사이트에 접속할 수 없음
- 너무 많은 사용자가 접속하여 웹 서버가 한계 상황에 도달하면 응답 속도가 느려지거나 서버 접속이 불가능해짐
-
로드밸런서는 부하 분산 집합에 속한 웹 서버들에 트래픽을 고르게 분산하는 역할을 함
- 사용자는 로드밸런서의 공개 IP 주소로 접속 (웹 서버는 클라이언트의 접속을 직접 처리하지 않음)
- 보안을 위해 서버 간 통신에는 사설 IP 주소를 사용 (같은 네트워크에 속한 서버 사이의 통신에만 쓰일 수 있음)
- 로드밸런서는 웹 서버와 통신하기 위해 사설 주소를 이용
- 부하 분산 집합에 두개의 웹 서버를 추가하고 나면 장애를 자동복구하지 못하는 문제는 해소되며, 가용성은 향상됨
- 서버 1이 다운되면 모든 트래픽은 서버 2로 전송되어 웹 사이트 전체가 다운되는 일이 방지됨
- 부하를 나누기 위해 새로운 서버를 추가할 수 있음
- 웹 사이트로 유입되는 트래픽이 가파르게 증가하면 로드밸런서가 자동적으로 트래픽을 분산하기 시작함
-
데이터베이스 다중화를 통해 장애의 자동복구가 가능
-
많은 데이터베이스 관리 시스템이 다중화를 지원
-
서버 사이에 주/부 관계를 설정하고 데이터 원본은 주 서버에, 사본은 부 서버에 저장
- 주 서버에서만 쓰기 연산을 지원
- 부 서버에서는 주 서버로부터 사본을 전달받으며, 읽기 연산만을 지원
- 대부분의 애플리케이션은 쓰기 연산보다 읽기 연산의 비중이 훨신 높아 부 서버 수가 주 서버보다 많음
-
데이터베이스 다중화 장점
- 더 나은 성능: 병렬로 처리될 수 있는 질의으 수가 늘어나므로 성능이 좋아짐
- 안정성: 자연 재해 등의 이유로 데이터베이스 서버 일부가 파괴되어도 데이터는 보존됨
- 가용성: 데이터를 여러곳에 복제해 둠으로써 하나의 데이터베이스에 장애가 발생해도 다른 서버의 데이터를 가져와서 계속 서비스 할 수 있게 됨
-
데이터베이스 서버 다운 시나리오
- 부 서버가 다운된 경우
- 부 서버가 한대 뿐인데 다운된 경우: 읽기 연산은 모두 주 서버로 전달, 새로운 데이터베이스 서버가 장애 서버를 대체
- 부 서버가 여러대인데 다운된 경우: 읽기 연산은 나머지 부 스 서버로 분산됨, 새로운 부 데이터베이스 서버가 장애 서버를 대체
- 주 서버가 다운된 경우
- 한대의 부 서버만 있는 경우 해당 부 서버가 새로운 주 서버가 되며, 모든 데이터베이스 연산은 새로운 주 서버에서 수행됨
- 프로덕션 환경의 경우, 부 서버에 보관된 데이터가 최신 상태가 아닐 수 있어 없는 데이터는 복구 스크립트를 돌려서 추가해야 함
- 부 서버가 다운된 경우
-
설계안
- 사용자는 DNS로부터 로드밸런서의 공개 IP 주소를 받는다
- 사용자는 해당 IP 주소를 사용해 로드밸런서에 접속한다.
- HTTP 요청은 서버 1이나 서버 2로 전달된다.
- 웹 서버는 사용자의 데이터를 부 데이터베이스 서버에서 읽는다.
- 웹 서버는 데이터 변경 연산(추가, 삭제, 갱신 등)은 주 데이터베이스로 전달한다.
- 값비싼 연산 결과 또는 자주 참조되는 데이터를 메모리 안에 두어 요청이 보다 빨리 처리될 수 있도록 함
- 웹 페이지를 새로고침 할 때마다 표시할 데이터를 가져오기 위해 한 번 이상의 데이터베이스 호출이 발생함
- 어플리케이션의 성능은 데이터베이스를 얼마나 자주 호출하느냐 크게 좌우됨.
-
데이터가 잠시 보관되는 곳으로 데이터베이스보다 훨씬 빠름
-
별도의 캐시 계층을 두면 성능이 개선될 뿐 아니라 데이터베이스의 부하를 줄일 수도 있고, 캐시 계층의 규모를 확장도 가능함
- 주도형 캐시 전략 (캐시 전략은 다양하며, 캐시할 데이터 종류, 크기, 액세스 패턴에 맞는 캐시 전략을 선택하면 됨)
- 웹 서버가 요청을 받으면 캐시에 응답이 저장되어 있는지 확인 후, 저장되어 있다면 캐시에서 데이터를 클라이언트에 반환
- 없는 경우 데이터베이스 질의를 통해 데이터를 찾아 캐시에 저장한 뒤 클라이언트에 반환
- 주도형 캐시 전략 (캐시 전략은 다양하며, 캐시할 데이터 종류, 크기, 액세스 패턴에 맞는 캐시 전략을 선택하면 됨)
-
캐시는 어떤 상황에 바람직한가? 데이터 갱신은 자주 일어나지 않지만 참조는 빈번하게 일어난다면 고려가 필요
-
어떤 데이터를 캐시에 두어야 하는가? 캐시는 데이터를 휘발성 메모리에 두므로 영속적으로 보관할 데이터를 캐시에 두는 것은 바람직하지 않음.
-
캐시에 보관된 데이터는 어떻게 만료되는가? 만료 정책이 없으면 데이터는 캐시에 계속 남게 됨. 만료 기한이 너무 짧으면 데이터베이스에서 너무 자주 읽게 될 것이고, 너무 길어도 원본과 차이가 날 가능성이 높아짐
-
일관성은 어떻게 유지되는가? 저장소의 원본을 갱신하는 연산과 캐시를 갱신하는 연산이 단일 트랜잭션으로 처리되지 않는 경우 이 일관성은 깨질 수 있음.
-
장애는 어떻게 대처할 것인가? 캐시 서버를 한 대만 두는 경우 해당 서버는 단일 장애 지점이 되어버릴 가능성이 있으므로 여러 지역에 걸쳐 캐시를 분산시켜야 함
-
캐시 메모리는 얼마나 크게 잡을 것인가? 캐시 메모리가 너무 작으면 액세스 패턴에 따라서는 데이터가 자주 캐시에서 밀려나 캐시의 성능이 떨어지게 됨. 이를 막기 위한 방법으로는 캐시 메모리를 과할당 하는 방법이 있음
-
데이터 방출 정책은 무엇인가? 캐시가 꽉 차버린 경우 기존 데이터를 내보내야 함.
- LRU(Least Recently Used) : 마지막으로 사용된 시점이 가장 오래된 데이터를 내보내는 정책
- LFU(Lesat Frequently Used) : 사용된 빈도가 가장 낮은 데이터를 내보내는 정책
- FIFO(First In First Out) : 가장 먼저 캐시에 들어온 데이터를 가장 먼저 내보내는 정책
-
정적 콘텐츠를 전송하는 데 쓰이는 지리적으로 분산된 서버의 내트워크. 이미지, 비디오 CSS, JavaScript 파일 등을 캐시할 수 있음
-
동적 콘텐츠 캐싱은 요청 경로, 질의 문자열, 쿠키, 요청 헤더 등의 정보에 기반하여 HTML 페이지를 캐시 (이 책에서는 다루지 않음)
-
사용자가 웹 사이트 방문 시 그 사용자에게 가장 가까운 CDN 서버가 정적 콘텐츠를 전달
- 사용자가 CDN 서버로부터 멀면 웹 사이트는 천천히 로드됨
-
CDN의 동작 방법
- 사용자 A가 이미지 URL을 이용해 image.png height=400> 접근
- CDN 서버의 캐시에 해당 이미지가 없는 경우 서버는 원본 서버에 요청하여 파일을 가져옴
- 원본 서버가 파일을 CDN 서버에 반환
- CDN 서버는 파일을 캐시하고 사용자 A에게 반환
- 사용자 B가 같은 이미지에 대한 요청을 CDN 서버에 전송
- 만료되지 않은 이미지에 대한 요청은 캐시를 통해 처리됨
- 비용: CDN은 보통 제 3사업자에 의해 운영되므로 데이터 전송 양에 따라 요금을 내개 되어 자주 사용되지 않는 콘텐츠를 캐싱하는 것은 이득이 크지 않음
- 적절한 만료 시한 설정: 시의성이 중요한 콘텐츠의 경우 만료 시점을 잘 잡아서 너무 길어 콘텐츠의 신선도가 떨어지거나, 너무 짧아 원본 서버에 빈번히 접속하지 않도록 해야 함.
- CDN 장애에 대한 대처 방안: CDN 자체가 죽었을 경우 해당 문제를 감지하여 원본 서버로부터 직접 콘텐츠를 가져오도록 클라이언트를 구성해야 함
- 콘텐츠 무효화 방법: 만료되지 않은 콘텐츠라 하더라도 CDN에서 제거 가능
- CDN 서비스 사업자가 제공하는 API를 이용하여 콘텐츠 무효화
- 콘텐츠의 다른 버전을 서비스하도록 오브젝트 버저닝 이용
- 웹 계층을 수평적으로 확장하기 위해서는 상태 정보(사용자 세션 데이터와 같은)를 웹 계층에서 제거하여야 함
- 상태 정보를 관계형 데이터베이스나 NoSQL 같은 지속성 저장소에 보관하고 필요할 때 가져와야 함
-
상태 정보를 보관하는 서버는 클라이언트 정보, 즉 상태를 유지하여 요청들 사이에 공유되도록 함
- 사용자 A의 세션 정보나 프로파일 이미지 같은 상태 정보는 서버 1에 저장됨
- 사용자 A를 인증하기 위해 HTTP 요청은 반드시 서버 1로 전송되어야 함. 요청이 서버 2로 전송되면 서버 2에는 사용자에 관한 데이터는 없기 때문에 인증 실패
- 클라이언트로부터의 요청은 항상 같은 서버로 전송되어야 하기 때문에 문제가 발생함
- 로드밸런서가 이를 위해 고정 세션 기능을 제공하지만 로드밸런서에 부담을 주고, 서버를 추가하거나 제거하기도 까다로워짐
-
사용자로부터 HTTP 요청은 어떤 웹 서버로도 전달될 수 있음
- 웹 서버는 상태 정보가 필요할 경우 공유 저장소로부터 데잍터를 가져옴
- 상태 정보는 웹 서버로부터 물리적으로 분리되어 있어 단순하고 안정적이며 규모 확장이 쉬움
-
설계안
- 세션 데이터를 웹 계층에서 분리하고 지속성 데이터 보관소에 저장하도록 함
- 공유 저장소는 관계형 데이터베이스일 수 도 있고, Memcached/Redis 같은 캐시 시스템 혹은 NoSQL일 수 있음
- 자동 규모 확장은 트래픽 양에 따라 웹 서버를 자동으로 추가하거나 삭제하는 기능을 뜻함
- 상태 정보가 웹 서버들로부터 제거되었으므로 트래픽 양에 따라 웹 서버를 넣거나 빼기만 하면 자동으로 규모 확장 가능
- 세션 데이터를 웹 계층에서 분리하고 지속성 데이터 보관소에 저장하도록 함
-
웹 사이트가 매우 빨리 성장하여 전 세계 사용자의 이목을 받는 경우, 가용성을 높이고 전 세계 어디서도 쾌적하게 사용할 수 있도록 함
-
두 개의 데이터 센터를 이용하는 경우, 장애가 없는 상황에서 사용자는 가까운 데이터 센터로 안내됨 (지리적 라우팅 이라고 함)
- 지리적 라우팅에서 geo DNS는 사용자의 위치에 따라 도메인 이름을 어떤 IP 주소로 변환할지 결정함
- 이 예제에서는 그 결과로 x% 사용자를 US-East 센터로, (100-x%) 사용자는 US-West 센터로 안내됨
- 지리적 라우팅에서 geo DNS는 사용자의 위치에 따라 도메인 이름을 어떤 IP 주소로 변환할지 결정함
-
데이터 센터 중 하나에 장애가 발생한 경우 모든 트래픽은 장애가 없는 데이터 센터로 전송됨
- 트래픽 우회: 올바른 데이터 센터로 트래픽을 보내는 효과적인 방법을 찾아야 함.
- 데이터 동기화: 데이터 센터마다 별도의 데이터베이스를 사용하고 있으면 장애가 자동으로 복구되어 트래픽이 다른 데이터베이스로 우회된다 해도, 해당 데이터센터에는 찾는 데이터가 없을 수 있기 때문에 데이터를 여러 데이터센터에 걸쳐 다중화가 필요
- 테스트와 배포: 여러 데이터 센터를 사용하도록 시스템이 구성된 상황이라면 웹 사이트 또는 애플리케이션을 여러 위치에서 테스트해 보는 것이 중요. 자동화된 배포 도구는 모든 데이터 센터에 동일한 서비스가 설치되도록 중요한 역할을 함
-
시스템을 더 큰 규모로 확장하기 위해서는 시스템의 컴포넌트를 분리하여, 각기 독립적으로 확장될 수 있도록 해야 함.
-
메세지 큐는 많은 실제 분산 시스템이 채용하고 있는 핵심적인 전략
-
메시지 큐는 메시지의 무손실을 보장하는 비동기 통신을 지원하는 컴포넌트.
- 메시지의 버퍼 역할을 하며 비동기적으로 전송.
- 생산자 또는 발행자라고 불리는 입력 서비스가 메시지를 만들어 메시지 큐에 발행하면, 메세지 큐에 연결된 소비자 혹은 구독자가 메시지를 받아 그에 맞는 동작을 수행
-
메세지 큐를 이용하면 서비스 또는 서버 간 결합이 느슨해져 규모 확장성이 보장되어야 하는 안정적 애플리케이션을 구성하기 좋음
-
생산자는 소비자 프로세스가 다운되어 있어도 메세지를 발행할 수 있고, 소비자는 생산자 서비스가 가용 상태가 아니어도 메세지를 수신할 수 있음
- 소규모 웹 사이트에서는 로그나 메트릭, 자동화가 필수는 아니지만, 사업 규모가 커지면 이러한 도구에 투자가 필수적
- 로그: 에러 로그를 모니터링하여 시스템의 오류와 문제들을 보다 쉽게 찾아낼 수 있어야 함. 서버 단위 모니터링도 가능하지만, 단일 서비스로 모아주는 도구를 활용하면 더 편리하게 검색하고 조회할 수 있음
- 메트릭: 사업 현황에 관한 유용한 정보를 얻으며 시스템의 현재 상태를 손쉽게 파악 가능.
- 호스트 단위 메트릭: CPU, 메모리, 디스크 I/O
- 종합 메트릭: 데이터베이스 계층의 성능, 캐시 계층의 성능 등
- 핵심 비즈니스 메트릭: 일별 능동 사용자, 수익, 재방문 등
- 자동화: 시스템이 크고 복잡해지면 생산성을 높이기 위해 자동화 도구를 활용해야 함
- 지속적 통합을 도와주는 도구를 활용하면 개발자가 만드는 코드가 어떤 검증 절차를 자동으로 거치도록 할 수 있어 쉽게 문제를 감지할 수 있음
- 빌드, 테스트, 배포 등의 절차를 자동화하면 개발 생산성을 크게 향상시킬 수 있음
- 기존 서버에 더 많은, 고성능의 자원(CPU, RAM, 디스크)을 증설하는 방법
- 데이터베이스 서버 하드웨어에는 한계가 있어 CPU, RAM 등을 무한히 증설할 수 있음. 사용자 증가 시 한 대 서버로는 감당이 어려워짐
- SPOF로 인한 위험성이 큼
- 비용이 많이 듬. 고성능 서버로 갈 수록 가격이 비싸짐
-
데이터베이스의 수평적 확장은 샤딩이라고도 하며, 더 많은 서버를 추가함으로써 성능을 향상시킴
-
샤딩은 대규모 데이터베이스를 샤드로 부르는 작은 단위로 분할하는 기술
-
모든 샤드는 같은 스키마를 쓰지만 샤드에 보관되는 데이터는 중복이 없음
-
샤드로 분할된 데이터베이스의 예
- 사용자 데이터를 어느 샤드에 넣을지는 사용자 ID에 따라 결정됨.
- user_id % 4 를 해시 함수로 사용하여 데이터가 보관되는 샤드를 정함
-
샤딩 전략을 구현할 때 고려해야 할 가장 중요한 것은 샤딩 키를 정하는 것으로, 데이터가 어떻게 분산될지 정하는 하나 이상의 컬럼으로 구성됨
-
샤딩 키를 통해 올바른 데이터베이스에 질의를 보내어 데이터 조회나 변경을 처리하므로 효율을 높일 수 있음
-
샤딩 키를 정할 때는 데이터를 고르게 분할 할 수 있도록 하는 것이 중요
-
샤딩을 도입할 경우 풀어야할 문제
- 데이터의 재 샤딩
- 데이터가 너무 많아져서 하나의 샤드로는 감당하지 못할 때
- 샤드 간 데이터 분포가 균등하지 못하여 어떤 샤드에 할당된 공간 소모가 다른 샤드에 비해 빨리 진행될 때
- 샤드 소진 현상이 발생하면 샤드 키를 계산하는 함수를 변경하고 데이터를 재배치하여야 함
- 안정 해시 기법을 활용하면 이 문제를 해결할 수 있음
- 유명인사 문제: 핫스팟 키 문제라고도 불리우며, 특정 샤드에 질의가 집중되어 서버에 과부하가 걸리는 문제
- 케이티 페리, 저스틴 비버, 레이디 가가 같은 유명인사가 전부 같은 샤드에 저장되는 데이터베이스가 있는 경우
- 이 데이터로 사회관계망 애플리케이션을 구축하게 되면 결국 해당 샤드에는 read 연산 때문에 과부하가 걸리게 될 것
- 이 문제를 풀기 위해서는 유명인사를 각각에 샤드 하나씩을 할당하거나 더 잘게 쪼개야 함
- 조인과 비정규화
- 하나의 데이터베이스를 여러 샤드 서버로 쪼개고 나면 여러 샤드에 걸친 데이터를 조인하기 힘들어짐
- 이를 해결하기 위해서는 데이터베이스를 비정규화하여 하나의 테이블에서 질의가 수행될 수 있도록 하는 것
- 데이터의 재 샤딩
- 정리
- 웹 계층은 무상태 계층으로
- 모든 계층에 다중화 도입
- 가능한 한 많은 데이터를 캐시할 것
- 여러 데이터 센터를 지원할 것
- 정적 콘텐츠는 CDN을 통해 서비스할 것
- 데이터 계층은 샤딩을 통해 그 규모를 확장할 것
- 각 계층은 독립적 서비스로 분할할 것
- 시스템을 지속적으로 모니터링하고 자동화 도구들을 활용할 것