기타

[가상 면접 사례로 배우는 대규모 시스템 설계 기초] 1. 사용자 수에 따른 규모 확장성

jammmm 2025. 2. 4. 22:39
반응형

기술 인터뷰 중 '대규모 트래픽을 감당해야 하는 경우 시스템을 어떻게 설계할 것인가' 라는 질문을 받은 적이 있다. 대규모 트래픽, 대용량 데이터에 대한 솔루션들의 중요성은 알고있지만 실무에서 경험이 없어 제대로 공부해보지 못했다. 이번 기회에 '가상 면접 사례로 배우는 대규모 시스템 설계 기초' 책을 기반으로 관련 내용들을 공부하고 이를 정리하려 한다.

단일 서버

단일 서버로 구성되어 있는 시스템에 대해서 생각해보자. 이 시스템은 웹앱, DB, 캐시 등을 하나의 단일 서버에서 실행한다.

시스템에 사용자의 요청이 도달하여 처리하는 과정은 다음과 같다.

 

클라이언트: 사용자에 의해서 특정 도메인에 대한 요청 생성
-> DNS: 도메인 이름을 IP 주소로 변환
-> 클라이언트: 반환된 IP 주소로 HTTP 요청을 전달
-> 웹 서버: 도착한 요청에 대한 응답을 다시 클라이언트로 반환

데이터베이스

서비스 운영을 위해 데이터를 저장하기 위해서는 데이터베이스가 필요하다. 이때 우리는 관계형 데이터베이스 (RDB)와 비 관계형 데이터베이스 (NoSQL) 중 어떤 DB를 사용할지 정해야한다.

 

일반적으로 행열로 구성된 테이블에 데이터를 저장하고 테이블간의 관계에 따라 조인을 이용한 조회가 필요하다면 관계형 데이터베이스를 사용하는 것이 좋다. 하지만 낮은 응답 지연시간 (latency), 비정형 데이터의 저장, 데이터 직렬화/역직렬화 (JSON, YAML, XML 등), 많은 양의 데이터 저장 등의 기능이 필요한 경우에는 비 관계형 데이터베이스를 고려해봐야 한다.

수직적 규모 확장 vs 수평적 규모 확장

서버의 성능을 개선하기 위한 방법으로 두가지 방법을 얘기한다. CPU와 메모리를 늘려서 현재 서버의 스펙을 높이는 것을 '스케일 업' 또는 '수직적 규모 확장' 이라고 한다. 반대로 기존 서버외에 서버를 추가로 구성하여 성능을 개선하는 방법을 '스케일 아웃' 또는 '수평적 규모 확장' 이라고 한다.

 

수직적 규모 확장은 비교적 간단하게 서버의 성능을 개선할 수 있기 때문에 트래픽이 작은 서버에서는 고려해볼만 한 좋은 방법이다. 하지만 서버의 리소스를 무한정 늘릴 수 없고, 다중 서버가 아니기에 서버에 장애가 발생하는 경우 서비스가 바로 중단되어 버리는 문제가 발생한다. 이때문에 대규모 애플리케이션을 지원하는 경우에는 수직적 규모 확장보다는 수평적 규모 확장을 적용한다.

- 로드밸런서

로드밸런서는 부하 분산 집합(load balancing set)에 속한 웹 서버들에게 트래픽 부하를 고르게 분산하는 역할을 한다. 분산처리로 인해 응답속도를 향상할 뿐 아니라 여러대의 서버를 운용함으로 하나의 서버가 죽어도 다른 서버가 요청을 처리함으로 서비스가 중단되지 않는다. 이외에도 클라이언트가 웹 서버에 직접 접속하지 않기 때문에 웹 서버의 IP를 숨기고 보안적인 이점을 취할 수 있다.

- 데이터베이스 다중화

대부분의 DBMS 들은 다중화를 지원한다. 보통은 master - slave 관계를 설정하여 구성한다.

사본 DB 서버를 여러대 두어서 일반적으로 많이 발생하는 읽기 연산을 처리하도록 하고 데이터의 정합성이 중요한 쓰기 연산은 마스터에서 처리하도록 한다. 이를 통해 병렬로 처리할 수 있는 쿼리의 양을 늘려서 성능을 개선하고, 여러 서버가 같은 데이터를 가지도록 하여 일부가 파괴되거나 장애가 발생해도 이를 대체하고 데이터를 다시 로드하여 서비스 할 수 있도록 한다.

 

DB 서버 중 하나가 죽는 경우에는 다른 서버가 이를 대체하도록 한다. 만약 마스터 서버가 죽는 경우 사본 서버 중 하나가 이를 대체하는데, 이때 사본의 데이터를 최신화하기 위한 처리 로직, 스크립트 등이 필요하다.

캐시

캐시는 연산이 오래 걸리는 데이터나 자주 참조되는 데이터를 메모리에 저장하여 요청을 빠르게 처리할 수 있도록 하는 저장소다. 데이터가 잠시 보관되는 곳으로 DB보다 훨씬 빠르다. 이를 통해서 성능의 개선과 DB 서버에 대한 부하를 완화할 수 있다.

- 읽기 주도형 캐시 전략 (read-through caching strategy)

웹 서버에 요청이 들어오면 캐시를 먼저 확인한다. 캐시에 데이터가 저장되어 있다면 해당 데이터를 반환한다. 없는 경우에는 DB에서 조회하여 캐시에 저장한 뒤 클라이언트로 반환한다.

 

캐시를 도입할 때는 다음과 같은 요소들에 대해서 고려해야한다.

- 데이터의 갱신과 조회가 일어나는 빈도
- 데이터 영속성 여부에 따른 캐시의 위치
- 캐시에 저장된 데이터의 만료 정책, 기한
- 캐시와 데이터 저장소 (주로 DB) 간의 데이터 일관성
- 장애 발생 대책
- 캐시 메모리의 크기
- 메모리가 꽉 찬 경우의 데이터 방출 정책

