Contents

가상 면접 사례로 배우는 대규모 시스템 설계 기초 Study [15장] 구글 드라이브 설계

Note
팀 내에서 진행하는 Study 정리 입니다.
함께 논의하고 싶은 주제
  1. 같이 스터디를 함으로써 책을 빠른시간내에 읽고 정리해볼 수 있어서 좋았습니다. ( 그 과정은 조금 힘들지만 그래도 다 읽어서 좋습니다!)
  2. 저장소 공간을 절약할 때 자주 바뀌는 파일로 인해 버전 이력이 많이 생긴다면 중요한 버전만 어떻게 골라낼 수 있을까?

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

1.1 기능적 요구사항

  • 파일추가. 가장 쉬운 방법은 drag-and-drop
  • 파일 다운로드
  • 여러 단말에 파일 동기화
  • 파일 갱신 이력 조회(revision history)
  • 파일 공유
  • 파일이 편집되거나 삭제되거나 새롭게 공유되었을 때 알림푯;
  • 제외기능 : 구글문서 편집 및 협업 기능

1.2 비 기능적 요구사항

  • 데이터에 대한 안정성
  • 빠른 동기화 속도
  • 네트워크 대역폭
  • 규모 확장성
  • 높은 가용성

1.3 개략적 추정치

  • 가입자는 오천만 명. DAU 천만명이라고 가정
  • 모든 사용자에게 10GB 제공
  • 매일 각 사용자가 평균 2개의 파일을 업로드. 각 파일 크기는 500KB
  • 읽기:쓰기 비율 1:1
  • 필요한 저장공간 총량 = 5천만 사용자 * 10GB = 500PB
  • 업로드 API QPS = 천만 사용자 * 2회 업로드 / 24시간 / 3600초 = 약 240
  • 최대 QPS = QPS * 2 = 480

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

서버 한 대로 구성해보기

  • 파일 업로드 및 다운로드를 위한 웹서버
  • 사용자, 로그인 정보, 파일 정보 등을 관리하는 데이터베이스
  • 파일을 저장할 저장소
Note

[예시]

  • 아파치 웹 서버, MySQL 데이터베이스를 설치하고 파일저장소인 drive/ 디렉터리를 생성
  • dirve/ 디렉터리 안에는 네임스페이스라 불리는 하위 디렉터리를 구성
  • 각 네임스페이스에는 특정 사용자가 올린 파일을 보관
  • 각 파일과 폴더는 상대 경로를 네임스페이스 이름과 결합하여 유일하게 식별

2.1 API

  • 클라이언트와 백엔드 서버가 주고받는 데이터를 보호하기 위해 SSL(Secure Socket Layer)를 지원하는 HTTPS 프로토콜을 사용

파일 업로드 API

  • 단순 업로드 : 파일 크기가 작을 때 사용
  • 이어 올리기(resumable upload) : 파일 사이즈가 크고 네트워크 문제로 업로드가 중단될 가능성이 높은 경우
이어올리기 API 예시

https://api.example.com/files/upload?uploadType=resumable

인자

  • uploadType=resumable
  • data : 업로드할 로컬 파일
  • 이어 올리기 URL을 받기 위한 최초 요청 전송
  • 데이터를 업로드하고 업로드 상태 모니터링
  • 업로드 장애 발생시 장애 발생시점부터 업로드 재시작

파일 다운로드 API

다운로드 API 예시

https://api.example.com/files/download

인자

  • path : 다운로드 할 파일의 경로
1
2
3
{
  "path" : "/recipes/soup/best_soup.txt"
}

파일 갱신 히스토리 API

파일 갱신 히스토리 API 예시

인자

  • path: 갱신 히스토리를 가져올 파일의 경로
  • limit: 히스토리 길이의 최대치
1
2
3
4
{
  "path" : "/recipes/soup/best_soup.txt",
  "limit" : 20
}

2.2 한 대 서버의 제약 극복

  • 파일 시스템이 가득차는 경우 데이터를 샤딩하여 여러 서버에 나누어 저장
  • 아마존 S3와 같은 객체 저장소 서비스를 활용
  • 데이터의 다중화는 같은 지역 혹은 여러 지역 안에 걸쳐 다중화가 가능
  • 여러 지역 안에 걸쳐 다중화하면 데이터 손실을 막고 가용성을 최대한 보장

더 개선할 부분 찾기

  • 로드밸런서: 로드밸런서는 트래픽을 고르게 분산. 웹서버 장애시 다른 서버로 우회
  • 웹 서버: 로드밸런서를 추가하면 웹 서버를 손쉽게 추가 가능
  • 메타데이터 데이터베이스: 데이터베이스를 파일 저장 서버에 분리 SPOF(Single Point Of Failure)를 회피. 다중화, 샤딩 정책적용으로 가용성 규모확장성 대응
  • 파일 저장소 : 가용성과 데이터 무손실을 보장하기 위해 두 개 이상에 지역에 데이터 다중화

