문제 이해 및 설계 범위 확정개략적 설계안 제시 및 동의 구하기API한대 서버의 제약 극복좀더 개선한 설계안동기화 충돌개략적 설계안상세 설계블록 저장소 서버높은 일관성 요구사항메타데이터 데이터베이스업로드 절차다운로드 절차알림 서비스저장소 공간 절약장애 처리
문제 이해 및 설계 범위 확정
기능 설계 목록
- 파일 추가 (drag-and-drop)
- 파일 다운로드
- 여러 단말에 파일 동기화. 한 단말에서 파일을 추가하면 다른 단말에도 자동으로 동기화되어야 함
- 파일 갱신이력 조회
- 파일 공유
- 파일이 편집되거나 삭제되거나 새롭게 공유되었을 때 알림 표시
비 기능적 요구사항
- 안정성: 저장소 시스템에서 안정성은 아주 중요. 데이터 손실이 발생하면 안됨
- 빠른 동기화 속도 : 파일 동기화에 시간이 너무 많이 걸리면 사용자가 더이상 사용하지 않음
- 네트워크 대역폭 : 이 제품이 네트워크 대역폭을 너무 많이 사용하면 모바일 데이터 플랜을 사용하는 사용자는 매우 좋아하지 않음
- 규모 확장성 : 이 시스템은 아주 많은 양의 트래픽도 처리 가능해야 함
- 높은 가용성 : 일부 서버에 장애가 발생하거나, 느려지거나, 네트워크 일부가 끊겨도 시스템은 계속 사용가능해야 함
개략적 추정치
- 가입 사용자는 오천만명, 천만 명의 DAU 사용자가 있다고 가정
- 모든 사용자에게 10GB의 무료 저장공간 할당
- 매일 각 사용자가 평균 2개의 파일을 업로드한다고 가정. 각 파일의 평균 크기는 500KB
- 읽기 : 쓰기 = 1:1
- 필요한 저장공간 총량 = 5천만 사용자 x 10GB = 500페타바이트(Petabyte)
- 업로드 API QPS = 1천만 사용자 x 2회 업로드/24시간/3600초 = 약 240
- 최대 QPS = QPS * 2 = 480
개략적 설계안 제시 및 동의 구하기
서버 한대로 시작
- 파일을 올리고 다운로드하는 과정을 처리할 웹 서버
- 사용자 데이터, 로그인 정보, 파일 정보 등의 메타데이터를 보관할 데이터베이스
- 파일을 저장할 저장소 시스템. 파일 저장을 위해 1TB의 공간을 사용
사례 : drive/ 디렉터리 아래에 네임스페이스(사용자별) 별로 파일 보관
API
필요한 api는 아래 3개
파일 업로드 API
- 단순 업로드 : 파일 크기 작을 때
- 이어 올리기 : 파일 사이즈 크고 네트워크 문제로 업로드 중단될 가능성이 높을 때
- 절차
- 이어 올리기 URL을 받기 위한 최초 요청 전송
- 데이터를 업로드하고 업로드 상태 모니터링
- 업로드에 장애 발생하면 장애 발생시점부터 업로드 재시작
파일 다운로드 API
인자
- path : 다운로드할 파일의 경로
파일 갱신 히스토리 API
인자
- path : 갱신 히스토리를 가져올 파일의 경로
- limit : 히스토리 길이의 최대치
한대 서버의 제약 극복
업로드되는 파일이 많아지면 파일 시스템이 가득차게 됨 → 데이터를 샤딩하여 여러 서버에 나누어 저장
더 좋은 해결책
→ 업계 최고 수준의 규모 확장성, 가용성, 보안, 성능을 제공하는 객체 저장소 서비스인 아마존 S3를 사용하기
S3는 다중화를 지원하고 같은 지역 안에서 할 수도 있고 여러 지역에 걸쳐서 할 수도 있다.
좀더 개선한 설계안

