가상 면접 사례로 배우는 대규모 시스템 설계 기초 -1-
사용자 수에 따른 규모 확장성
단일 서버
모든 컴포너트가 단 한대의 서버에서 실행되는 간단한 시스템. 웹 앱, 데이터베이스, 캐시 등이 전부 서버 한 대에서 실행한다
사용자 요청 흐름
도메인 서버(DNS) 질의 → IP 주소 획득 → 해당 IP 주소로 Http 요청 전달 → 서버는 요청 반환
- http 프로토콜 반환 데이터는 주로 json이 사용된다. (xml 등 사용 가능)
step1. 트래픽이 늘 경우 단일 서버로 부족하다. 서버를 사용자 트래픽 처리 용도와 데이터 베이스 용도로 나눈다.
데이터 베이스 서버
관계형 데이터 베이스와 비-관계형 데이터 베이스가 있음
- SQL : 테이블, 열, 컬럼으로 표현한다. 데이터를 관계에 따라 조인한다
- NOSQL : 키-값 형태, 그래프 저장, 문서 저장등이 있다. 일반적으로 조인 연산을 지원하지 않는다.
- 아주 낮은 응답 지연시간이 요구된다. - 사용자에게 빠르게 응답해야 한다
- 다루는 데이터가 정형화 되어있지 않다 (데이터가 수시로 변경되는 경우)
- 데이터를 직렬화 하거나 역직렬화 할 수 있기만 하면 된다. (Join 연산 필요 없을 경우)
- 아주 많은 양의 데이터를 저장해야 한다
수직적 확장과 수평적 확장
수직적 확장
- 장점 : 단순함
- 단점 : 무한대로 cpu나 메모리를 증설할 수 없는 한계가 있음, 장애에 대한 복구가 불가능
수평적 확장
- 장점 : 서버를 증설하기 쉽다. 장애에 유연한 대처가 가능(fail over, 다중화 가능)
- 단점 : 설계가 어렵다
로드 밸런서
웹 서버들에게 트래픽 부하를 고르게 부산하는 역할
사용자는 로드밸런서를 통해 공개 ip에 접근하고 로드 밸런서가 웹 서버에게 응답을 포워딩 해주는 방식. 사용자는 공개 ip 밖에 모르므로 보안에도 장점이 있다. 웹 서버들은 사설 ip 주소(lan 영역이나 vpn)등으로 통신한다.
웹 어플리케이션 다중화 - 서버를 똑같이 만들어서 로드 밸런서에 연결만 해주면 쉽게 확장 가능
데이터베이스 다중화
보통 master-slave 관계를 설정한다. 원본 데이터는 master에 사본은 slave에 전달한다. (레플리케이션 구조)
쓰기 연산은 마스터만 지원한다.
다중화 이점
- 성능 : 읽기 노드와 다수의 쓰기 노드로 인해 트래픽 분산 가능
- 안정성 : 데이터를 복제하여 저장하고 있으므로 데이터 복원 가능
- 가용성 : 데이터 베이스 장애시 서비스 유지 가능(레플리케이션에서 마스터 장애시 슬레이브 승격, 슬레이브 데이터 백업 등)
- tip HBAHBA 란MHA에 의해서 장애 발생시 자동 Fail-Over(Master 승격)를 지원하고 Slave 중 가장 최신의 Slave DB를 Master DB로 승격시켜 고가용성을 유지 시키는 역할을 한다
- 마스터 DB 장애를 최대한 단축하기 위한 오픈소스 프로그램
- 출처 : https://hoing.io/archives/9175
사용자 응답 시간은 캐시를 통해 개선하고, 정적 콘텐츠의 트래픽이 많다면 CDN으로 옮겨서 응답 속도를 개선한다
캐시
연산 결과나 자주 참조되는 데이터를 메모리에 두어서 요청이 빠르게 처리할 수 있게 하는 저장소
애플리케이션의 성능은 데이터 베이스를 적게 호출 할 수록(disk i/o 가 적을 수록) 좋다.
별도의 캐시 계층을 두면 성능이 개선 될 뿐만 아니라 데이터 베이스의 부하를 줄일 수 있다. 도한 캐시 계층의 규모를 독립적으로 확장/축소 할 수 있어 확장성이 좋다
캐시 사용 시 고려할 점
- 데이터 갱신은 자주 일어나지 않지만 참조가 번번이 일어날 때 유용하다
- 캐시는 휘발성이므로 영속적으로 보관할 데이터를 캐시에만 저장하는 것은 바람직하지 않다
- 캐시는 만료 정책을 정해야 한다. 만료 시간이 없으면 데이터가 캐시에 계속 남는다.(비효율적이다)
- 캐시는 일관성을 유지해야 한다. 데이터의 원본 저장소와 캐시 데이터와 같아야 한다. 주의 : 저장소의 원본을 갱신하는 연산과 캐시를 갱신하는 연산이 단일 트랜잭션 내에서 처리되지 않을 경우 일관성이 깨질 수 있음
- 장애는 어떻게 대처할 지 고려해야 한다. 캐시 서버가 한대 일 경우 캐시 서버가 장애가 날 경우 단일 장애 지점이 될 수 있다. 따라서 여러 지역에 걸쳐 캐시 서버를 분산해야 한다
- 단일 장애 지점 : 특정 지점에서 장애가 전체 시스템의 동작을 중단시켜버릴 수 있는 경우, 해당 지점을 단일 장애 지점이라 부른다.(SPOF)
- 캐시 메모리의 영역은 어떻게 잡을 것인가. 캐시 메모리가 너무 작다면 엑세스 패턴에 따라 캐시 히트율이 떨어져 성능이 떨어 질 수 있다. 캐시 메모리를 충분하게 할당하자
- 데이터 방출 정책을 어떻게 결정할 것인가. 캐시가 다 차버린 경우에는 기존의 캐시 데이터를 내보내야 한다. 다양한 정책이 사용된다. LRU, LFU, FIFO (FIFO의 경우 Belady의 역설이 일어날 수 있다 http://melonicedlatte.com/2020/10/13/003700.html)
콘텐츠 전송 네트워크(CDN)
정적 콘텐츠를 전송하는 데 쓰이는, 분산된 서버 네트워크. 이미지, 비디오, CSS, JavaScript 캐시 가능하다.
요청 경로, 질의 문자열, 쿠키, 요청 헤더 등의 정보에 기반하여 html 페이지를 캐시하는 것이다
사용자가 웹 사이트 방문시 가장 가까운 CDN 서버가 정적 콘텐츠를 전달한다. CDN 서버의 캐시에 해당 이미지가 없는 경우 원본 서버에 요청하여 파일을 가져온다. 파일은 캐시에 저장된다. 이후 같은 이미지 요청의 경우 캐시를 이용하여 사용자에게 전달한다.
*tip : 이미지에 버지닝(+ v1, v2...)을 하거나 cdn provider가 제공하는 api를 통해 콘텐츠를 무효화 할 수 있다
무상태 웹 계층
Http 프로토콜 자체는 무상태 프로토콜이지만, 사용자 로그인 정보와 같은 세션 상태 정보를 가지고 있어야 할 때가 있다. 따라서 사용자의 세션 정보를 가지고 있는 서버에게 사용자 요청을 주는 sticky 세션 기능을 제공한다. 하지만 이는 서버 확장성과 로드밸런싱에 비효율적이다.
따라서 사용자의 상태 정보를 다른 저장소에 보관하여 웹 계층과 분리하는 전략을 사용한다. 상태 정보는 필요할 때만 가져오고 웹 계층 자체는 상태가 없도록 유지한다.
데이터 센터
장애가 없는 상황에서 사용자는 가장 가까운 데이터 센터로 안내된다. 이 절차를 지리적 라우팅(geoDns)라고 부른다. 지리적 라우팅에서 geoDNS는 사용자 위치에 따라 도메인 이름을 어떤 IP 주소로 변환할지 결정한다
데이터 센터 고려 사항
- 트래픽 우회 : 올바른 데이터 센터로 보내는 방법이 필요하다
- 데이터 동기화 : 데이터 센터마다 별도의 데이터베이스를 사용한다면 데이터를 동기화를 해주어야 하며 장애에 대응할 수 있어야 한다
- 테스트와 배포 : 모든 데이터 센터에서 동일한 서비스를 할 수 있도록 구축해야 한다
메시지 큐
메시지의 무손실을 보장하는, 비동기 통신을 지원하는 컴포넌트다.
메시지 큐 아키텍쳐
- 생산자가 메시지를 만들어 메시지 큐에 발행한다.
- 큐에 소비자가 연결되어 있다(서비스 or 서버).
- 소비자는 큐에 메시지를 소비하여 맞는 동작을 수행한다
생산자는 소비자 프로세스가 다운 되어 있어도 메시지를 발행 할 수 있고, 소비자는 생산자 서비스가 가용한 상태가 아니더라도 메시지를 수신할 수 있다
메시지 큐를 이용하면 서비스 또는 서버 간 결합이 느슨해진다. 또한 큐를 확장하기 쉬워 규모 확장을 보장하는 안정적 애플리케이션을 구성할 수 있다
대표적인 메시지 큐 : Rabbitmq, kafka
Rabbitmq와 kafka 비교
https://programming-workspace.tistory.com/69
로그, 메트릭, 자동화 도구들
규모가 작을 때는 상관 없지만 규모가 커졌을 때 관리하기 위해 필요한 기능들이다
로그
시스템의 오류와 문제들을 보다 쉽게 찾아 낼 수 있도록 모니터링 하기 위한 필요하다. 특정 이벤트가 발생 했을 때 기록
메트릭
시스템의 상태나 유용한 정보를 손쉽게 파악하기 위해 필요하다. 주기적으로 결과를 기록
- 호스트 단위 메트릭 : CPU, 메모리, 디스크 I/O 관한 메트릭
- 종합 메트릭 : 데이터 베이스 계층 성능, 캐시 계층 성능 등에 관한 메트릭
- 핵심 비지니스 메트릭 : 일별 능동 사용자, 수익, 재방문 등이 해당 된다
자동화
생산성을 높이고 실행 환경을 쉽게 구축할 수 있게 만들어 주는 기능(ex 지속적인 통합/CI , 지속적인 배포/CD)
데이터 베이스 규모 확장
수평적 규모 확장과 수직적 규모 확장이 있다.
수직적 규모 확장
기존 서버에 성능을 높이는 방식
단점 : 서버의 성능 한계가 존재한다, SPOF의 위험성이 크다. 비용이 많이 든다
수평적 규모 확장
다수의 서버를 늘려서 확장하는 방식
파티셔닝과 샤딩으로 데이터를 분할해서 저장하는 방식
샤딩은 데이터를 샤딩 키로 어떻게 분산될지 정한다.
샤딩시 고려해야 할점
- 데이터의 재 샤딩 : 데이터가 너무 많아져서 하나의 샤드로 감당 못할 때, 샤드간 데이터 불균형이 생겨 어떤 샤드에 할당된 공간 소모가 다른 샤드에 빨리 진행될때(샤드 소진) 데이터를 재배치 해야 한다
- 유명인사 문제 : 특정 샤드에 질의가 집중되어 서버에 과부하가 걸리는 문제를 해결해야 한다. 유명인사는 샤드를 하나씩 더 할당 하는 등으로 문제를 처리한다
- 조인과 비정규화 : 여러 샤드에 걸친 데이터를 조인하기 어려워진다.
기법 정리
- 웹 계층은 무상태 계층으로
- 모든 계층에 다중화 도입
- 가능한 많은 데이터 캐시할 것
- 여러 데이터 센터를 지원할 것
- 정적 콘텐츠는 CDN을 통해 서비스 할 것
- 데이터 계층은 샤딩을 통해 규모를 확장할 것
- 각 계층은 독립적 서비스로 분할 할 것
- 시스템을 모니터링 하고 자동화 도구를 활용할 것
개략적인 규모 추정
통상적인 컴퓨터에서 구현된 연산들의 응답지연 값
- L1 캐시 참조(가장 속도가 빠름) →
- 분기 예측 오류 →
- L2 캐시 참조 →
- 뮤텍스 락/언락 = 주메모리 참조 →
- Zippy로 1KB 압축 →
- 1Gbps 네트워크로 2KB 전송 →
- 메모리에서 1MB 순차적으로 READ →
- 같은 데이터 센터 내에서 메시지 왕복 지연 시간 = 디스크 탐색 = 네트워크에서 1MB 순차적으로 READ →
- 디스크 에서 1 MB 순차적으로 READ →
- 한 패킷의 CA로부터 네덜란드까지의 왕복 지연 시간
결론
- 메모리는 빠르지만 디스크는 아직도 느리다
- 디스크 탐색은 가능한 피하라
- 단순한 압축 알고리즘은 빠르다
- 데이터를 인터넷으로 전송하기 전에 가능하면 압축하라
- 데이터 센터는 분산 되어 있고 센터 간에 데이터를 주고 받는데는 시간이 걸린다
면접 TIP
- 근사치를 활용하여 계산하라
- 가정들은 적어두라. 나중에 살펴보기 위해
- 단위를 붙여라. 모호함을 없애기 위해
- 많이 출제되는 개략적 규모 추정 문제는 QPS, 최대 QPS, 저장소 요구량, 캐시 요구량, 서버 수 등을 추정하는 것이다
효과적인 면접을 위한 4단계 접근법
- 문제 이해 및 설계 범위 확정
- 깊이 생각하고 질문하여 요구사항과 가정들을 분명히 하라
- 개략적인 설계안 제시 및 동의 구하기
- 설계안에 대한 최초 청사진을 제시하고 의견을 구하라
- 화이트보드나 종이에 핵심 컴포넌트를 포함하는 다이어그램을 그려라
- 최초 설계안이 시스템 규모와 관계된 제약사항들을 만족하는지 계산해 보라
- 상세 설계
- 마무리