DevOps

[AWS/나만의무기]아키텍쳐 변경: S3와 Cloudfront(CDN)를 이용한 서버리스 온디맨드 스트리밍 설계

Woonys 2022. 2. 25. 21:27
반응형

휴..오늘 또 한 건 했다.

 

0. Executive Summary

  • 온디맨드 스트리밍은 스트리머가 방송한 라이브 스트리밍 전체 영상을 저장해 시청자가 '지나간 라이브'(playback) 방송을 보고 싶을 때 언제든 시청할 수 있는(on-demand) 시스템을 말한다.
  • 기존 오픈소스에서 제공하는 playback 기능은 미디어 서버 내 스토리지에 지나간 영상을 저장해뒀다가, 클라이언트로부터 요청이 들어오면 RTMP 프로토콜을 통해 node-media-client에서 제공하는 <NodePlayerView> 컴포넌트로 재생하는 방식이었다.  여기에는 두 가지 문제가 있었다.
    1. feature의 한계: node-media-client가 제공하는 기능은 지나간 영상을 재생만 할 수 있다. 지나간 영상을 재생/정지/특정 구간 재생 등 다양한 feature를 넣는 기능을 제공하지 않아 다른 컴포넌트로 변경해야 했다.
    2. 미디어 서버의 부하 문제: 현재는 라이브 스트리밍(실시간 라이브)과 온디맨드 스트리밍(지나간 라이브)를 모두 EC2 내 미디어 서버에서 처리하고 있었다. 그러다 보니 EC2 프리 티어로 이를 버티는데 한계가 많이 발생했다.(특히 메모리 문제)
  • 클라이언트에서 미디어 플레이어 기능을 추가함과 동시에 서버 단의 부하를 줄이기 위해 S3와 cloudfront 배포를 이용해 서버리스 온디맨드 스트리밍 아키텍쳐를 구현했고 성공적으로 동작함을 확인했다. 

 

 

 

 

1. Current Status & Problem

 

본 프로젝트에서 기획하는 라이브 커머스 서비스의 특징은 라이브 스트리밍과 온디맨드 스트리밍을 함께 제공한다는 점이다. 여기서 라이브 스트리밍은 말 그대로 실시간 방송을 의미한다. 한편, 온디맨드 스트리밍은 라이브 스트리밍과 약간 다른데, 저장된 영상을 시청자가 보고 싶다면 언제든 스트리밍으로 볼 수 있는 형태를 뜻한다. 라이브 스트리밍 서비스에서의 온디맨드 스트리밍은 지나간 라이브 스트리밍 영상을 저장해두고 시청자가 과거 방송을 언제든 볼 수 있는 형태로 제공한다고 보면 되겠다.

 

두 서비스를 제공해주기 위해서는 어떤 아키텍쳐를 설계해야 하는지 살펴보자. 예시로 AWS를 들겠다. (해당 글을 참고함)

 

 

온디맨드 스트리밍: 원본 => S3 스토리지 저장 => 트랜스 코딩, HLS 변환 => CDN(Contents Distribution Network) => 사용자

 

AWS 서비스를 이용한 온디맨드 스트리밍 아키텍쳐

(AWS 설명 링크)

 

먼저 원본 영상을 온라인 스토리지 상에 업로드해둔다. 여기서 시청자가 접속해 해당 영상을 시청하겠다는 요청을 하면 이를 AWS Lambda가 감지한다.

 

Lambda는 mediaConvert가 해당 영상을 HLS 형식으로 변환하도록 트랜스코딩을 시킨다. 그러면 인덱스 파일인 .m3u8과 영상을 특정 시간(보통 1~10초 사이)으로 자른 청크 파일인 .ts가 다시 S3로 저장된다. 우리 아키텍쳐에서는 람다 -> mediaConvert 트랜스코딩 파트를 EC2 내에 있는 미디어 서버가 수행한다.

 

S3는 중간에 CDN(Contents Distribution Network)을 끼고서 사용자에게 영상을 전송한다. CDN은 일종의 영상 전송에 대한 캐시라고 보면 되는데, S3에서 다이렉트로 사용자에게 영상을 꽂아주면 두 가지 문제가 생긴다. 하나는 수많은 사용자에 대해 S3 혼자 요청을 감당해야 하다보니 부하가 걸린다는 점, 둘째는 만약 지구 반대편의 시청자가 한국에 위치한 S3로부터 영상을 요청할 경우 전송하는데 드는 비용이 크다는 점(시간적 자원, 금전적 자원 모두).

 

