본문 바로가기
독서/가상 면접 사례로 배우는 대규모 시스템 설계 기초

15장. 구글 드라이브 설계

by yoon_seon 2023. 12. 30.

1단계. 문제 이해 및 설계 범위 확정

기능적 요구사항

  • 파일 추가. 가장 쉬운 방법은 구글 드라이브 안으로 떨구는(drag-and-drop) 것이다.
  • 파일 다운로드
  • 여러 단말에 파일 동기화. 한 단말에서 파일을 추가하면 다른 단말에도 자동으로 동기화 되어야 한다.
  • 파일 갱신 이력 조회
  • 파일 공유
  • 파일이 편집되거나 삭제되거나 새롭게 공유되었을 때 알림 표시

비-기능적 요구사항

  • 안정성 : 저장소 시스템에서 안정성은 아주 중요하다. 데이터 손실은 발생하면 안된다.
  • 빠른 동기화 속도
  • 네트워크 대역폭 : 제품이 네트워크 대역폭을 불필요하게 많이 소요한다면 사용자는 불편할 것이다.
  • 규모 확장성 : 이 시스템은 아주 많은 양의 트래픽도 처리 가능해야 한다.
  • 높은 가용성 : 일부 서버에 장애가 발생하거나, 느려지거나, 네트워크 일부가 끊겨도 시스템은 계속 사용 가능해야 한다.

개략적 추정치

  • 가입 사용자 오천만명. 천만명의 DAU 사용자가 있다고 가정
  • 모든 사용자에게 10GB의 무료 저장공간 할당
  • 매일 각 사용자가 평균 2개의 파일을 업로드한다고 가정. 각 파일의 평균 크기는 약 500KB
  • 읽기:쓰기 비율은 1:1
  • 필요한 저장공간 총량 = 오천만 사용자 * 10GB = 500페타바이트(Petabyte)
  • 업로드 API QPS = 천만 사용자 * 2회 업로드/24시간/3600초 = 약 240
  • 최대 QPS = OPS * 2 = 480


2단계. 개략적 설계안 제시 및 동의 구하기

아래와 같은 구성의 서버 한 대로 시작하고 점차 발전 시켜본다.

  • 파일을 올리고 다운로드 하는 과정을 처리할 웹 서버
  • 사용자 데이터, 로그인 정보, 파일 정보 등의 메타데이터를 보관할 데이터베이스
  • 파일을 저장할 저장소 시스템. 파일 저장을 위해 1TB의 공간을 사용할 것

API

이 시스템은 기본적으로 세 가지 API가 필요하다.

  1. 파일 업로드 API
  2. 다운로드 API
  3. 파일 갱신 히스토리 API

1. 파일 업로드 API

  • 단순 업로드 : 파일 크기가 작을 때 사용
  • 이어 올리기 : 파일 크기가 크고 네트워크 문제로 업로드가 중단될 가능성이 높다고 생각되면 사용
    • 이어 올리기는 다음 세 단계 절차로 이루어진다.
      • 이어 올리기 URL을 받기 위한 최초 요청 전송
      • 데이터를 업로드하고 업로드 상태 모니터링
      • 업로드에 장애가 발생하면 장애 발생시점부터 업로드를 재시작

2. 파일 다운로드 API

3. 파일 갱신 히스토리 API

지금까지 나열한 모든 API는 사용자 인증을 필요로 하고 HTTPS 프로토콜을 사용해야한다.

SSL를 지원하는 프로토콜을 이용하는 이유는 클라이언트와 백엔드 서버가 주고받는 데이터를 보호하기 위한 것이다.


한 대 서버의 제약 극복

업로드되는 파일이 많이지다 보면 결국 파일 시스템은 가득 차게 된다. 이렇게 되면 사용자는 더 이상 파일을 올릴 수 없게 되므로, 문제를 해결해야한다.

해결책은 데이터를 샤딩하여 여러 서버에 나누어 저장하는 것이다. 다음은 user_id를 기준으로 샤딩한 예제다.

단일 서버에 장애 발생 시 SPOF로 데이터가 손실될 수 있다.

따라서 아마존 S3같은 클라우드 저장소 시스템에 파일을 저장할 수 있다.