콘텐츠 전송 네트워크 (CDN)

CDN은 정적 콘텐츠를 전송하는데 쓰이는, 지리적으로 분산 서버의 네트워크이다. 이미지, 비디오, CSS, JavaScript 파일 등을 서버에 저장하여 사용자가 지리적으로 가까운 서버에 접근함으로 빠르게 파일을 전송할 수 있도록 한다.

 

사용자는 URL로 특정 컨텐츠에 접근한다. 이 URL은 CDN 서비스에서 제공한 것으로 해당 URL에 대응되는 CDN 서버에 파일이 있는 경우 이를 반환한다. 만약 파일이 없는 경우 원본 서버에 요청하여 파일을 가져와 CDN 서버에 저장한 후 해당 파일을 사용자에게 반환한다. 파일은 TTL (Time-To-Live)에 명시된 시간만큼 CDN 서버에 저장된다.

 

CDN은 보통 서드파티를 사용하기 때문에 이를 사용하는데 따른 비용을 고려해야 한다. 또한 콘텐츠의 만료 시한에 대한 설정과 장애에 대한 대처 방안, 만료되지 않은 콘텐츠를 제거하기 위한 콘텐츠 무효화 방법 등에 대해서도 고려해야 한다.

무상태(stateless) 웹 계층

서버를 여러대 운용하여 웹 계층을 수평적으로 확장하기 위해서는 사용자 정보, 세션 데이터와 같은 상태 정보가 특정 서버에 종속되는 것이 아니라 모든 웹 서버가 공유할 수 있어야 한다. 이를위해 상태 정보를 DB와 같은 지속성 저장소에 보관하고 필요할 때 조회하여 요청을 처리하도록 한다. 이렇게 구성된 웹 계층에서 상태 정보를 제거한 것을 무상태 웹 계층이라고 한다.

데이터 센터

시스템이 글로벌 서비스를 제공하게 된다면, 빠른 성능과 가용성을 위해 여러개의 데이터 센터를 운용하도록 해야한다. 장애가 없는 상황에서 사용자는 가까운 데이터 센터로 안내되는데, 이를 지리적 라우팅이라고 한다. 만약 데이터 센터 중 하나에 장애가 발생하게 되면 다른 데이터 센터로 요청이 전송된다.

 

데이터 센터를 여러개 운용하기 위해서는 효과적인 트래픽 우회 방법, 데이터 센터간의 데이터 동기화, 다양한 상황에서의 테스트와 배포 등을 고려해야 한다.

메시지 큐

시스템을 더 큰 규모로 확장하기 위해서는 여러 컴포넌트로 분리하여야 한다. 이떄 메시지 큐를 이용하여 컴포넌트사이의 비동기 통신을 지원하도록 하여 분산 시스템을 구성할 수 있도록 할 수 있다. 메시지 큐는 서비스 간의 메시지의 버퍼 역할을 하며 비동기적인 메시지 통신을 통해 서비스 간의 결합을 느슨하게 하여 규모 확장성이 보장되어야 하는 안정적 애플리케이션을 구성하기에 좋다.

로그, 메트릭 그리고 자동화

시스템의 규모가 커지면 로그, 메트릭, 자동화 등이 필요하다. 에러 로그 관리와 서버의 용량, 시스템 트래픽, 사용자 정보 등의 메트릭, 시스템의 CI/CD를 위한 자동화 도구 등을 통해서 큰 규모의 시스템을 운영할 수 있도록 구성해야한다.

데이터베이스의 규모 확장

- 수직적 확장

데이터베이스의 메모리, 디스크 등의 추가를 통해서 데이터베이스를 증설한다. 하지만 이러한 방법은 용량 증설의 한계가 있고, SPOF (Single Point of Failure)의 문제가 있다.

- 수평적 확장

데이터베이스의 데이터를 여러대의 데이터베이스 서버로 나누어 저장하기 위해서는 '샤딩'을 적용해야 한다. 샤딩은 대규모 데이터베이스를 '샤드'라고 부르는 작은 단위로 분할하는 기술로 모든 샤드는 같은 스키마를 사용하지만 중복되는 데이터가 없어야 한다.

 

샤딩 전략에서 가장 중요한 것은 어떤 방식으로 샤딩 키 (파티션 키)를 정할 것인가이다. 샤딩키는 데이터를 어떤 샤드에 저장할 것인지 정하는 값으로 간단하게 mod를 적용하는 방식부터 다른 알고리즘을 사용하는 방식까지 다양하게 존재한다. 이와 관련해서는 뒤쪽의 다른 챕터에서 다시 다룬다.

 

샤딩을 적용할 때 고려해야 할 점은 다음과 같다.

- 데이터의 재 샤딩
데이터가 많아져서 샤드 용량이 부족하거나, 샤드 간의 데이터 분포가 고르지 않는 경우 다른 샤드에 데이터를 재배치 해야한다.

- 유명인사 문제
핫스팟 키 문제라고도 부르는 문제로 특정 샤드에 쿼리가 많이 발생하여서 해당 서버에 과부하가 걸리는 문제이다. 이러한 경우에는 해당 데이터들에 대해서 별개의 샤드를 할당하거나 샤드를 더욱 잘게 쪼개야 할 수도 있다.

- 조인과 비정규화
하나의 데이터베이스가 여러 샤드로 쪼개지면, 서로 다른 샤드에 저장된 데이터 간의 조인이 어려워진다. 이를 해결하기 위해서 데이터베이스를 비정규화하여 하다의 테이블에서 쿼리를 수행할 수 있도록 할 수도 있다.
반응형