- [가상 면접 사례로 배우는 대규모 시스템 설계 기초] 1장 사용자 수에 따른 규모 확장성2024년 11월 21일 16시 00분 44초에 업로드 된 글입니다.작성자: @kimyu0218
시스템 아키텍처를 보면 웹 서버와 DB 서버를 분리한 경우를 많이 볼 수 있다. 웹 서버와 DB 서버를 분리하면 각각 독립적으로 확장할 수 있기 때문이다. 지금부터 시스템 규모 확장 방법을 알아보자.
수직 확장 vs. 수평 확장
시스템 확장에는 크게 수직, 수평 확장 두 가지가 있다.
- 수직 확장 (scale up) : 고사양 자원을 사용하여 서버의 성능을 높인다.
- 수평 확장 (scale out) : 더 많은 자원을 추가하여 성능을 높인다.
수직 확장은 쉽게 성능을 향상시킬 수 있지만, 무한대로 확장할 수 없기에 성능 향상에 한계가 있으며, 자동 복구(= failover)나 다중화(= redundancy)도 할 수 없다. 즉, 아무리 성능이 높은 서버라도 장애가 발생하면 더 이상 서비스를 이용할 수 없다. 따라서 대규모 애플리케이션에서는 수평 확장이 더 적절하다.
로드밸런서
서버가 하나인 시스템에서 과도한 트래픽으로 인해 서버가 다운되면, 사용자는 서비스를 이용할 수 없다. 이를 예방하기 위해 로드밸런서를 사용한다.
사용자가 로드밸런서의 ip 주소로 접근하면, 로드밸런서는 target group에 속한 웹 서버들에게 트래픽 부하를 고르게 분산시킨다. 한 서버가 다운되더라도 target group에 정상적인 서버가 존재한다면, 지속적으로 서비스하여 가용성을 보장할 수 있다.
데이터베이스 확장
이번엔 DB 부하 및 장애를 해결하는 방법을 알아보자.
데이터베이스 다중화 : master-slave
일반적으로 DB는 master-slave 관계를 설정하여 다중화를 구현한다.
master 서버 slave 서버 write 연산 read 연산 데이터 원본 데이터 사본 write 연산은 오직 master에서만 일어난다. slave는 master로부터 사본을 전달받고 read 연산을 지원한다. read 연산이 write 연산보다 많기 때문에 대체로 slave의 수가 master보다 많다.
- 성능 : 연산을 병렬로 처리할 수 있다.
- 안정성 : 자연 재해 등으로 일부 서버가 파괴되어도 지역적으로 분산되어 있다면 데이터를 보존할 수 있다.
- 가용성 : 일부 서버에 장애가 발생해도 다른 서버에서 계속 서비스할 수 있다.
slave가 다운되면 master가 일시적으로 읽기/쓰기 연산을 수행한다. 반면, master가 다운되면 slave가 새로운 master가 되에 쓰기를 담당한다. 이때, slave가 최신 상태가 아니라면 recovery script를 통해 이전 master에서 수행한 연산을 바탕으로 데이터를 수정해야 한다.
데이터베이스 수평 확장 : 샤딩
데이터베이스 수평 확장은 샤딩이라고도 부른다. 샤딩은 DB를 샤드라는 작은 단위로 분할하는 기술이다. 모든 샤드는 같은 스키마를 사용하지만 서로 다른 데이터를 보관한다.
샤딩을 구현할 때 가장 중요한 것은 파티션 키(= 샤딩 키)로, 데이터를 어떻게 분산시킬지 정한다. 파티션 키는 하나 이상의 칼럼으로 구성되며 데이터를 고르게 분할할 수 있는 칼럼을 선정해야 한다.
샤딩은 데이터를 여러 데이터베이스에 나누어 보관하기 때문에 부하를 방지하지만, 시스템이 복잡해지기에 새로운 문제가 발생한다.- resharding : 데이터가 감당할 수 없을 정도로 많아졌거나 샤드 간 데이터 분포가 균등하지 못해 어떤 샤드가 다른 샤드보다 공간이 빨리 소모되면, 새로운 샤드를 만들어야 한다.
- celebrity (= hotspot key) : 특정 샤드에 질의가 집중되어 특정 서버만 과부하가 걸릴 수 있다.
- 비정규화 : 데이터를 여러 샤드에 분할하여 저장하기 때문에 여러 샤드에 걸친 JOIN 연산이 어려워진다. 하나의 샤드에서 질의가 수행될 수 있도록 비정규화가 필요하다.
💡 재샤딩 시 안정 해시를 활용하면 데이터 불균형을 해결할 수 있다.
응답 시간 줄이기 (feat. 캐시 & CDN)
캐시
캐시는 일시적으로 데이터를 저장하는 메모리 공간이다. 디스크보다 속도가 훨씬 빠르기 때문에 응답 시간을 개선할 수 있다. 실제로 애플리케이션 성능은 DB를 얼마나 자주 호출하느냐에 따라 좌우된다.
캐시는 우선 읽기 전략을 통해 DB 부하를 예방한다.
- 클라이언트가 데이터를 요청한다.
- 캐시에 요청한 데이터가 있는지 확인하고, 있으면 캐시에서 데이터를 반환한다.
- 요청한 데이터가 캐시에 없는 경우, 디스크로부터 데이터를 조회하고 캐시에 저장하여 이후 요청에 빠르게 응답할 수 있도록 한다.
하지만 캐시를 무분별하게 사용해서는 안된다. 캐시는 휘발성 메모리이기 때문에 영속적인 데이터를 보관해선 안되며, 적절한 만료 기간을 설정하여 공간을 계속 점유하는 것을 막아야 한다.
CDN; Contents Delivery Network
CDN은 정적 콘텐츠를 전송하는 데 사용되는, 지리적으로 분산된 서버 네트워크다.
CDN 유의사항에 앞서 동작 과정을 살펴보자. 앞서 설명한 캐시와 유사하게 동작한다. 사용자가 CDN을 사용하는 웹사이트에 방문하면, 사용자와 가장 가까운 CDN 서버가 정적 콘텐츠를 전달한다. 요청한 콘텐츠가 CDN 캐시에 없다면, 서버에서 원본 파일을 받아온다. CDN은 파일을 캐싱하고 사용자에게 응답을 보낸다.
하지만 CDN도 다음 사항을 고려해야 한다.- CDN은 보통 써드 파티가 운영하므로 데이터 전송양에 따라 요금이 발생한다. 따라서 자주 사용되지 않는 콘텐츠는 CDN에서 제외하여 비용을 절약해야 한다.
- 적절한 만료 기간을 설정하여 콘텐츠의 신선도가 떨어지지 않도록 해야 한다.
- CDN에 장애가 발생해도 원본 서버로부터 정적 콘텐츠를 받아볼 수 있어야 한다.
- 아직 만료되지 않은 콘텐츠여도 새로운 콘텐츠가 등장할 수 있다. 버저닝(ex. `image.png?v=2`)을 통해 최신 버전을 서비스해야 한다.
웹 수평 확장의 핵심, stateless
HTTP는 상태 정보를 저장하지 않는다. 상태 정보가 없기 때문에 항상 요청에 필요한 모든 값을 전달해야 한다. 전송되는 데이터양이 많지만, 장애 여부와 관계없이 서버가 복구되기만 하면 정상적으로 처리할 수 있다. 만약 상태 정보를 저장한다면, 장애 발생 시 이전 정보가 날라가기 때문에 요청이 실패할 것이다.
stateless는 수평 확장의 필수 조건이다. 웹 서버가 여러 개인 경우를 가정해보자. `A 서버`가 `C 사용자`의 상태 정보를 저장하고 있는 상황에서 `C 사용자`의 요청이 `B 서버`로 간다면 요청이 제대로 처리되지 않을 수 있다. 따라서 상태를 유지하지 않고, 항상 필요한 모든 값을 전달하여 어느 웹 서버에서도 제대로 동작할 수 있도록 해야 한다.데이터 센터
데이터 센터는 컴퓨팅 시스템과 장비가 위치한 물리적 지역을 의미한다. 다중 데이터 센터를 이용하면, 한 데이터 센터에 장애가 발생해도 다른 데이터 센터로 라우팅되기 때문에 가용성을 보장한다. 장애가 없는 경우, 사용자 요청은 가장 가까운 데이터 센터로 라우팅된다.
고가용성을 위해서는 다음 기술들이 필요하다.- geoDNS-routing : 사용자에게 가장 가까운 데이터 센터로 트래픽을 보내야 한다.
- 데이터 동기화 : 데이터 센터마다 별도의 DB를 사용하고 있고 하나의 센터에서 장애가 발생한 상황이라면, failover 할 수 있도록 데이터가 여러 데이터 센터에 걸쳐 다중화되어 있어야 한다.
메시지 큐
메시지 큐는 durability를 보장하는 비동기 통신 기술이다. 메시지 큐는 다음과 같이 구성되어 있다.
- 생산자 (= publisher = producer) : 메시지를 메시지 큐에 발행한다
- 소비자 (= subscriber = consumer) : 메시지큐에서 메시지를 받아 처리한다
- 메시지 큐
메시지 큐에 보관된 메시지는 소비자가 꺼내기 전까지 안전하게 보관된다는 특징이 있다. 생산자는 소비자가 다운되어 있어도 메시지를 발행할 수 있고, 소비자가 가용한 상태가 아니어도 메시지를 수신할 수 있다. 또한, 메시지 큐를 이용하면 서비스 간의 결합도가 낮아지기 때문에 각 부분을 독립적으로 개발하고 운영할 수 있어 확장성도 높다.
메시지 큐의 사용 예시로는 사진 보정 애플리케이션을 들 수 있다. 시간이 많이 소요되는 사진 보정 작업을 메시지 큐에 넣고, 사진 보정 프로세스를 수행하는 워커가 메시지 큐에서 이를 꺼내 비동기적으로 수행한다.
💡 메시지 큐 종류에는 Kafka, RabbitMQ, JMS 등이 있다.
'학습기록 > 독서' 카테고리의 다른 글
[Good Code, Bad Code] 2장 추상화 계층 (0) 2024.02.01 [Good Code, Bad Code] 1장 코드 품질 (1) 2024.01.24 다음글이 없습니다.이전글이 없습니다.댓글