가상 면접 사례로 배우는 대규모 시스템 설계 기초

구글 드라이브 설계

막이86 2023. 11. 9. 17:52
728x90

가상 면접 사례로 배우는 대규모 시스템 설계 기초 "구글 드라이브 설계"을 요약한 내용입니다.

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

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

이번 장에서는 다음 기능은 논의하지 않을 것

  • 구글 문서 편집 및 협업 기능, 구글 문서는 여러 사용자가 같은 문서를 동시에 편집할 수 있도록 하는데, 이부분은 설계 범위에서 제외

기능적 요구사항 이외에, 비-기능적 요구사항을 이해하는 것도 중요

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

개략적 추정치

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

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

아래와 같은 구성의 서버 한대로 시작

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

API

시스템은 기본적으로 세 가지 API가 필요함

  1. 파일 업로드 API
    • 단순 업로드: 파일 크기가 작을 때 사용
    • 이어 올리기: 파일 사이즈가 크고 네트워크 문제로 업로드가 중단될 가능성이 높다고 생각되면 사용
  2. 다운로드 API
  3. 파일 갱신 히스토리 제공 API

개략적 설계안

[그림 15-10]은 개략적 설계안이다.

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

3단계 상세 설계

블록 저장소 서버

  • 정기적으로 갱싱되는 큰 파일들은 업데이트가 일어날 때마다 전체 파일을 서버로 보내면 네트워크 대역폭을 많이 잡아먹게 된다.
  • 최적화하는 방법으로는 델타 동기화, 압축 정도를 생각해볼수 있다.
    • 델타 동기화: 파일이 수정되면 전체 파일 대신 수정이 일어난 블록만 동기화 하는 것
    • 압축: 블록 단위로 압축해 두면 데이터 크기를 많이 줄일 수 있다. 이때 압축 알고리즘은 파일 유형에 따라 정한다. 예를 들어 텍스트 파일을 압축할 때는 gzip이나 bzip2를 쓰고, 이미지나 비디오를 압축할 때는 다른 압축 알고리즘을 쓰는 것이다.
  • [그림 15-11]은 새파일이 추가 되었을때 블록 저장소 서버가 어떻게 동작하는지 나와 있다
    • 주어진 파일을 작은 블록들로 분할한다.
    • 각 블록을 압축한다.
    • 클라우드 저장소로 보내기 전에 암호화 한다.
    • 클라우드 저장소로 보낸다.

높은 일관성 요구사항

  • 이 시스템은 강한 일관성 모델을 기본으로 지원해야 한다.
    • 같은 파일이 단말이나 사용자에 따라 다르게 보이는 것은 허용할 수 없다는 뜻이다.
  • 메타 데이터 캐시와 데이터베이스 계층에도 같은 원칙이 적용되어야 한다.
  • 메모리 캐시는 보통 최종 일관성 모델을 지원한다.
  • 캐시에 보관된 사본과 데이터베이스에 있는 원본이 일치한다.
  • 데이터베이스에 보관된 원본에 변경이 발생하면 캐시에 있는 사본을 무효화 한다.
  • 관계형 데이터베이스는 ACID를 보장하므로 강한 일관성을 보장하기 쉽다.
  • NoSQL 데이터베이스는 이를 기본으로 지원하지 않으므로, 동기화 로직 안에 프로그램해 넣어야한다.
  • 이번 설계에서는 관계형 데이터베이스를 채택하여 높은 일관성 요구사항에 대응할 것이다.

메타데이터 데이터베이스

  • [그림 15-13]은 데이터베이스 스키마 설계안이다.
  • user: user 테이블에는 이름, 이메일, 프로파일 사진 등 사용자에 관계된 기본적 정보들이 보관된다.
  • device: device 테이블에는 단말 정보가 보관된다. push_id는 모바일 푸시 알림을 보내고 받기 위한 것, 한 사용자가 여러 대의 단말을 가질 수 있음에 유의하자.
  • namespace: 사용자의 루트 디렉터리 정보가 보관된다.
  • file: 파일 최신 정보가 보관된다.
  • file_version: 파일의 갱신 이력이 보관되는 테이블이다. 이 테이블에 보관되는 레코드는 전부 읽기 전용이다. 갱신 이력이 훼손되는 것을 막기 위한 조치
  • block: 파일 블록에 대한 정보를 보관하는 테이블이다. 특정 버전의 파일은 파일 블록을 올바른 순서로 조합하기만 하면 복원해 낼 수 있다.

업로드 절차

파일 메타 데이터 추가

  1. 클라이언트 1이 새 파일의 메타데이터를 추가하기 위한 요청 전송
  2. 새 파일의 메타데이터를 데이터베이스에 저아하고 업로드 상태를 대기 중으로 변경
  3. 새 파일이 추가되었음을 알림 서버에 통지
  4. 알림 서비스는 관련된 클라이언트에게 파일 업로드 되고 있음을 알림