CDN은 이 문제를 해결한다. S3는 지구 곳곳에 퍼져 있는 CDN에 영상을 송출해준다. 그러면 CDN은 해당 영상을 저장해둔다. 그러다 어떤 사용자가 영상을 요청하면 S3에서 보내는 것이 아닌 사용자로부터 가장 가까운 지역에 있는 CDN이 대신 영상을 전송해준다. 이렇게 되면 S3가 모든 사용자에 대한 요청을 수행하는 게 아니라 흩어져있는 CDN이 대신 처리해주니 부하가 줄어들 뿐더러 거리에 대한 비용이 줄어든다는 이점이 생긴다.

 

 

라이브 스트리밍: 원본 => 인코딩 => 미디어 서버(트랜스 코딩, HLS 변환) => CDN => 사용자

 

AWS 서비스를 이용한 라이브 스트리밍 아키텍쳐

라이브 스트리밍은 약간 다르다. 원본 영상을 송출하면 이를 클라이언트 단에서 실시간으로 인코딩해 미디어 서버로 전송한다. 우리의 경우는 스트리머 -> 미디어 서버로 송출하는 단계에서 RTMP 프로토콜을 사용하기에 클라이언트 단에서 RTMP 프로토콜에 맞게 인코딩해 EC2 서버로 영상을 전송한다.

 

미디어 서버에서는 스트리머로부터 받은 영상을 트랜스코딩해 HLS 형식으로 변환한다. 이후에 CDN을 이용해 사용자로 송출해준다. (우리 아키텍쳐에서는 라이브 스트리밍에 CDN이 현재 적용되어 있지 않은 상황)

 

 

Problem: 미디어 서버에 트래픽이 편중되어 있는 아키텍쳐 & 제한된 플레이어 기능

 

여기서 문제를 살펴보자. 현재 우리가 사용하고 있는 서버는 node-media-server를 기반으로 만든 오픈소스를 포크해서 커스터마이징해 쓰고 있다. 기존 오픈소스에서 제공하는 playback(온디맨드 스트리밍) 기능은 미디어 서버 내 스토리지에 지나간 영상을 저장해뒀다가, 클라이언트로부터 요청이 들어오면 RTMP 프로토콜을 통해 node-media-client에서 제공하는 <NodePlayerView> 컴포넌트로 재생하는 방식이었다. 여기에는 두 가지 문제가 있었다.

 

1. 플레이어 feature의 한계: 기존 오픈소스에서는 클라이언트 단에서 미디어 서버로부터 영상을 받아와 재생해주는 컴포넌트로 node-media-client를 사용하고 있었다.  그런데 이 컴포넌트는 오직 영상을 autoplay하는 기능만 있으며 재생/정지/특정 구간 재생 등 다양한 feature를 넣는 기능을 제공하지 않아 이를 제공하는 다른 컴포넌트로 변경해야 했다. 그런데 여기서 바로 아래 문제와 연결되는 바람에 새로운 플레이어 컴포넌트를 적용할 수 없었다.

2. 노후화된 스트리밍 프로토콜(RTMP): RTMP 프로토콜은 어도비 플래시 기반으로 구성되어 있는 프로토콜이다. 그 특성상 스트리머에서 -> 미디어 서버로 송출하는데는 최적화되어 있기에 지금까지도 계속 사용하고 있지만 스트리밍된 영상을 받는 입장에서는 얘기가 달라진다. RTMP 프로토콜로 받아오는 영상을 틀기 위해서는 해당 네트워크 프로토콜을 지원하는 플레이어가 있어야 하는데, 기존에 사용하던 node-media-client 이외에 다양한 기능을 제공하는 비디오 플레이어 컴포넌트에서는 rtmp를 지원하지 않았던 것. 애초에 요즘은 미디어 서버 -> 시청자 간 영상 전송 방식으로 HLS가 거의 표준화된(아래 이미지 참조) 상황이라 그런듯. 

 

&lt;스트리밍 프로토콜 점유율&gt;,&nbsp;https://www.wowza.com/blog/2021-video-streaming-latency-report

 