아마존 S3

  • 업계 최고 수준의 규모 확장성, 가용성, 보안, 성능을 제공하는 객체 저장소 서비스
  • AWS 서비스 지역은 아마존 AWS가 데이터 센터를 운영하는 지리적 영역이다.
  • 다중화를 지원하는데, 같은 지역 안에서 다중화 가능하고 여러 지역에 걸쳐 다중화 가능함
    • 여러 지역에 걸쳐 다중화하면 데이터 손실을 막고 가용성을 최대한 보장할 수 있다.


이전 단일 서버로 구성된 설계에 개선할 부분

  • 로드밸런서 : 네트워크 트래픽을 분산 및 특정 웹 서버 장애 발생 시 자동으로 해당 서버를 우회함.
  • 웹 서버 : 로드밸런서 추가로 인해 더 많은 웹 서버를 추가할 수 있다. → 트래픽이 폭증해도 쉽게 대응 가능
  • 메타데이터 데이터베이스 : 데이터베이스를 파일 저장 서버에서 분리하여 SPOF를 회피한다. 아울러 샤딩 정책을 적용하여 가용성과 규모 확장성 요구사항에 대응
  • 파일 저장소 : S3를 파일 저장소로 사용하고 가용성과 데이터 무손실을 보장하기 위해 두 개 이상의 지역에 데이터를 다중화한다.

다음은 개선된 설계안이다.

동기화 충돌

두 명 이상의 사용자가 같은 파일이나 폴더를 동시에 업데이트하려고 할 때 동기화 충돌이 발생할 수 있다.

해결책은 먼저 처리되는 변경은 성공한 것으로 보고, 나중에 처리되는 변경은 충돌이 발생한 것으로 표시하는 것이다. 오류가 발생한 시점에 두 가지 버전이 존재하기 된다.

따라서 더 늦게 데이터에 접근한 로컬 사본과 서버에 있는 이 전 사용자가 수정한 최신 버전 중 두 버전의 파일을 하나로 합칠지 아니면 둘 중 하나를 다른 파일로 대체할지 결정해야 한다.

개략적 설계안

  • 사용자 단말 : 사용자가 이용하는 웹브라우저나 모바일 앱 등의 클라이언트.
  • 블록 저장소 서버 : 파일 블록을 클라우드 저장소에 업로드하는 서버다. ****블록 저장소는 블록 수준 저장소 라고도 하며 클라우드 환경에서 데이터 파일을 저장하는 기술이다. 이 저장소는 파일을 각 고유의 해시값이 할당된 여러개의 블록으로 나눠 저장한다. 각 블록은 독립적인 객체로 취급되며 클라우드 저장소 시스템에 보관된다. 파일을 재구성하려면 블록들을 원래 순서대로 합쳐야 한다.
  • 클라우드 저장소 : 파일은 블록 단위로 나눠져 클라우드 저장소에 보관된다.
  • 아카이빙 저장소 : 오랫동안 사용되지 않은 비활성 데이터를 저장하기 위한 컴퓨터 시스템
  • 로드 밸런서 : 요청 트래픽 분산
  • API 서버 : 파일 업로드 외에 거의 모든 것을 담당하는 서버. 사용자 인증, 사용자 프로파일 관리, 파일 메타데이터 갱신 등에 사용
  • 메타데이터 데이터베이스 : 사용자, 파일, 블록, 버전 등의 메타데이터 정보를 관리한다. 실제 파일은 클라우드에 저장하며, 이 데이터베이스에는 오직 메타데이터만 저장한다.
  • 메타데이터 캐시 : 성능을 높이기 위해 자주 쓰이는 메타데이터는 캐시한다.
  • 알림 서비스 : 특정 이벤트가 발생했음을 클라이언트에게 알리는데 쓰이는 발생/구독 프로토콜 기반 시스템
  • 오프라인 사용자 백업 큐 : 클라이언트가 접속 중이 아니라서 파일의 최신 상태를 확인할 수 없을 때는 해당 정보를 이 큐에 두어 나중에 클라이언트가 접속했을 때 동기화될 수 있도록 한다.


