Share
Sign In

구글 드라이브

규모 추청

Given
총 사용자 : 50,000,000명
DAU = 10,000,000명
사용자당 10GB 저장소 제공
사용자당 평균 일일 업로두 수 : 2개
파일당 평균 크기 : 500KB
읽기 : 쓰기 = 1 : 1
Derived
필요 저장 공간 = 50,000,000명 x 10GB = 50 PB
업로드 API QPS = 10,000,000명 x 2개 x 하루(24시간 x 3600초) = 240
최대 QPS = 240 x 2 = 480

API 종류

파일 업로드 (/files/upload?data=<file>&uploadType=<resumable>)
단순 업로드
이어 올리기 (uploadType=resumable) : 업로드 상태를 모니터링하고 장애 시점부터 재시작할 수 있도록 한다.
파일 다운로드 (/files/download?path=<file>)
파일 갱신 히스토리 (/files/list_revisions?path=<file>&limit=<limit>)

서버 분산

S3 는 짱짱이다.

동기화 충돌

A 사용자와 B 사용자가 동시에 업로드할 경우 충돌이 발생하는데 어떻게 해결할까?
에서 vector clock이 방법이 될 수도…

개략적인 설계안

Block Server : 한 파일을 쪼개서 블럭을 만들어 저장한다.
Cloud Storage : 각 블럭의 해쉬값을 키로 해서 블럭을 저장한다.
로드밸런서, API 서버, 메타데이터 DB/캐시
알림 서비스 : 파일의 추가/삭제 등을 알린다. (뭐지 로그인가)
오프라인 백업 큐 : 알림 서비스의 로그를 가져와 오프라인 상태의 장치가 온라인이 되었을 때 동기화시킨다.

상세 설계

델타 동기화 : 파일이 수정되면 수정된 블록만 동기화한다. (Git?)
압축 : gzip, bzip2 등
강한 일관성 : 에서 설명하듯 모든 읽기 연산은 가장 최근에 갱신된 결과만 반환한다
캐시에 보관된 사본과 DB의 원본이 일치해야 한다.
DB에서 원본이 변경되면 캐시의 사본이 무효화된다.
RDB는 ACID를 보장하지만 NoSQL은 그렇지 않기 때문에 어렵다.

업로드

1.
클라이언트는 서버에게 업로드를 알리고 파일을 업로드한다.

다운로드

1.
알림 서비스는 다른 클라이언트에게 원본이 변했음을 알린다.
2.
클라이언트서버에게 변경된 블럭 내역을 요청한다.
3.
서버메타데이터 DB를 참조해 변경된 블럭 내역을 반환한다.
4.
클라이언트S3에서 변경된 블럭을 다운로드한다.

알림 서비스

💡
어떻게 보면 (pull 방식 vs push 방식)을 어렵게 설명한 것 같다.
롱 폴링 : 에서 말한 것처럼 한 번에 긴 시간동안 메시지를 달라고 해서 전체 API 호출을 줄인다.
웹 소켓 : 채널을 한 번 뚫어놓고 지속적으로 양방향 통신을 한다. (얘는 event-driven이었나?) -

저장소 공간 절약

중복 제거 : 해시 값 비교
지능적 백업 : S3 수명주기 규칙을 쓰자.
아카이빙 : Amazon S3 Glacier는 싸다.

장애 처리

SPOF 안만들기 : 여러 서버, 여러 지역, stateless

출처