- 로드밸런서 : 네트워크 트래픽 분산
- 웹 서버 : 스케일 아웃이 쉬워짐. 트래픽 폭증시 쉽게 대응 가능
- 메타데이터 데이터베이스 : 데이터베이스를 파일 저장 서버에서 분리하여 SPOF를 회피. 다중화 및 샤딩 정책을 적용하여 가용성과 규모 확장성 요구사항에 대응
- 파일 저장소 : S3를 파일 저장소로 사용하고 가용성과 데이터 무손실을 보장하기 위해 두 개 이상의 지역에 데이터 다중화
동기화 충돌
두 명 이상의 사용자가 같은 파일이나 폴더를 동시에 업데이트하려고 하는 경우
→ 먼저 처리되는 변경을 성공한 것으로 표시. 나중에 처리되는 변경은 충돌이 발생한 것으로 표시
오류 발생 시 시스템에는 같은 파일의 두 가지 버전이 존재하게 됨(로컬 사본, 서버에 있는 최신 버전)
개략적 설계안

- 블록 저장소 서버 : 파일 블록을 클라우드 저장소에 업로드하는 서버
- block-level storage 라고도 하며, 클라우드 환경에서 데이터 파일을 저장하는 기술. 파일을 여러개의 블록으로 나눠 저장하며, 각 블록에는 고유한 해시값이 할당됨
- 이 해시값이 메타데이터 데이터베이스에 저장
- 각 블록은 독립적인 객체로 취급되며 클라우드 저장소 시스템(AWS S3)에 보관됨
- 파일 재구성을 위해서는 블록들을 원래 순서대로 합쳐야 함(한 블록은 드롭박스 사례를 참고하여 최대 4MB)
- 클라우드 저장소 : 파일은 블록 단위로 나눠져 클라우드 저장소에 보관
- 아카이빙 저장소(cold storage) : 오랫동안 사용되지 않은 비활성 데이터를 저장하기 위한 컴퓨터 시스템
- API 서버 : 파일 업로드 외에 거의 모든 것을 담당하는 서버. 사용자 인증, 사용자 프로파일 관리, 파일 메타데이터 갱신 등에 사용
- 메타데이터 데이터베이스 : 사용자, 파일, 블록, 버전 등의 메타데이터 정보를 관리. 실제 파일은 클라우드에 보관하며, 이 데이터베이스에는 오직 메타 데이터만 둠
- 메타데이터 캐시 : 성능을 높이기 위해 자주 쓰이는 메타데이터 캐시
- 알림 서비스 : 특정 이벤트가 발생했음을 클라이언트에게 알리는 데 쓰이는 발생/구독 프로토콜 기반 시스템
- 예시 설계안에서는 클라이언트에게 파일이 추가되었거나, 편집되었거나, 삭제되었음을 알려 파일의 최신 상태를 확인하도록 하는데 쓰임
- 오프라인 사용자 백업 큐 : 클라이언트가 접속 중이 아니라서 파일의 최신 상태를 확인할 수 없을 때는 해당 정보를 이 큐에 두어 나중에 클라이언트가 접속했을 때 동기화될 수 있도록 함
상세 설계
블록 저장소 서버
정기적으로 갱신되는 큰 파일들은 업데이트가 일어날 때마다 전체 파일을 서버로 보내면 네트워크 대역폭을 많이 소모함 → 이를 최적화하는 방법은
- 델타 동기화 : 수정이 일어난 블록만 동기화
- 압축 : 블록 단위로 압축해 두면 데이터 크기를 많이 줄일 수 있음. 이때 압축 알고리즘은 파일 유형에 따라 정한다.
- 예로, 텍스트 파일 압축시에는 gzip이나 bzip2. 이미지나 비디오를 압축할 때는 다른 압축 알고리즘
하는 일
- 클라이언트가 보낸 파일을 블록 단위로 나누고
- 블록에 압축 알고리즘 적용
- 암호화
- 클라우드 저장소에 전송
동시에 전체 파일을 저장소 시스템으로 보내는 대신 수정된 블록만 전송해야 함
높은 일관성 요구사항
강한 일관성 모델을 기본으로 지원해야 함 (= 같은 파일이 단말이나 사용자에 따라 다르게 보이는 것은 허용할 수 없음). 메타데이터 캐시와 데이터베이스 계층에도 같은 원칙이 적용되어야 함
메모리 캐시는 보통 결과적 일관성 모델을 지원
강한 일관성을 달성하려면 다음 사항이 보장되어야 함
- 캐시에 보관된 사본과 데이터베이스에 있는 원본이 일치
- 데이터베이스에 보관된 원본에 변경이 발생하면 캐시에 있는 사본 무효화
관계형 데이터베이스는 ACID를 보장하므로 강한 일관성을 보장하기 쉬움
NoSQL 데이터베이스는 이를 기본으로 지원하지 않으므로, 동기화 로직 안에 프로그램해 넣어야 함
메타데이터 데이터베이스