파일을 클라우드 저장소에 업로드

  1. 클라이언트 1이 파일을 블록 저장소 서버에 업로드
  2. 블록 저장소 서버는 파일을 블록 단위로 쪼갠 다음 압축하고 함호화 한다음에 클라우드 저장소에 전송
  3. 업로드가 끝나면 클라우드 스토리지는 완료 콜백을 호출 이 콜백 호출은 API 서버로 전송됨
  4. 메타데이터DB에 기록된 해당 파일의 상태를 완료로 변경
  5. 알림 서비스에 파일 업로드가 끝났음을 통지
  6. 알림 서비스는 관련된 클라이언트에게 파일 업로드가 끝났음을 알림

다운로드 절차

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

블록들을 다운 받아 파일을 재구성하는 흐름

  1. 알림 서비스가 클라이언트 2에게 누군가 파일을 변경했음을 알림
  2. 알림을 확인한 클라이언트 2는 새로운 메타데이터를 요청
  3. API 서버는 메타데이터 데이터베이스에게 새 메타데이터 요청
  4. API 서버에게 새 메타데이터가 반환됨
  5. 클라이언트 2에게 새 메타데이터가 반환됨
  6. 클라이언트 2는 새 메타데이터를 받는 즉시 블록 다운로드 요청 전송
  7. 블록 저장소 서버는 클라우드 저장소에서 블록 다운로드
  8. 클라우드 저장소는 블록 서버에 요청된 블록 반환
  9. 블록 저장소 서버는 클라이언트에게 요청된 블록 반환, 클라이언트 2는 전송된 블록을 사용하여 파일 재구성

알림 서비스

  • 파일의 일관성을 유지하기 위해, 클라이언트는 로컬에서 파일이 수정되었음을 감지하는 순간 다른 클라이언트에 그 사실을 알려서 충동 가능성을 줄여야 한다.
  • 알림 서비스는 이벤트 데이터를 클라이언트로 보내는 서비스
    • 롱 폴링: 드롭박스가 이 방식을 채택하고 있다.
    • 웹 소켓: 클라이언트와 서버 사이에 지속적인 통신 채널을 제공 한다.
      • 따라서 양방향 통신이 가능하다
  • 이번 설계안의 경우에는 롱 폴링을 사용할 것이다.
    • 채팅서비스와 달리 본 시스템의 경우에는 알림 서비스와 양방향 통신이 필요하지 않다.
    • 파일이 변경된 사실을 클라이언트에게 알려줘야하지만 반대 방향의 통신은 요구되지 않는다.
    • 웹소켓은 실시간 양방향 통신이 요구되는 채팅 같은 응용에 적합
    • 구글 드라이브의 경우 알림을 보낼 일이 그렇게 자주 발생하지 않으며, 알림을 보내야하는 경우에도 단시간에 많은 양의 데이터를 보낼 일은 없다.
  • 롱 폴링의 경우 각 클라이언트는 알림 서버와 롱폴링용 연결을 유지하다가 특정 파일에 대한 변경을 감지하면 해당 연결을 끊는다.
  • 클라이언트는 최신 내역을 다운로드 해야한다.
  • 다운로드 작업이 끝났거나 연결 타임아웃 시간에 도달한 경우에는 즉시 새 요청을 보내어 롱 폴링 연경을 복원하고 유지해야 한다.

저장소 공간 절약

  • 파일 갱신 이력을 보존하고 안정성을 보장하기 위해서는 파일의 여러 버전을 여러 데이터센터에 보관할 필요가 있다.
  • 모든 버전을 자주 백업하게 되면 저장용량이 빨리 소진된 가능성이 있다.
    • 중복 제거
      • 중복된 파일 블록을 계정 차원에 제거하는 방법
      • 두 블록이 같은 블록인지는 해시 값을 비교하여 판다.
    • 지능적 백업 전략을 도입
      • 한도 설정: 보관해야할 파일 버전 개수에 상한을 두는것, 젤 오래된 버전은 버린다.
      • 중요한 버전만 보관: 자주 바뀌는 경우 짧은 시간동안 많은 버전이 만들어질 수 있다. 불필요한 버전과 사본이 만들어지는 것을 피하려면 그 가운데 중요한 것만 골라내야 한다.
      • 자주 쓰이지 않는 데이턴는 아카이빙 저장소로 옮긴다.
        • 몇달 혹은 수년간 이용되지 않는 데이터가 이에 해당한다.
        • 아마존 S3 글레시어 같은 아카이빙 저장소는 이용료는 S3보다 훨씬 저렴하다.

장애 처리

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

4단계 마무리

  • 이번 설계안은 크게 두가지 부분으로 구성 된다.
    • 파일의 메타데이터를 관리하는 부분
    • 파일 동기화를 처리하는 부분
  • 블록 저장소 서버를 거치지 않고 파일을 클라우드 저장소에 직업 업로드 한다면?
    • 단점
      • 분할, 압축, 암호화 로직을 클라이언트에 두어야 하므로 플랫폼별로 따로 구현해야함
        • 당초 설계안에서는 이 모두를 블록 저장소 서버라는 곳에 모아 뒀으므로 그럴 필요가 없었다.
      • 클라이언트가 해킹 당할 가능성이 있으므로 암호화 로직을 클라이언트 안에 두는 것은 적절치 않은 선택일 수 있다.
  • 접속상태를 관리하는 로직을 별도 서비스로 옮기는 것
    • 다른 서비스에서도 쉽게 활용할 수 있게 되므로 좋을 것
728x90