3. 미디어 서버의 부하 문제: 현재는 라이브 스트리밍(실시간 라이브)과 온디맨드 스트리밍(지나간 라이브)를 모두 EC2 내 미디어 서버에서 처리하고 있었다. 그러다 보니 EC2 프리 티어로 이를 버티는데 한계가 많이 발생했다. 특히 메모리 문제가 심각했는데, 프리 티어에서 제공하는 메모리는 1GB밖에 안 됐기 때문.. 이미 기본적으로 차지하고 있는 메모리 용량이 꽤나 됐던 게 컸다. 아래 이미지를 보자.

 

1) EC2 서버에 2명 접속한 상태(스트리밍 X): 100MB free(...)

 

아무 것도 안하고 2명 접속만 한 상황에서 free인 메모리가 겨우 100MB 남짓 남아있다.


2) EC2 서버에 3명 접속한 상태(스트리밍 X): 79 MB free

 

3명 접속 중인 상황(방송 켜지 X)

 

3) EC2 서버에 3명 접속한 상태(한 명 스트리밍 & 2명 시청): 75 MB free

 

3명 접속 중 (한 명 스트리밍 &amp; 2명 시청)

 

 

확실히 메모리는 부족한 상황. CPU도 많이 딸리는 것을 볼 수 있다. 모두 스트리밍 과정에서 인코딩하느라 CPU 사용률이 100에 달한 상황이 발생했다.

 

 

 

이를 해결하기 위해 일차적으로 메모리 스왑 공간을 생성해 해결하긴 했지만 스트리밍 서비스인지라 단순히 스왑만으로는 부하를 견디기 힘들 것으로 판단했다. 

 

2. Solution: S3 - 클라이언트 사이에 CDN 적용 & 새로운 오픈소스 비디오 플레이어 컴포넌트 적용

 

이를 해결하기 위해 먼저 온디맨드 스트리밍 아키텍쳐부터 손보기로 했다.

 

먼저, 서버 단의 부하를 줄이기 위해 S3와 cloudfront 배포를 이용해 서버리스 온디맨드 스트리밍 아키텍쳐를 구현했다. 아래 링크를 참고해 기존 S3와 cloudfront를 연결했다. 많은 글을 찾아봤는데 가장 도움이 많이 됐던 글.

 

 

자습서: Amazon S3, Amazon CloudFront 및 Amazon Route 53로 온디맨드 스트리밍 비디오 호스팅 - Amazon Simple Sto

도메인을 등록하면 즉시 비용이 청구되며, 이는 취소할 수 없습니다. 도메인을 자동 갱신하지 않도록 선택할 수 있지만, 선불로 비용을 지불하며 1년 동안 소유합니다. 자세한 내용은 Amazon Route 5

docs.aws.amazon.com

 

 

[AWS] CloudFront와 S3 연결하기

들어가기 전에 기존에 SpringBoot를 이용한 S3에 이미지 업로드 및 삭제에 대해 포스팅한 적이 있습니다. [SpringBoot] SpringBoot를 이용한 AWS S3에 여러 파일 업로드 및 삭제 구현하기 해당 포스팅을 할

earth-95.tistory.com

 

CloudFront는 HLS 방식만을 제공하기에 기존의 RTMP를 사용하지 않아도 되었다. 자연스럽게 기존의 node-media-client가 아닌 새로운 비디오 컨트롤러 컴포넌트를 적용할 수 있었다.

 

 

react-native-video-controls

A set of GUI controls for the react-native-video component. Latest version: 2.8.1, last published: 10 months ago. Start using react-native-video-controls in your project by running `npm i react-native-video-controls`. There are 9 other projects in the npm

www.npmjs.com

 

결과는 대성공!

 

클라이언트에서 서버로 요청하지 않고 곧바로 CloudFront에 영상을 요청하는 로직으로 변경하였다. 이제는 서버에 접근하지 않고 곧바로 S3 -> CloudFront -> 클라이언트로 HLS 방식으로 영상이 꽂히는 것을 확인했다. HLS 방식이 적용되었기에 새로운 컴포넌트로 역시 잘 작동하는 것을 확인!

 

사용자 추가 접속에 따른 메모리 부하 테스트는 아직 진행하지 못함. 얼른 측정해봐야겠다.

 

결과적으로 아래 이미지와 같이 아키텍쳐가 변경되었다.

반응형