2.3 동기화 충돌

  • 두 명 이상의 사용자가 같은 파일이나 폴더를 동시에 업데이트 하는 경우
  • 먼저 처리된 변경을 성공한 것으로 보고 나중에 처리되는 변경은 충돌이 발생한 것으로 표기
  • 오류가 발생한 시점에는 같은 파일의 두 가지 버전이 존재

2.4 개략적 설계안

  • 사용자 단말 : 사용자가 이용하는 웹브라우저나 모바일 앱 등 클라이언트
  • 블록 저장소 서버(block server)
    • 블록 수준 저장소(blcok-level storage)
    • 파일을 여러개의 블록으로 나누어 저장하고 각 블록에는 고유한 해시값을 할당
    • 해시값은 메타데이터 데이터베이스에 저장
    • 각 블록은 독립적인 개체이고 클라우드 저장소 시스템에 보관
    • 재 구성을 위해 블록들을 원래 순서대로 병합
  • 클라우드 저장소 : 블록단위로 나누어진 파일은 저장소에 보관
  • 아카이빙 저장소(cold storage) : 오랫동안 사용하지 않은 비활성 데이터를 저장
  • 로드밸런서 : 요청을 모든 API 서버에 고르게 분산
  • API 서버 : 파일 업로드 외 모든 것을 담당.
  • 메타데이터 데이터베이스 : 사용자, 파일, 블록, 버전 등 메타데이터 정보 관리. 실제 파일은 클라우드에 보관되며 메타데이터만 관리
  • 메타데이터 캐시 : 자주쓰이는 메타데이터는 캐시
  • 알림 서비스 : 클라이언트에게 특정 이벤트 알림.생성/구독 프로토콜 기반 시스템 사용
  • 오프라인 사용자 백업 큐(offline backup queue) : 클라이언트가 접속중이 아닐 경우 해당 정보를 큐에 두어 나중에 클라이언트가 접속했을 때 동기화

3. 상세 설계

3.1 블록 저장소 서버

큰 파일 업데이트 최적화

  • 델타 동기화(delta sync) : 파일이 수정되면 전체 파일 대신 수정이 일어난 블록만 동기화
  • 압축(compression) : 블록 단위의 압축은 데이터 크기를 많이 줄일 수 있음. 파일 유형에 따라 압축알고리즘 지정

블록 저장소 동작 방식

  • 주어진 파일을 작은 블록으로 분할
  • 각 블록 압축
  • 클라우드 저장소로 보내기 전 암호화
  • 클라우드 저장소로 전송

블록저장소 서버에 델타 동기화 전략과 알고리즘을 도입하였으므로 네트워크 대역폭 사용량을 절감

3.2 높은 일관성 요구사항

  • 강한 일관성(strong consistency) 모델을 지원해야함
  • 메모리 캐시는 결과적 일관성(eventual consistency) 모델을 지원
  • 관계형 데이터베이스는 ACID(Atomicity, Consistency, Isolation, Durability)를 보장하므로 강한 일관성을 보장하기 쉬움
  • NoSQL은 기본적으로 지원하지 않으므로 동기화 로직 안에 프로그램하여 넣어야 함

캐시의 강한 일관성 달성

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

3.3 메타데이터 데이터베이스

  • user : 이름, 이메일, 프로파일 사진 등 사용자와 관계된 정보 보관
  • device : 단말 정보 저장. 한 사용가 여러 대의 단말을 가질 수 있다.
  • namespace : 사용자의 루트 디렉터리 정보 보관
  • file : 파일이 최신 정보 보관
  • file_version : 파일의 갱신 이력 보관. 갱신 이력의 훼손을 막기 위해 읽기 전용
  • block : 파일 블록에 대한 정보를 보관. 특정 버전의 파일은 파일 블록을 올바른 순서로 조합하면 복원가능

3.4 업로드 절차

  • 파일 메타데이터 추가, 파일 클라우드 저장소 업로드 두 가지 요청이 병렬적으로 실행

파일 메타데이터 추가

  1. 클라이언트 1이 새 파일의 메타데이터를 추가하기 위해 요청 전송
  2. 새 파일의 메타데이터를 데이터베이스에 저장하고 업로드 상태를 pending으로 변경
  3. 새 파일 추가 알림 서비스 통지
  4. 알림 서비스는 관련 클라이언트에게 파일 업로드 알림

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

  1. 클라이언트 1이 파일을 블록 저장소 서버에 업로드
  2. 블록 저장소 서버는 파일을 블록 단위로 분할한 다음 압축하고 암호화 한 다음에 클라우드 저장소에 전송
  3. 업로드 완료 후 클라우드 스토리지는 완료 콜백 호출.
  4. 메타데이터 데이터베이스에 기록된 해당 파일의 상태를 uploaded로 변경
  5. 알림 서비스에게 파일 업로드 완료 통지
  6. 알림 서비스는 관련 클라이언트에게 파일 업로드 완료를 알림