3단계. 상세 설계

  • 블록 저장소 서버
  • 메타데이터 데이터베이스
  • 업로드 절차
  • 다운로드 절차
  • 알림 서비스
  • 저장소 공간 절약
  • 장애 처리


블록 저장소 서버

정기적으로 갱신되는 큰 파일들을 업데이트가 일어날 때마다 전체 파일을 서버로 보내면 네트워크 대역폭을 많이 잡아먹게 된다. 이를 최적화 하기 위한 두가지 방법은 다음과 같다.

  • 델타 동기화 : 파일이 수정되면 전체 파일 대신 수정이 일어난 블록만 동기화 하는 것이다.
  • 압축 : 블록 단위로 압축해 두면 데이터 크기를 많이 줄일 수 있다. 압축 알고리즘은 파일 유형에 따라 정한다.

이 시스템에서 블록 저장소는 다음과 같이 동작한다.

  1. 클라이언트가 보낸 파일을 작은 블록 단위로 분할한다.
  2. 각 블록에 압축 알고리즘을 적용하여 압축한다.
  3. 클라우도 저장소로 보내기 전에 암호화 한다.
  4. 전체 파일을 클라우드 저장소로 보내는 대신 수정된 블록만 전송한다.


델타 동기화 전략 동작 방식

블록 저장소 서버에 델타 동기화 전략과 압축 알고리즘을 도입하여 네트워크 대역폭 사용량을 절감할 수 있다.


높은 일관성 요구사항

강한 일관성을 지원하여 같은 파일이 단말이나 사용자에 따라 다르게 보이는 것을 허용하면 안된다.

강한 일관성을 달성하려면 다음과 같은 사항을 보장해야한다.

  • 캐시에 보관된 사본과 데이터베이스에 있는 원본이 일치한다.
  • 데이터베이스에 보관된 원본에 변경이 발생하면 캐시에 있는 사본을 무효화한다.


메타데이터 데이터베이스

다음은 데이터베이스의 스키마 설계안이다.

업로드 절차

다음 그림은 두 개의 요청이 병렬적으로 전송된 상황이다.

첫 번째 요청은 파일 메타데이터를 추가하기 위한 것이고

두 번째 요청은 파일을 클라우드 저장소로 업로드하기 위한 것이다.

  • 파일 메타데이터 추가
    1. 클라이언트 1이 새 파일의 메타데이터를 추가하기 위한 요청 전송
    2. 새 파일의 메타데이터를 데이터베이스에 저장하고 업로드 상태를 대기중으로 변경
    3. 새 파일이 추가되었음을 알림 서비스에 통지
    4. 알림 서비스는 관련된 클라이언트에게 파일이 업로드되고 있음을 알림
  • 파일을 클라우드 저장소에 업로드
    2.1. 클라이언트 1이 파일을 블록 저장소 서버에 업로드
    2.2. 블록 저장소 서버는 파일을 블록 단위로 쪼갠 다음 압축하고 암호화 후 클루으도 저장소에 전송
    2.3. 업로드가 끝나면 클라우드 스토리지는 완료 콜백을 호출. 이 호출은 API 서버로 전송됨
    2.4. 메타데이터 DB에 해당 파일의 상태를 완료로 변경
    2.5. 알림 서비스에 파일 업로드가 끝났음을 통지
    2.6. 알림 서비스는 관련된 클라이언트에게 파일 업로드가 끝났음을 알림


다운로드 절차

클라이언트는 다른 클라이언트가 파일을 편집하거나 추가 했다는 사실을 감지하기 위해 두가지 방법을 사용한다.

  • 클라이언트 A가 접속 중이고 다른 클라이언트가 파일을 변경하면 알림 서비스가 클라이언트 A에게 변경이 발생했으니 새 버전을 끌어가야 한다고 알린다.
  • 클라이언트 A가 네트워크에 연결된 상태가 아닐 경우에는 데이터는 캐시에 보관될 것이다. 해당 클라이언트의 상태가 접속중으로 바뀌면 그 때 해당 클라이언트는 새 버전을 가져갈 것이다.

알림 서비스