namespace
: 사용자의 루트 디렉터리 정보가 보관됨
file_version
: 파일의 갱신 이력이 보관되는 테이블
업로드 절차

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

알림 서비스
목적 : 파일의 일관성을 유지하기 위해, 클라이언트는 로컬에서 파일이 수정되었음을 감지하는 순간 다른 클라이언트에 그 사실을 알려 충돌 가능성을 줄여야 함
이벤트 데이터를 클라이언트로 보내는 방법
- 롱 폴링 (드롭박스가 채택중) →
선택
- 클라이언트는 알림 서버와 롱 폴링용 연결을 유지하다가 특정 파일에 대한 변경을 감지하면 해당 연결을 끊음
- 웹소켓
- 그러나 여기서는 양방향 통신이 필요하지 않음(서버 → 클라 방향만 존재)
- 실시간 양방향 통신이 요구되는 채팅 같은 응용에 적합함. 구글 드라이브의 경우 알림을 보낼 일은 그렇게 자주 발생하지 않으며, 알림을 보내야 하는 경우에도 단시간에 많은 양의 데이터를 보낼 일은 없음
저장소 공간 절약
파일의 여러 버전을 여러 데이터센터에 보관할 필요가 있는데, 모든 버전을 자주 백업하면 저장용량이 너무 빨리 소진됨
- 중복 제거 : 중복된 파일 블록을 계정 차원에서 제거
- 지능적 백업전략 도입
- 한도설정 : 보관해야 하는 파일 버전 개수에 상한을 둠
- 중요한 버전만 보관 : 어떤 파일은 아주 자주 바뀜. 불필요한 버전과 사본이 만들어지는 것을 피하려면 그 가운데 중요한 것만 골라내야 함
- 자주 쓰이지 않는 데이터는 아카이빙 저장소로 옮김 (몇달 혹은 수년간 이용되지 않은 데이터)
장애 처리
- 로드밸런서 : 로드밸런서에 장애가 발생할 경우 부 로드밸런서가 활성화되어 트래픽 이어받음
- 블록 저장소 서버 장애 : 블록 저장소 서버에 장애가 발생 시, 다른 서버가 미완료 상태 또는 대기 상태인 작업을 이어받아야 함
- 클라우드 저장소 장애 : 다중화
- api 서버 장애 : 스케일 아웃 & 트래픽 차단
- 메타데이터 캐시 장애 : 다중화
- 메타데이터 데이터베이스 장애 : 다중화
- 주 데이터베이스 서버 장애 : 부 데이터베이스 서버를 주 데이터베이스 서버로 변경
- 부 데이터베이스 서버 장애 : 다른 부 데이터베이스 서버가 읽기 연산 처리하도록 하고 장애 서버 새것으로 교체
- 알림 서비스 장애 : 접속 중인 모든 사용자는 알림 서버와 롱 폴링 연결을 유지함
- 2012년 드롭박스 행사 발표자료에 따르면, 한 대의 드롭박스 알림 서비스 서버가 관리하는 연결의 수는 1백만 개가 넘음. 한대 서버 장애 발생 시 백만 명 이상의 사용자의 롱폴링 연결을 다시 만들어야 함
- 동시에 백만 개 이상의 접속을 유지하는 것은 가능하지만, 동시에 백만 개 접속을 ‘시작’하는 것은 불가능 ⇒ 롱 폴링 연결 복구가 상대적으로 느릴 수 있음
- 오프라인 사용자 백업 큐 장애 : 다중화