2022년 조사 결과 유투브에서 매일 재생되는 비디오 수는 10억을 넘는다고 한다. (https://www.omnicoreagency.com/youtube-statistics/)
말이 유튜브 설계지, 사실 영상 업로드 시스템 설계에 가까웠다.. (추천, 라이브 스트리밍에 대한 내용은 나와있지 않다.)
유튜브 같은 비디오 스트리밍 서비스와 다른 서비스의 가장 큰 차이점은 다루는 데이터의 크기 차이일 것이다. 단순 텍스트나 이미지 몇장이 아닌 비디오를 다룬다. 그래서 특별히 고려해야 할 점이 몇가지 있다.
.avi
, .mov
, .mp4
파일 확장자를 통해 컨테이너 포맷을 알 수 있다.앞서 언급했듯이 비디오는 다른 데이터와 조금 다르게 다룰 것이다. 빠른 재생을 위해 CDN을 사용하고, 메타데이터를 보관해 요청을 빠르게 처리할 것이다.
아래 그림에서 검은색 화살표는 영상 업로드 과정을, 빨간색 화살표는 영상 재생 과정을 나타낸다. 재생 과정은 심플하다. 곧바로 CDN에서 스트리밍을 받으면 된다. (책에서는 CDN에서 스트리밍하는 자세한 과정은 다루지 않았다.)
책에서는 업로드 과정을 좀 더 자세히 다루었다. 영상 1개를 업로드하기 위해 (1) 원본 저장소에서 CDN까지 (2) API서버와 메타데이터 캐시 및 DB 사이에 데이터가 흘러간다.
(1) 원본 저장소에서 CDN까지: 영상 인코딩을 비롯한 가공 작업을 거친 뒤 최종본을 CDN까지 업로드한다. 인코딩에 시간이 많이 걸리기 때문에 비동기로 처리하기 위해 중간에 인코딩 완료 큐를 두었다. 인코딩 완료 핸들러는 큐에서 각 영상을 꺼낸 뒤 메타데이터를 업데이트하고, 인코딩 된 영상 저장소로 보낸다. 마지막으로 사용자에게 직접 영상을 보여줄 CDN에 업로드한다.
(2) API서버에서 메타데이터 캐시/DB까지: (1)번 흐름이 이루어지는 동안 클라이언트는 병렬적으로 또다른 요청을 보낸다. 비디오 메타데이터를 업데이트하는 요청이다. 또한 비디오 업로드가 완료되면 API서버가 사용자에게 업로드가 완료 되었음을 알린다.
비디오 변환 작업은 여러 단계를 거칠 수 있다. 단순히 동영상을 압축하는 작업뿐만 아니라 워터마크를 표시하거나 인코딩 화질을 선택하는 등 비디오 업로더 맞춤 기능이 제공될 수 있기 때문이다. 책에서는 이런 커스텀 기능을 제공하기 위해 DAG(Directed Acyclic Graph) 프로그래밍 모델을 도입한 방식을 소개한다. 실제로 페이스북의 스트리밍 비디오 엔진이 이 모델을 사용한다.
원본 파일을 비디오(영상), 오디오 가공 단계와 메타데이터 생성 단계로 나누어 처리한다. 비디오와 오디오를 나누어 처리한 다음 마지막에 병합하는 방식이다.
빨간색으로 표시한 비디오 부분을 좀 더 살펴보자. 다음 작업을 수행한다.
그렇다면 위의 작업은 어떤 과정으로 수행될까? 각 작업은 시간과 컴퓨팅 파워를 꽤 잡아먹을 수 있기 때문에 다음 구조를 통해 비디오 작업이 이루어진다.
검사, 썸네일 추출, 워터마크, ...
의 작업 중 어떤 것을 수행해야 하는지와 수행 순서 등을 받아 DAG를 만든다.비디오 하나가 위 파이프라인을 거쳐가는 데 꽤 많은 시간이 소요될 것이다. 중간에 실패하는 경우도 있을 것이고, 지연되는 경우도 많을 것이다. 따라서 파이프라인의 각 단계가 이전 단계의 완료 여부에 의존하지 않을 수 있도록 비동기 처리가 필요하다. 즉, 앞 단계가 너무 빠르거나 너무 느리게 끝나더라도 자신이 할 일을 꾸준히 처리할 수 있도록 해줘야 한다.
비디오 전부를 단 한번만에 올리는 것은 비효율적이다. 지연이나 실패가 있을 수 있기 때문이다. 따라서 비디오 하나를 GOP 여러개로 분할해서 업로드하는 것이 좋다. 일부가 실패하더라도 빠르게 업로드를 재개할 수 있기 때문이다.
비디오 스트리밍 시 CDN을 사용하는 것과 같은 원리로, 비디오 업로더와 업로드 센터를 물리적으로 가깝게 위치시키는 것도 방법이다. 책에서는 아예 CDN을 업로드 센터로 사용한다.
원본 저장소에서 GOP를 다운로드하고, GOP를 인코딩하고, 이를 다시 인코딩 된 영상 저장소로 업로드 한 뒤 CDN으로 보내는… 일련의 작업 역시 비동기로 처리되어야 한다. 이를 위해 각 작업 사이에 메시지 큐를 도입해서 각 단계의 결합도를 낮출 수 있다. 예를 들어 인코딩 모듈과 업로드 모듈 사이에 메시지 큐를 두면, 인코딩 작업 속도와 관계 없이 업로드 작업을 병렬적으로 처리할 수 있다. 책에서는 모든 단계 사이에 메세지 큐를 두는 모습을 보여준다.
이제 영상 업로드가 아닌 빠른 접근을 위한 방법을 살펴보자. 사실 대부분 위에서 말한 내용이라 간략하게만 언급하겠다.
메타 데이터를 통해 영상에 빠르게 접근할 수 있다. 여기서 말하는 ‘접근’이란 검색, 영상 추천, 광고 등을 위해 동영상 정보를 탐색하는 것을 말한다. 당연히 재생을 위한 메타데이터도 저장된다. 주로 파일 이름, 크기, 포맷 등의 정보가 들어간다. 구글의 설명에 따르면 유튜브는 동영상을 인덱싱하기 위해 비디오 제목, 태그, 설명을 메타데이터로 사용한다.
CDN을 사용해 영상을 빠르게 스트리밍 할 수 있다. 또한 영상을 여러 화질로 인코딩해두면 사용자의 네트워크 상황에 따라 화질을 조절해 속도를 보장할 수 있다.
악의를 가진 클라이언트가 비디오를 업로드하거나, 잘못된 장소에 비디오가 업로드 되는 일을 막히 위해 미리 지정된(pre-signed) 업로드 URL을 사용한다.
책의 연구 결과에 따르면 유튜브의 비디오 스트리밍은 롱테일(long-tail) 분포를 따른다고 한다. 이를 기반으로 몇가지 최적화를 할 수 있다.
시스템 오류에는 2가지 종류가 있다. 회복 가능 오류(recoverable error)와 회복 불가능 오류(non-recoverable error)다. 스트리밍 시스템에서 각각의 예시는 다음과 같다.
회복 가능 오류는 몇 번 재시도 해보고 끝까지 안 되면 클라이언트에게 오류 코드를 반환하하고, 회복 불가능 오류는 곧바로 작업을 중단하고 오류 코드를 반환하면 된다.
각 서버별 장애를 막기 위해서 다음과 같은 조치를 할 수 있다.