3.5 다운로드 절차

다른 클라이언트의 변경 감지

  • 클라이언트 A가 접속 중이고 다른 클라이언트가 파일 변경 : 알림서비스가 A에게 변경 알림. 새 버전 알림
  • 클라이언트 A가 접속 중이 아닐 때 다른 클라이언트가 파일 변경 : 데이터는 캐시에 보관. A가 접속 중으로 변경시 새 버전을 가져감
  1. 알림 서비스가 클라이언트 2에게 누군가 파일 변경을 알림
  2. 클라이언트 2는 새로운 메타데이터 요청
  3. API 서버는 메타데이터 데이터베이스에게 새 메타데이터 요청
  4. API 서버 새 메타데이터 반환
  5. 클라이언트2 는 새 메타데이터 수신
  6. 클라이언트2는 새 메타데이터를 받는 즉시 블록 다운로드 요청 전송
  7. 블록 저장소 서버는 클라우드 저장소에 블록 다운로드
  8. 클라우드 저장소는 블록 서버에 요청된 블록 반환
  9. 블록 저장소 서버는 클라이언트에게 요청된 블록 반환. 클라이언트 2는 전송된 블록을 사용하여 파일 재구성

3.6 알림 서비스

  • 롱 폴링(long polling)
  • 웹 소켓(Websocket) : 클라이언트와 서버 사이 지속적인 통신 채널을 제공. 양방향 통신 가능

롱 폴링 사용 이유

  • 채팅 서비스와 달리 본 시스템은 서버는 파일이 변경된 사실을 클라이언트에게 알려주어야 하지만 그 반대는 요구되지 않음
  • 웹소켓은 양방향 통신이 요구되는 곳에 적합. 알림을 보낼일은 자주 발생하지 않고 단시간에 많은 양의 데이터를 보낼일은 없음

3.7 저장소 공간 절약

  • 중복제거(de-dupe): 중복된 파일을 블록을 계정 차원에서 제거. 두 블록의 해시값 비교
  • 지능적 백업 전략 도입
    • 한도 설정 : 보관해야 하는 파일의 개수 상한. 상한에 도달하면 제일 오래된 버전 파기
    • 중요한 버전만 보관 : 자주 파일이 변경되는 경우 중요한 이력만 보존해야 한다.
  • 자주 쓰이지 않는 데이터는 아카이빙(cold storage)로 이동. 몇 달 혹은 수년간 이용되지 않는 데이터

3.8 장애 처리

  • 로드밸런서 장애
    • 로드밸런서 장애시 부 로드밸런서가 활성화
    • 로드밸런서 끼리 박동(heartbeat) 신호를 주기적으로 보내 상태 모니터링
    • 일정 시간 동안 박동 신호에 응답하지 않는 로드 밸런서는 장애 간주
  • 블록 저장소 서버 장애: 다른 서버가 미완료 상태 또는 대기 상태인 작업을 이어받음
  • 클라우드 저장소 장애: S3 버킷은 여러 지역에 다중화. 다른지역에 파일을 가져옴
  • API 서버 장애 : 장애 서버에 트래픽을 보내지 않고 격리
  • 메타데이터 캐시 장애 : 메타데이터 개시 서버 다중화
  • 메타데이터 데이터베이스 장애
    • 주 데이터베이스 서버 장애 : 부 데이터베이스 서버 하나를 주 데이터베이스로 변경. 부 데이터베이스 추가
    • 부 데이터베이스 서버 장애 : 다른 부 데이터베이스 서버가 읽기 연산 처리. 장애서버는 교체
  • 알림 서비스 장애
    • 접속 중인 모든 사용자는 알림 서버와 롱 폴링 연결
    • 서버 한대가 장애 발생시 수백만 개의 롱 폴링을 재연결. 동시에 여러개의 연결을 하는 것은 불가능
  • 오프라인 사용자 백업 큐 장애: 큐 다중화. 큐 장애시 구독 클라이언트들도 백업 큐 구독 관계를 재설정

4. 마무리

  • 블록 저장소를 거치지 않고 파일을 클라우드 저장소에 직접 업로드 한다면?
    • 분할, 압축, 암호화 로직을 클라이언트에 두어야 하므로 플랫폼별로 따로 구현 필요
    • 클라이언트가 해킹 당할 가능성이 있음 암호화 로직을 클라이언트 안에 두는 것을 적절하지 않음