알림 서비스는 파일의 일관성을 유지하기 위해 클라이언트가 로컬에서 파일을 수정했을 시 다른 클라이언트에게 사실을 알려서 충돌가능성을 낮추는 목적으로 이용된다.

  • 롱 폴링
  • 웹소켓 : 클라이언트가 서버 사이의 지속적인 통신 채널을 제공한다. 따라서 양방향 통신이 가능하다.

본 설계안의 경우 알림 서비스는 채팅 서비스와 달리 양방향 통신이 필요하지 않기 때문에 롱 폴링 방식을 채택한다.

폴링 방안을 사용하면 각 클라이언트는 알림 서버와 롱 폴링용 연결을 유지하다가 특정 파일에 대한 변경을 감지하면 해당 연결을 끊는다. 이 때 클라이언트는 반드시 메타데이터 서버와 연결해 파일의 최신 내역을 다운로드 해야하며 해당 다운로드 작업이 끝났거나 연결 타임아웃 시간에 도달한 경우 즉시 새 요청을 보내어 롱 폴링 연결을 복원하고 유지해야한다.


저장소 공간 절약

  • 중복 제거 : 중복된 파일 블록을 계정 차원에서 제거하는 방법이다. 두 블록이 같은 블록인지는 해시 값을 비교하여 판단한다.
  • 지능적 백업 전략 도입 :
    • 한도 설정 : 보관해야 하는 파일의 버전 개수에 상한을 두고 상한에 도달하면 제일 오래된 버전은 버린다.
    • 중요한 버전만 보관
  • 자주 쓰이지 않는 데이터는 아카이빙 저장소로 옮김


장애 처리

  • 로드밸런서 장애 : 부 로드밸런서가 활성화되어 트래픽을 이어받아야 한다. 일정 시간동안 박동 신호에 응답하지 않은 로드밸런서는 장애가 발생한 것으로 간주한다.
  • 블록 저장소 서버 장애 : 다른 서버가 미완료 상태 또는 대기 상태인 작업을 이어받아야한다.
  • 클라우드 저장소 장애 : S3 버킷은 여러 지역에 다중화할 수 있으므로 다른 지역에서 파일을 가져오면된다.
  • API 서버 장애 : API 서버는 무상태 서버다. 따라서 API 서버에 장애가 발생하면 로드밸런서가 트래픽을 해당 서버로 보내지 않음으로써 장애 서버를 격리할 것이다.
  • 메타데이터 캐시 장애 : 메타데이터 캐시 서버도 다중화한다. 따라서 한 노드에 장애가 생겨도 다른 노드에서 데이터를 가져올 수 있다.
  • 메타데이터 데이터베이스 장애 :
    • 주 데이터베이스 서버 장애 : 부 데이터베이스 서버 가운데 하나를 주 데이터베이스로 바꾸고, 부 데이터베이스 서버를 새로 하나 추가한다.
    • 부 데이터베이스 서버 장애 : 다른 부 데이터베이스 서버가 읽기 연산을 처리하도록 하고 그동안 장애 서버는 새것으로 교체한다.
  • 알림 서비스 장애 : 접속중인 모든 사용자는 알림 서버와 롱 폴링 연결을 유지하기 때문에 알림 서비스는 한 대의 서버에서 장애가 발생하면 수많은 사용자와 롱 폴링 연결을 다시 만들어야한다. 따라서 롱 폴링 연결을 복구하는 것은 상대적으로 느릴 수 있다.
  • 오프라인 사용자 백업 큐 장애 : 다중화한다. 큐에 장애가 발생하면 구독 중인 클라이언트들은 백업 큐로 구독 관계를 재 설정해야 한다.


4단계. 마무리

추가로 논의해볼 사항

  • 블록 저장소 서버를 거치지 않고 파일 클라우드 저장소에 직접 업로드
    • 장점
      1. 업로드 시간이 빨라진다.
    • 단점
      1. 분할, 압축, 암호화 로직을 클라이언트에 두어야 함으로 플랫폼별로 따로 구현해야한다.
      2. 클라이언트가 해킹 당할 가능성이 있으므로 암호화 로직을 클라이언트 안에 두는 것은 보안적으로 취약하다.
  • 접속상태를 관리하는 로직을 별도 서비스로 옮김.
    • 알림 서비스에서 분리함으로써 다른 서버에서도 쉽게 활용할 수 있다.

댓글