728x90
가상 면접 사례로 배우는 대규모 시스템 설계 기초 "구글 드라이브 설계"을 요약한 내용입니다.
1단계 문제 이해 및 설계 범위 확정
- 파일 추가, 가장 쉬운 방법은 파일을 구글 드라이브 안으로 떨구는 것
- 파일 다운로드
- 여러 단말에 파일 동기화, 한 단말에서 파일을 추가하면 다른 단말에도 자동으로 동기화 되어야 함
- 파일 갱신 이력 조회
- 파일 공유
- 파일이 편집되거나 삭제되거나 새롭게 공유되었을 때 알림 표시
이번 장에서는 다음 기능은 논의하지 않을 것
- 구글 문서 편집 및 협업 기능, 구글 문서는 여러 사용자가 같은 문서를 동시에 편집할 수 있도록 하는데, 이부분은 설계 범위에서 제외
기능적 요구사항 이외에, 비-기능적 요구사항을 이해하는 것도 중요
- 안정성: 저장소 시스템에서 안정성은 아주 중요하다. 데이터 손실은 발생하면 안된다.
- 빠른 동기화 속도: 파일 동기화에 시간이 너무 많이 걸리면 사용자는 인내심을 일고 해당 제푼을 더이상 사용하지 않게 될 것이다.
- 네트워크 대역폭: 이 제품이 네트워크 대역폭을 불필요하게 많이 소모한다면 사용자는 좋아하지 않을 것
- 규모 확장성: 이 시스템은 아주 많은 양의 트래픽도 처리 가능해야한다.
- 높은 가용성: 일부 서버에 장애가 발생하거나, 느려지거나, 네트워크 일부가 끊겨도 시스템은 계속 사용 가능해야 한다.
개략적 추정치
- 가입 사용자는 5000만명이고 1000만명의 DAU 사용자가 있다고 가정
- 모든 사용자에게 10GB의 무료 저장공간 할당
- 매일 각 사용자가 평균 2개의 파일을 업로드한다고 가정, 각 파일의 평균 크기는 500KB
- 읽기:쓰기 비율을 1:1
- 필요한 저장공간 총량 = 5000만 사용자 X 10GB = 500페타바이트
- 업로드 API QPS = 1000만 사용자 X 2회 업로드 / 24시간 / 3600초 = 약 240
- 최대 QPS = QPS X 2 = 480
2단계 개략적 설계안 제시 및 동의 구하기
아래와 같은 구성의 서버 한대로 시작
- 파일을 올리고 다운로드 하는 과정을 처리할 웹 서버
- 사용자 데이터, 로그인 정보, 파일 정보 등의 메타데이터를 보관할 데이터베이스
- 파일을 저장할 저장소 시스템, 파일 저장을 위해 1TB의 공간을 사용할 것
API
시스템은 기본적으로 세 가지 API가 필요함
- 파일 업로드 API
- 단순 업로드: 파일 크기가 작을 때 사용
- 이어 올리기: 파일 사이즈가 크고 네트워크 문제로 업로드가 중단될 가능성이 높다고 생각되면 사용
- 다운로드 API
- 파일 갱신 히스토리 제공 API
개략적 설계안
[그림 15-10]은 개략적 설계안이다.
- 사용자 단말: 사용자가 이용하는 웹브라우저나 모바일 앱 등의 클라이언트
- 블록 저장소 서버: 파일 블록을 클라우드 저장소에 업로드하는 서버
- 블록 저장소는 블록 수준 저장소라고 하며, 클라우드 환경에서 데이터 파일을 저장하는 기술
- 파일을 여러개의 블록으로 나눠 저장하며, 각 블록에는 고유한 해시값이 할당
- 해시값은 메타데이터 데이터베이스에 저장
- 각 블록은 독립적인 객채로 취급되며 클라우드 저장소 시스템에 보관
- 파일을 재구성하려면 블록들을 원래 순서대로 합처야 함
- 클라우드 저장소: 파일은 블록 단위로 나눠져 클라우드 저장소에 보관
- 아카이빙 저장소: 오랫동안 사용되지 않는 비활성 데이터를 저장하기 위한 컴퓨터 시스템
- 로드밸런서: 요청을 모든 API 서버에 고르게 분산하는 구실
- API 서버: 파일 업로드 외 거의 모든 것을 담당하는 서버
- 메타데이터 데이터베이스: 사용자, 파일, 블록, 버전 등의 메타데이터 정보를 관리
- 파일은 클라우드에 보관하며, 데이터베이스에는 오직 메타 데이터만 둔다는 것을 명심
- 메타데이터 캐시: 성능을 높이기 위해 자주 쓰이는 메타데이터는 캐시
- 알림 서비스: 특정 이벤트가 발생했음을 클라이언트에게 알리는데 쓰이는 발생/구독 프로토콜 기반 시스템
- 오프라인 사용자 백업 큐: 클라이언트가 접속 중이 아니라서 파일의 최신 상태를 확인할 수 없을 때는 해당 정보를 큐에 두어 나중에 클라이언트가 접속했을 때 동기화 될 수 있도록 한다.
3단계 상세 설계
블록 저장소 서버
- 정기적으로 갱싱되는 큰 파일들은 업데이트가 일어날 때마다 전체 파일을 서버로 보내면 네트워크 대역폭을 많이 잡아먹게 된다.
- 최적화하는 방법으로는 델타 동기화, 압축 정도를 생각해볼수 있다.
- 델타 동기화: 파일이 수정되면 전체 파일 대신 수정이 일어난 블록만 동기화 하는 것
- 압축: 블록 단위로 압축해 두면 데이터 크기를 많이 줄일 수 있다. 이때 압축 알고리즘은 파일 유형에 따라 정한다. 예를 들어 텍스트 파일을 압축할 때는 gzip이나 bzip2를 쓰고, 이미지나 비디오를 압축할 때는 다른 압축 알고리즘을 쓰는 것이다.
- [그림 15-11]은 새파일이 추가 되었을때 블록 저장소 서버가 어떻게 동작하는지 나와 있다
- 주어진 파일을 작은 블록들로 분할한다.
- 각 블록을 압축한다.
- 클라우드 저장소로 보내기 전에 암호화 한다.
- 클라우드 저장소로 보낸다.
높은 일관성 요구사항
- 이 시스템은 강한 일관성 모델을 기본으로 지원해야 한다.
- 같은 파일이 단말이나 사용자에 따라 다르게 보이는 것은 허용할 수 없다는 뜻이다.
- 메타 데이터 캐시와 데이터베이스 계층에도 같은 원칙이 적용되어야 한다.
- 메모리 캐시는 보통 최종 일관성 모델을 지원한다.
- 캐시에 보관된 사본과 데이터베이스에 있는 원본이 일치한다.
- 데이터베이스에 보관된 원본에 변경이 발생하면 캐시에 있는 사본을 무효화 한다.
- 관계형 데이터베이스는 ACID를 보장하므로 강한 일관성을 보장하기 쉽다.
- NoSQL 데이터베이스는 이를 기본으로 지원하지 않으므로, 동기화 로직 안에 프로그램해 넣어야한다.
- 이번 설계에서는 관계형 데이터베이스를 채택하여 높은 일관성 요구사항에 대응할 것이다.
메타데이터 데이터베이스
- [그림 15-13]은 데이터베이스 스키마 설계안이다.
- user: user 테이블에는 이름, 이메일, 프로파일 사진 등 사용자에 관계된 기본적 정보들이 보관된다.
- device: device 테이블에는 단말 정보가 보관된다. push_id는 모바일 푸시 알림을 보내고 받기 위한 것, 한 사용자가 여러 대의 단말을 가질 수 있음에 유의하자.
- namespace: 사용자의 루트 디렉터리 정보가 보관된다.
- file: 파일 최신 정보가 보관된다.
- file_version: 파일의 갱신 이력이 보관되는 테이블이다. 이 테이블에 보관되는 레코드는 전부 읽기 전용이다. 갱신 이력이 훼손되는 것을 막기 위한 조치
- block: 파일 블록에 대한 정보를 보관하는 테이블이다. 특정 버전의 파일은 파일 블록을 올바른 순서로 조합하기만 하면 복원해 낼 수 있다.
업로드 절차
파일 메타 데이터 추가
- 클라이언트 1이 새 파일의 메타데이터를 추가하기 위한 요청 전송
- 새 파일의 메타데이터를 데이터베이스에 저아하고 업로드 상태를 대기 중으로 변경
- 새 파일이 추가되었음을 알림 서버에 통지
- 알림 서비스는 관련된 클라이언트에게 파일 업로드 되고 있음을 알림
파일을 클라우드 저장소에 업로드
- 클라이언트 1이 파일을 블록 저장소 서버에 업로드
- 블록 저장소 서버는 파일을 블록 단위로 쪼갠 다음 압축하고 함호화 한다음에 클라우드 저장소에 전송
- 업로드가 끝나면 클라우드 스토리지는 완료 콜백을 호출 이 콜백 호출은 API 서버로 전송됨
- 메타데이터DB에 기록된 해당 파일의 상태를 완료로 변경
- 알림 서비스에 파일 업로드가 끝났음을 통지
- 알림 서비스는 관련된 클라이언트에게 파일 업로드가 끝났음을 알림
다운로드 절차
- 파일 다운로드는 파일이 새로 추가되거나 편집되면 자동으로 시작된다.
- 클라이언트는 다른 클라이언트가 파일을 편집하거나 추가했다는 사실을 어떻게 감지하는 것일까?
- 클라이언트 A가 접속 중이고 다른 클라이언트가 파일을 변경하면 알림 서비스가 클라이언트 A에게 변경이 발생했으니 새 버전을 끌어가야 한다고 알린다.
- 클라이언트 A가 네트워크에 연결된 상태가 아닐 경우에는 데이터는 캐시에 보관될 것이다. 해당 클라이언트의 상태가 접속 중으로 바뀌면 그때 해당 클라이언트는 새 버전을 가져갈 것이다.
블록들을 다운 받아 파일을 재구성하는 흐름
- 알림 서비스가 클라이언트 2에게 누군가 파일을 변경했음을 알림
- 알림을 확인한 클라이언트 2는 새로운 메타데이터를 요청
- API 서버는 메타데이터 데이터베이스에게 새 메타데이터 요청
- API 서버에게 새 메타데이터가 반환됨
- 클라이언트 2에게 새 메타데이터가 반환됨
- 클라이언트 2는 새 메타데이터를 받는 즉시 블록 다운로드 요청 전송
- 블록 저장소 서버는 클라우드 저장소에서 블록 다운로드
- 클라우드 저장소는 블록 서버에 요청된 블록 반환
- 블록 저장소 서버는 클라이언트에게 요청된 블록 반환, 클라이언트 2는 전송된 블록을 사용하여 파일 재구성
알림 서비스
- 파일의 일관성을 유지하기 위해, 클라이언트는 로컬에서 파일이 수정되었음을 감지하는 순간 다른 클라이언트에 그 사실을 알려서 충동 가능성을 줄여야 한다.
- 알림 서비스는 이벤트 데이터를 클라이언트로 보내는 서비스
- 롱 폴링: 드롭박스가 이 방식을 채택하고 있다.
- 웹 소켓: 클라이언트와 서버 사이에 지속적인 통신 채널을 제공 한다.
- 따라서 양방향 통신이 가능하다
- 이번 설계안의 경우에는 롱 폴링을 사용할 것이다.
- 채팅서비스와 달리 본 시스템의 경우에는 알림 서비스와 양방향 통신이 필요하지 않다.
- 파일이 변경된 사실을 클라이언트에게 알려줘야하지만 반대 방향의 통신은 요구되지 않는다.
- 웹소켓은 실시간 양방향 통신이 요구되는 채팅 같은 응용에 적합
- 구글 드라이브의 경우 알림을 보낼 일이 그렇게 자주 발생하지 않으며, 알림을 보내야하는 경우에도 단시간에 많은 양의 데이터를 보낼 일은 없다.
- 롱 폴링의 경우 각 클라이언트는 알림 서버와 롱폴링용 연결을 유지하다가 특정 파일에 대한 변경을 감지하면 해당 연결을 끊는다.
- 클라이언트는 최신 내역을 다운로드 해야한다.
- 다운로드 작업이 끝났거나 연결 타임아웃 시간에 도달한 경우에는 즉시 새 요청을 보내어 롱 폴링 연경을 복원하고 유지해야 한다.
저장소 공간 절약
- 파일 갱신 이력을 보존하고 안정성을 보장하기 위해서는 파일의 여러 버전을 여러 데이터센터에 보관할 필요가 있다.
- 모든 버전을 자주 백업하게 되면 저장용량이 빨리 소진된 가능성이 있다.
- 중복 제거
- 중복된 파일 블록을 계정 차원에 제거하는 방법
- 두 블록이 같은 블록인지는 해시 값을 비교하여 판다.
- 지능적 백업 전략을 도입
- 한도 설정: 보관해야할 파일 버전 개수에 상한을 두는것, 젤 오래된 버전은 버린다.
- 중요한 버전만 보관: 자주 바뀌는 경우 짧은 시간동안 많은 버전이 만들어질 수 있다. 불필요한 버전과 사본이 만들어지는 것을 피하려면 그 가운데 중요한 것만 골라내야 한다.
- 자주 쓰이지 않는 데이턴는 아카이빙 저장소로 옮긴다.
- 몇달 혹은 수년간 이용되지 않는 데이터가 이에 해당한다.
- 아마존 S3 글레시어 같은 아카이빙 저장소는 이용료는 S3보다 훨씬 저렴하다.
- 중복 제거
장애 처리
- 로드밸런서 장애
- 로드밸런서에 장애가 발생할 경우 부 로드밸런서가 활성화되어 트래픽을 이어 받아야한다.
- 로드 밸런서끼리는 보통 박동 신호를 주기적으로 보내서 상태를 모니터링 한다.
- 블록 저장소 서버 장애
- 다른 서버가 미완료 상태 또는 대기 상태인 작업을 이어받아야한다.
- 클라우드 저장소 장애
- S3버킷은 여러 지역에 다중화할 수 있으므로, 한지역에서 장애가 발생하였다면 다른 지역에서 파일을 가져오면 된다.
- API 서버 장애
- API 서버들은 무 상태 서버다
- 로드밸런서는 API 서버에 장애가 발생하면 트래픽을 해당 서버로 보내지 않으므로써 장애 서버를 격리할 것이다.
- 메타데이터 캐시 장애
- 메타데이터 캐시 서버도 다중화해야한다.
- 한 노드에 장애가 생겨도 다른 노드에서 데이터를 가져올 수 있다.
- 장애가 발생한 서버는 새 서버로 교체하면 된다.
- 메타데이터 데이터베이스 장애
- 주 데이터베이스 서버 장애: 부 데이터베이스 서버 가운데 하나를 주 데이터베이스 서버로 바꾸고, 부 데이터베이스 서버를 새로 하나 추가 한다.
- 부 데이터베이스 서버 장애: 다른 부 데이터베이스 서버가 읽기 연산을 처리하도록 하고 그동안 장애 서버는 새 것으로 교체한다.
- 알림 서비스 장애
- 접속 중인 모든 사용자는 알림 서버와 롱폴링 연결을 하나씩 유지한다.
- 많은 사용자와의 연결을 유지하고 관리 해야한다.
- 드롭 박스 발표 자료에 따르면 알림 서비스 서버가 관리하는 연결의 수는 1백만 개가 넘는다.
- 한대의 서버에 장애가 발생하면 백만명 이상의 사용자가 롱 폴링연결을 다시 만들어야 한다.
- 주의할 것은 한 대 서버로 백만개 이상의 접속을 유지하는 것은 가능하지만, 동시에 백만 개 접속을 ‘시작’하는 것은 불가능 하다
- 롱 폴링 연결을 복구하는 것은 상태적으로 느릴수 있다.
- 오프라인 사용자 백업 큐 장애
- 이 큐 또한 다중화해 두어야 한다.
- 큐에 장애가 발생하면 구독 중인 클라이언트들은 백업 큐로 구독 관계를 재설정해야 할것
4단계 마무리
- 이번 설계안은 크게 두가지 부분으로 구성 된다.
- 파일의 메타데이터를 관리하는 부분
- 파일 동기화를 처리하는 부분
- 블록 저장소 서버를 거치지 않고 파일을 클라우드 저장소에 직업 업로드 한다면?
- 단점
- 분할, 압축, 암호화 로직을 클라이언트에 두어야 하므로 플랫폼별로 따로 구현해야함
- 당초 설계안에서는 이 모두를 블록 저장소 서버라는 곳에 모아 뒀으므로 그럴 필요가 없었다.
- 클라이언트가 해킹 당할 가능성이 있으므로 암호화 로직을 클라이언트 안에 두는 것은 적절치 않은 선택일 수 있다.
- 분할, 압축, 암호화 로직을 클라이언트에 두어야 하므로 플랫폼별로 따로 구현해야함
- 단점
- 접속상태를 관리하는 로직을 별도 서비스로 옮기는 것
- 다른 서비스에서도 쉽게 활용할 수 있게 되므로 좋을 것
728x90
'가상 면접 사례로 배우는 대규모 시스템 설계 기초' 카테고리의 다른 글
유튜브 설계 (2) | 2023.11.09 |
---|---|
검색어 자동완성 시스템 (0) | 2023.11.09 |
채팅 시스템 설계 (1) | 2023.11.09 |
뉴스 피드 시스템 설계 (0) | 2023.11.09 |
알림 시스템 설계 (1) | 2023.11.09 |