시스템 설계 면접 스터디도 마지막 주차가 되었다.
오늘은 구글 드라이브를 설계해보는 상황으로 진행한다.
구글 드라이브와 같이 드롭박스, 원드라이브, iCloud 와 같은 클라우드 저장소 서비스에 대한 설계이다.
문제 이해 및 설계 범위 확정
기능적 요구사항
- 기능: 파일 업로드/다운로드, 파일 동기화, 알림
- 파일 암호화 제공
- 제한은 10GB
- DAU: 천만명
비기능적 요구사항
- 안정성
- 빠른 동기화 속도
- 네트워크 대역폭
- 규모 확장성
- 높은 가용성
개략적 추정치
- 가입자 5천만명, DAU 1천만명
- 모든 사용자에게 10GB 제공 → 500페타바이트 필요
- 평균 500KB, 하루에 2개
- 읽기 쓰기 비율은 1대1
- 업로드 API QPS = 약 240
- 최대 QPS = 약 480
개략적 설계안 제시 및 동의 구하기
필요한 구성요소
- 웹 서버
- 메타데이터 데이터베이스
- 파일 저장소
웹 서버
3개의 API를 제공해야한다.
업로드, 다운로드, 히스토리
- 앞단의 로드밸런서를 두어 대처
메타데이터 DB
파일이 아닌 해당 파일의 정보를 저장한다.
속도 측면을 위해 캐시를 앞 단에 둘 수 있다.
파일 저장소
파일 저장소의 경우는 확장성과 안정성을 위해 클라우드 서비스의 S3와 같은 저장소를 사용한다.
여기서 지능형으로 사용을 안하는 데이터는 글랜시어와 같은 아카이브 저장소로 보내는 등 티어를 나눌 수 있다.
동기화 문제
이러한 경우 여러 클라이언트가 하나의 파일에 대한 수정을 하려할 수 있다.
그럴 때 발생하는게 이 문제이다.
동시에 작업을 해도 서버가 받아들이는 순서로 나중 것은 충돌이 발생했다고 알려줘야한다.
이 때 이름이 사본을 만들어서 작업한 것이 사라지지 않게 하는것도 중요하다.
계략적 설계안
- 블록 저장소 서버
- 하나의 파일을 여러 개로 나눠 저장 → 네트워크 대역폭 적게 차지
- 클라우드 저장소
- 아카이빙 저장소
- 로드밸런서
- API 서버
- 메타데이터 DB
- 메타데이터 캐시
- 알림 서비스: 클라이언트에게 파일이 추가, 수정, 삭제 되었다는 정보를 pub/sub 방식으로 전달
- 오프라인 사용자 백업 큐: 파일이 달라진 부분을 수정하기 위해 큐에 담아두고, 클라이언트 접속 시 적용
상세 설계
블록 저장소 서버
큰 파일을 한 번에 건들면 네트워크 대역폭을 많이 먹게 된다.
이를 최적화 하기 위해 블록 단위로 저장해
수정된 일부 블록만 수정한다. → 델타 동기화 전략
블록 단위로 압축해 관리한다.
이렇게 하기 위해 새로운 파일이 들어오면 먼저 블록 저장소 서버에서 해당 파일을 일정 크기로 분할하고 ID를 부여한다. 나중에 이 블록들을 순서대로 묶어 사용하면 된다.
높은 일관성 요구사항
이 시스템은 강한 일관성을 제공해야한다.
즉 누가 언제 열어도 모두 똑같은 걸 봐야한다.
메모리 캐시는 일반적으로 결과적 일관성을 보장한다.
일관성이 깨질 수 있지만, 언젠가 제대로 보여준다는 것이다.
우리가 원하는 건 강한 일관성이니 다음을 만족해야한다.
- 캐시에 보관된 사본과 DB에 원본이 일치해야한다
- DB에 원본에 변경이 발생하면 캐시는 무효화 되어야 한다.
이걸 RDBMS에 저장한다면 ACID원칙으로 강한 일관성 보장이 쉽지만,
NoSQL의 경우 기본적으로 지원 안해서 동기화 로직 안에 프로그램해 넣어야 한다.
그렇기에 메타데이터 디비는 RDBMS 사용됨
업로드 절차
이제 가장 중요한 업로드/다운로드 설계를 보겠다.
사용자가 파일을 올리면 어떤 일이 벌어지는지 살펴보면, 먼저 블록 저장소 서버에서 분할 후 저장소에 저장된다.
메타데이터 저장과 파일 저장이 병렬적으로 수행된다.
- 파일 메타데이터 추가
- 클라이언트 1이 새 파일의 메타데이터를 추가하기 위한 요청 전송
- 새 파일의 메타데이터를 데이터베이스에 저장하고 업로드 상태를 대기중으로 변경
- 새 파일이 추가되었음을 알림 서비스에 통지
- 알림 서비스는 관련된 클라이언트에게 파일이 업로드되고 있음을 알림
- 파일을 클라우드 저장소에 업로드
- 클라이언트 1이 파일을 블록 저장소 서버에 업로드
- 블록 단위로 나눠 압축 + 암호화 진행 후 클라우드 저장소로 전송
- 완료 시 콜백으로 API 서버로 전송
- 업로드 상태를 완료로 변경
- 알림 서비스에 파일 업로드 끝이라고 통지
- 알림 서비스 관련 클라이언트는 끝났음 알림을 받음
다운로드 절차
새로 추가되거나 편집되면 자동으로 시작된다.
그렇게 하기 위해서는 변경을 감지해야한다.
- 클라이언트 접속 중일 때는 알림 발생으로 새로운 버전 가져오기
- 접속 중이 아니면 변경이 되었다는 데이터가 캐시에 보관되고(큐) 접속 시 해당 변경 가져옴
이렇게 변경을 알았다면 클라이언트는 먼저 API를 보내 메타데이터를 받아와야한다.
그 후 새롭게 변경된 블록을 가져와 최신화 해야한다.
- 알림 서비스가 파일이 변경되었다고 알림
- 새로운 메타데이터 요청
- 해당 데이터로 블록 다운로드 요청
- 클라우드에서 새로운 블록 다운
- 파일 재구성
알림 서비스
파일의 일관성을 유지하기 위해, 클라이언트는 로컬에서 파일이 수정되었음을 감지하는 순간 다른 클라이언트에 그 사실을 알려서 충돌 가능성을 줄여야 한다. 알림 서비스는 그 목적으로 이용된다.
이를 구현하기 위해
- 롱 폴링
- 웹 소켓
- SSE
방식이 있는데 알림은 일방향 통신만 되면 되기에 웹소켓은 불필요하다.
저장소 공간 절약
클라우드 서비스를 사용하기에 용량은 곧 돈이다.
최대한 절약해야한다.
- 중복 제거: 동일한 블록을 계정단위로 제거하는 것 → 해시 값 비교로 간단하게 구현
- 지능적 백업 전략
- 버전 개수의 한도를 두기
- 중요 버전만 보관
- 자주 쓰지 않는 건 아카이빙 저장소에 넣기
장애 처리
이런 여러 컴포는트가 들어가는 서비스는 장애 처리에 있어서 각 컴포넌트들 모두를 신경써야 한다.
- 로드밸런서 장애
- 부 로드밸런서를 두고 헬스체크를 주기적으로
- 블록 저장소 서버 장애
- 다른 저장소 서버가 미완료 파일 대신 처리 로직
- 클라우드 저장소 장애
- 지역 다중화
- API 서버 장애
- 무상태성으로 설계해 다른 서버로 로드밸런싱
- 메타데이터 캐시 장애
- 캐시 서버 다중화
- 메타데이터 DB 장애
- 마스터 슬래이브 구조
- 알림 서비스 장애
- 서버 다중화 → 롱 폴링 재연결은 시간이 많이 듬
- 오프라인 사용자 백업 큐 장애
- 큐 다중화
마무리
구글 드라이브를 설계하면서
- 파일 나눠 저장
- 업로드/다운로드 절차
- 알림 서비스 적용
등을 알아봤다.
지금까지 15장의 다양한 시스템을 알아봤는데
가장 중요한건 다중화 같다.
하나의 시스템의 SPOF을 두지 않기위해서는 다중화 말고는 답이 없다는 걸 알게 되었다.
또한 컴포넌트 간의 결합도가 낮은게 좋다는 점 그렇기에 각 사이에 메시지 큐를 두어 비동기로 처리 가능하게 두는 것도 중요한 점이었다.
'스터디 > 시스템 설계 스터디' 카테고리의 다른 글
| [면접 스터디] 예상질문: 14. 유뷰트 설계 (1) | 2025.07.30 |
|---|---|
| [면접 스터디] 개념정리: 14. 유튜브 설계 (3) | 2025.07.30 |
| [면접 스터디] 예상질문: 13. 검색어 자동완성 시스템 (1) | 2025.07.18 |
| [면접 스터디] 개념정리: 13. 검색어 자동완성 시스템 (0) | 2025.07.18 |
| [면접 스터디] 예상질문: 12. 채팅 시스템 설계 (0) | 2025.07.17 |