15. Design Google Drive
구글 드라이브 설계
1. 문제 이해 및 설계 범위 설정
1.1. 기능적 요구사항
파일 추가
파일 다운로드
여러 단말에 파일 동기화
파일 갱신 이력 조회(revision history)
파일 공유
파일이 편집되거나 삭제되거나 새롭게 공유되었을 때 알림 표시.
1.2. 비기능적 요구사항
안정성
빠른 동기화 속도
네트워크 대역폭
규모 확장성
높은 가용성
2. 개략적 설계안
2.1. API
파일 업로드 API: 단순 업로드와 이어 올리기로 나뉩니다.
파일 다운로드 API
파일 갱신 히스토리 API
2.2. 전체 블루프린트
사용자 단말
블록 저장소 서버: 파일 블록을 클라우드 저장소에 업로드하는 서버. 블록 수준 저장소라고도 하며, 클라우드 환경에서 데이터 파일을 저장하는 기술입니다. 파일을 여러개의 블록으로 나눠서 저장하며, 각 블로에는 고유한 해시값이 할당됩니다. 이 해시값은 메타데이터 데이터베이스에 저장됩니다. 각 블록은 독립적인 객체로 취급되며 클라우드 저장소 시스템(S3)에 보관됩니다. 파일을 재구성하기 위해서는 원래 순서대로 합쳐야합니다.
클라우드 저장소: 블록 단위로 나눠진 파일을 저장하는 곳입니다.
아카이빙 저장소: 오랫동안 사용되지 않은 비활성 데이터를 저장합니다.
로드밸런서
API서버
메타데이터 데이터베이스: 메타데이터만 저장하며, 실제 파일은 클라우드 저장소에 있습니다.
메타데이터 캐시
알림 서비스: 특정 이벤트가 발생했음을 클라이언트에게 알리는 발생/구독 프로토콜 기반 시스템. 파일 추가/편집/삭제 알림을 클라이언트에게 보냅니다.
오프라인 사용자 백업 큐: 클라이언트가 오프라인이라서 파일의 최신 상태를 확인할 수 없을때, 나중에 온라인일때 동기화될 수 있도록 큐에 넣습니다.
2.3. 동기화 충돌
2.3.1. 여러 클라이언트가 같은 파일을 수정
사용자 A와 사용자 B가 같은 문서를 동시에 수정한다고 가정합니다. 사용자 A는 파일을 오프라인 상태에서 수정한 후 서버에 동기화하려 하고, 사용자 B는 온라인 상태에서 바로 서버에 변경 사항을 반영하고 있습니다.
2.3.2. 오프라인과 온라인의 충돌
사용자 A가 오프라인 상태에서 파일을 수정하고, 나중에 네트워크에 연결되어 파일을 서버에 업로드하려고 할 때, 이미 사용자 B의 수정된 내용이 서버에 반영되어 있을 수 있습니다. 이 경우 두 클라이언트가 서로 다른 변경 사항을 서버에 업로드하려 하므로 충돌이 발생합니다.
2.3.3. 구글 드라이브의 동기화 충돌 처리
버전 관리 구글 드라이브는 파일의 여러 버전을 관리합니다. 서버에서 새로운 버전이 생성될 때마다 그 버전이 기록되고, 동기화 시 충돌이 발생하면 두 버전을 비교하고 합칠 수 있는 방법을 찾습니다.
수동 충돌 해결 충돌이 자동으로 해결되지 않을 경우. 사용자가 직접 어떤 변경 사항을 유지할지 선택해야 할 수도 있습니다. 이를 위해 구글 드라이브는 파일의 이전 버전과 새로운 버전을 나란히 비교해서 보여주는 기능을 제공합니다.
3. 상세 설계
3.1. 블록 저장소 서버
블록 저장소 서버는 데이터를 효율적으로 관리하고 동기화하는 핵심 역할을 합니다. 블록 저장소는 파일을 여러 작은 블록 단위로 쪼개어 저장하고 관리하는 방식으로 동작합니다. (저장과 작업을 같이하는 서버)
저장소 역할: 실제 데이터를 저장하는 공간을 제공합니다. 파일을 블록 단위로 나누고, 각 블록은 해당 서버에 물리적으로 저장됩니다.
서버 역할: 데이터를 블록으로 나누고 관리 동기화 중복 제거 충돌 관리
정기적으로 갱신되는 큰 파일들은 업데이트가 일어날 때마다 전체 파일을 서버로 보내면 네트워크 대역폭을 많이 잡아먹게 됩니다. 이를 최적화하는 방법으로는 두 가지를 생각해 볼 수 있습니다.
델타 동기화: 파일이 수정되면 전체 파일 대신 수정이 일어난 블록만 동기화합니다.
압축: 블록 단위로 압축해 두면 데이터 크기를 많이 줄일 수 있습니다. 파일 유형에 따라 압축 알고리즘이 다릅니다.
3.1.1. 블록 저장소 서버의 역할
데이터의 효율적인 저장
클라이언트의 파일을 고유한 식별자를 가진 일정한 크기의 블록으로 나눠서 저장합니다. 블록으로 나눠서 저장함으로써, 파일 변경이 발생할때, 변경된 블록만 저장하여 효율성을 극대화합니다.
동기화 및 변경 관리
사용자가 파일을 수정하면 클라이언트는 수정된 블록만 서버에 전송합니다. 블록 서버는 해당 블록을 기존 데이터와 병합하거나 새 버전으로 관리합니다.
이를 통해 동기화가 보다 빠르고 효율적으로 이루어지며, 네트워크 부하도 줄일 수 있습니다.
버전 관리 및 충돌 처리
블록 저장소 서버는 파일의 여러 버전을 관리합니다. 파일의 일부 블록만 수정된 경우에도 이전 버전의 블록들과 새로운 버전의 블록들을 비교하고 관리합니다.
충돌이 발생하면, 서로 다른 클라이언트가 서로 다른 블록을 수정했다면, 충돌된 블록만 확인하고 처리합니다.
데이터 중복 제거
파일의 여러 사용자가 같은 내용을 수정하거나 같은 파일을 업로드하는 경우, 서버는 중복된 데이터를 하나의 블록으로 저장하고 여러 사용자가 이를 참조합니다.
3.2. 메타데이터 데이터베이스
NoSQL 데이터베이스는 기본적으로 ACID를 지원하지 않기 때문에 강한 일관성을 보장하지 않습니다. 메타데이터 캐시와 메타데이터 데이터베이스는 항상 일관해야합니다.
user
device: 단말 정보
namespace: 루트 디렉터리 정보
file: 최신 정보 보관
file_version: 파일의 갱신 이력을 보관(읽기전용, 레코드는 불변적으로 유지)
block: 파일 블록에 대한 정보를 보관.
3.3. 업로드, 수정 절차
1. 클라이언트 1이 새 파일의 메타데이터를 추가히기 위한 요청 전송
2. 새 파일의 메타데이터를 데이터베이스에 저장하고 업로드 상태를 대기중(pending)으로 변경
2.1. 클라이언트 1이 파일을 블록 저장소 서버에 업로드
2.2. 블록 저장소 서버는 파일을 블록 단위로 쪼갠 다음 압축, 암호화 단계를 거치고 클라우드 저장소에 전송
2.3. 업로드가 끝나면 클라우드 스토리지는 완료 콜백(callback)을 호출. 이 콜백 호출은 API 서버로 전송.
2.4. 메타데이터 DB에 기록된 해당 파일의 성태를 완료(uploaded)로 변경
2.5. 알림 서비스에 파일 업로드가 끝났음을 통지
2.6. 알림 서비스는 관련된 클라이언트(클라이언트 2)에게 파일 업로드가 끝났음을 알림
3. 새 파일이 추가되었음을 알림 서비스에 통지
4. 알림 서비스는 관련된 클라이언트에게 파일이 업로드되고 있음을 알림.
3.4. 다운로드 절차
파일이 새로 추가되거나 편집되면 자동으로 시작되는 절차입니다.
1. 알림 서비스가 클라이언트 2에게 누군가 파일을 변경했음을 알림.
2. 알림을 확인한 클라이언트 2는 새로운 메타데이터를 요청
3. API 서버는 메타데이터 데이터베이스에게 새 메타데이터 요청
4. API 서버에게 새 메타데이터가 반환
5. 클라이언트 2에게 새 메타데이터가 반환
6. 클라이언트 2는 새 메타데이터를 받는 즉시 블록 다운로드 요청 전송
7. 블록 저장소 서버는 클라우드 저장소에서 블록 다운로드
8. 클라우드 저장소는 블록 서버에 요청된 블록 반환
9. 블록 저장소 서버는 클라이언트에게 요청된 블록 반환. 클라이언트 2는 전송된 블록을 사용하여 파일 재구성.
3.5. 알림 서비스
이벤트 데이터를 클라이언트로 보내는 서비스. 파일의 일관성을 유지하기 위해, 클라이언트는 로컬에서 파일이 수정되었음을 감지하는 순간 다른 클라이언트에 그 사실을 알려서 충돌 가능성을 줄여야 합니다.
3.5.1. 롱 폴링
클라이언트가 서버에 요청을 보내고, 서버가 즉시 응답하지 않고, 변경 사항이 발생할 때까지 요청을 유지한 후 응답을 보냅니다.
클라이언트는 서버에 HTTP 요청을 보냅니다.
서버는 새로운 알림이나 변경 사항이 생길 때까지 이 요청을 열어둡니다.
변경 사항이 생기면 서버는 클라이언트에 응답을 보냅니다.
클라이언트는 응답을 받은 후 즉시 또 다른 요청을 서버에 보냅니다.
특징:
실시간 통신처럼 동작: 새로운 이벤트가 발생할 때마다 클라이언트가 거의 실시간으로 응답을 받을 수 있습니다.
낭비되는 리소스가 적음: 일반적인 폴링(정기적으로 서버에 요청을 보내는 방식)보다 서버 자원을 덜 소모합니다. 왜냐하면 서버는 변경이 있을 때만 응답하기 때문입니다.
단점: 각 요청이 완료되면 새로운 요청을 다시 보내는 방식이므로, 대규모 서비스에서는 서버와 클라이언트 간에 많은 연결을 유지해야 합니다. 또한, 요청을 유지하는 데 일정한 리소스가 사용됩니다.
3.5.2. 웹 소켓
웹소켓은 클라이언트와 서버 사이에 양방향 통신을 가능하게 하는 기술입니다. 한 번 연결이 성립되면, 클라이언트와 서버는 실시간으로 데이터를 주고받을 수 있습니다.
클라이언트가 서버와 웹소켓 연결을 설정합니다.
연결이 설정된 후, 클라이언트와 서버는 서로 데이터를 자유롭게 주고받을 수 있습니다. 클라이언트가 서버에 데이터를 요청하지 않아도, 서버는 클라이언트에 즉시 데이터를 보낼 수 있습니다.
웹소켓의 특징:
진정한 실시간 통신: 서버가 클라이언트에 데이터를 즉시 푸시할 수 있기 때문에 실시간 알림에 매우 적합합니다.
효율적인 자원 사용: 롱 폴링과 달리, 지속적인 HTTP 요청/응답 오버헤드가 없기 때문에 네트워크 자원을 더 효율적으로 사용할 수 있습니다.
복잡한 구현: 웹소켓 연결을 유지하려면 네트워크 환경에 따라 적절한 관리(예: 연결 끊김 처리, 재연결 등)가 필요할 수 있습니다.
롱 폴링은 비교적 단순하게 구현할 수 있고, 기존의 HTTP 기반 인프라를 그대로 사용할 수 있는 장점이 있지만, 서버 자원 사용과 응답 지연이 발생할 수 있습니다.
웹소켓은 매우 효율적인 실시간 통신을 제공하지만, 구현이 더 복잡하고 서버가 더 많은 상태 관리 및 네트워크 자원 사용을 필요로 할 수 있습니다.
3.6. 저장소 공간 절약 전략
3.6.1. 중복 제거
중복된 파일 블록을 계정 차원에서 제거하는 방법입니다. 두 블록이 같은 블록인지는 해시 값 사용합니다.
3.6.2. 지능적 백업 전략
한도 설정 보관해야 하는 파일 버전 개수에 상한을 둡니다.
중요한 버전만 보관 중요한 버전과 사본만 골라내어 유지하여 짧은 시간동안 많은 버전이 생성되더라도 저장하지 않습니다
3.6.3. 자주 쓰이지 않는 아카이빙 저장소로 옮깁니다.
아마존 Glacier와 같이 아카이빙 용도로만 쓰이는 저장소에 저장합니다.
3.7. 장애 처리
전체적으로, 다중화 시스템을 두어서, 하나의 SPOF를 피해야합니다.
Last updated