ToyProject

[Catarie] 영상 소셜 네트워크 프로젝트 - 1. 기획과 설계

sihanni 2025. 8. 25. 18:37

시작

영상이나 음원 데이터 처리에 대한 서비스를 개발해보면 재밌을 것 같았고, 관련 기술의 숙련도를 올리고 싶어서 시작하게 된 프로젝트이다.

서비스 이름의 아이디어는 폭포에서 시작되었다. 영상이나 음원 데이터는 기본적으로 버퍼 -> 패킷화 -> 스트리밍의 기술적인 과정을 거치는 것이 물방울 들이 모여서 떨어져 폭포를 이루는 것이 연상되기도하고, 폭포에서 떨어진 물이 한 곳에 모이는 것 처럼 모든 음원과 영상이 한 곳으로 모이길 바라는 마음이었다. 그리고 개인적으로 프랑스를 좋아해서 찾아보니 프랑스에서 가장 큰 폭포가 gavarnie라고 해서 서비스의 이름은 Gavarnie가 되었다.

 

Buffer, Packet, Stream

영상, 음원을 다루려면 이 세가지를 잘 알아야하는데, 여태까지 음원이나 영상 데이터를 많이 취급해본적이 없다보니 확실히 이 개념들에 대한 이해도가 낮았다. 본격적인 기획과 설계에 앞서서 우선 간단하게 개념을 짚고 넘어가보기로 했다.

 

Buffer

버퍼는 데이터를 잠시 쌓아두는 임시 저장 공간이라고 보면되는데, 네트워크 속도나 처리 속도가 달라 생기는 빈틈을 메워서 끊김 없는 재생을 가능케 한다. (유튜브 영상이 멈추고 버퍼링 중이면, 충분한 데이터를 쌓고 있는 과정인 것이다)

Packet

네트워크에서 데이터를 전송하기 위해 잘게 쪼갠 조각 단위이다. 큰 데이터를 여러 패킷으로 나눠 전송하고, 수신 측에서는 다시 조립해서 원래의 영상이나 음원으로 복원시키는 것이다. (1GB 짜리 영상을 TCP/IP로 전송할 때 수만 개의 작은 패킷으로 나눠 보내는 과정)

Stream

패킷들을 순서대로 이어붙여서 연속적인 데이터 흐름으로 처리하는 방식이다. 사용자가 데이터를 한 덩어리 파일로 기다리지 않고, 도착하는 대로 실시간에 가깝게 재생할 수 있도록 한다. (Netflix, Spotify, Twitch 같은 서비스에서 실시간 또는 점진적으로 영상·음원이 재생되는 원리)

 

정리하자면 서버에 저장된 영상이나 음원을 끊김 없이 재생하기 위해, 큰 파일을 패킷으로 쪼개서 전송하고, 수많은 패킷은 인터넷을 통해 클라이언트로 이동되고, 그 패킷을 모아 버퍼에 저장하고 충분히 쌓이면 재생을 시작하고, 버퍼에서 연속적으로 데이터를 꺼내 디코딩 후 영상, 음원을 출력하게 되는 흐름인 것이다.

 

기획과 설계

목표

음원, 영상 바이너리 데이터의 업로드 처리, 스트리밍 전 과정에 대한 이해와 숙련도 향상

 

MVP(Minimum Viable Product)

인증

  • 이메일/비밀번호, JWT 기반

업로드

  • 영상≤120초, 음원≤60초. 입력 지원 포맷: mp4, mov, webm, mp3, wav, m4a (추가 가능). 파일 크기 제한(예: 200MB) 

처리 파이프 라인 

  • 영상: 1080×1920 / 720×1280 H.264 + AAC, HLS(m3u8 + TS/ fMP4), 2초 세그먼트, 키프레임 정렬.
  • 음원: AAC 128–192kbps, 오디오 전용 HLS. (MVP에선 간단한 커버 이미지/파형 미리보기 선택)
  • 썸네일: 1~3장(중간, 시작, 임의 프레임) + 포스터(세로형 9:16 고정).

피드/ 플레이어

  • 한 화면에 1개 재생, 다음 콘텐츠 프리 로드

오버레이 UI

  • 프로필, 닉네임, 영상 기본 정보 좌 하단 위치

반응

  • 좋아요, 싫어요, 댓글(CRUD, 대댓글, 댓글 좋아요 싫어오)

공유

  • 퍼머링크, 클립보드 복사

저작권

  • 실제 저작권 검증은 실제 저작권 검증 서비스를 사용하게 되어 검증하면 비용이 많이 발생하므로, 업로드시 저작권에 대한 사용자 책임을 고지

확장 작업

  • 검색 기능
  • 추천 알고리즘
  • 모니터링과 통계
  • 신고, 차단

시스템 아키텍처

  • 웹앱(React/Next.js)API Gateway(NestJS)MongoDB(문서 저장) / Redis(캐시·카운터·레이트리밋) / MinIO or S3(오브젝트 스토리지)
  • Transcode 워커(BullMQ + Redis 큐): FFmpeg 컨테이너.
  • 정적/HLS 서빙: Nginx(+ 로컬: MinIO 정적), 배포 시 CDN(CloudFront 등).

미디어 파이프라인 (1차안)

  • 클라이언트 업로드 준비: API가 사전 서명 URL(S3/MinIO) 발급.
  • 직접 업로드: 클라이언트가 오브젝트 스토리지에 업로드(대용량은 멀티파트 권장). 업로드 완료 콜백/확인 API 호출.
  • 메타 검사(ffprobe): 포맷/길이/코덱 확인(정책 위반 즉시 거절: 길이 초과, 금지 코덱 등).
  • 큐 투입: transcode:enqueue(입력 객체 키, 타깃 프로필)
  • FFmpeg 변환:
    • 영상 HLS: 1080p/720p, GOP≈2초, H.264 baseline/main + AAC 128kbps.
    • 음원 HLS: AAC 128–192kbps, 커버 이미지 포함(선택).
    • 썸네일: N프레임 추출(예: 00:00, 중간, -00:01)
  • 결과 배치: /media/{mediaId}/hls/{1080p,720p}/index.m3u8 등 일관된 키 스킴.
  • DB 업데이트: processing → published, 길이/비트레이트/리소스 경로 저장.
  • 전파: 피드 인덱스에 삽입, 캐시 프리로드, 웹소켓/푸시(선택) 알림.

E2E 흐름 (1차안)

  1. 업로드 준비
  • FE가 BE에 “업로드할래요” 요청 → BE가 사전 서명 URL(S3/MinIO) 발급
  • (선택) Redis에 업로드 토큰/레이트리밋 저장 (짧은 TTL)
  1. 원본 업로드 & 확정
  • FE가 스토리지에 직접 업로드 → BE에 “업로드 끝!” 확정 호출
  • BE는 media 문서(상태=processing) 생성
  • Redis(BullMQ) 큐에 transcode:enqueue 잡을 넣음
    • 작업 내용: 원본 키, 타깃 프로필(1080p/720p), 썸네일 규칙 등
  1. 미디어 처리(워커)
  • 워커가 Redis 큐에서 잡을 가져감 → 순서대로:
    1. ffprobe 검증(길이·코덱·메타)
    2. 썸네일 추출(여러 프레임)
    3. HLS 변환(1080p/720p 병렬)
    4. DB 업데이트(경로/길이/상태)
  • 단계별 실패는 재시도/백오프(예: 5s→15s→45s), 최종 실패 시 rejected
  • 성공 시 상태 published
  1. 게시 시그널
  • (선택) 상태가 published 되면 Kafka에 media.published 이벤트를 발행
    • 추천·알림·통계 서비스가 구독해서 자기 할 일을 함
    • MVP에선 이 단계 없이도 제품 작동 OK
  1. 피드 & 재생
  • FE가 피드 호출 → published 미디어 목록/메타 + HLS m3u8 URL 반환
  • 플레이어(hls.js)가 CDN/스토리지에서 m3u8과 **세그먼트(ts/fmp4)**를 순차 요청
  • 재생 중 이벤트(뷰/좋아요/싫어요/댓글)는 즉시 Redis 카운터에 반영 → 주기적으로 DB 동기화

failover

  • 워커 다운: 진행중 잡은 타임아웃 후 다시 대기 → 다른 워커가 이어받음(중복 처리 방지)
  • ffmpeg 일시 오류: 자동 재시도/백오프
  • 트래픽 폭증: 업로드 API는 빠른 접수만, 무거운 변환은 **대기열(버퍼)**에 쌓아 워커가 소화
  • 이벤트 소비자 장애(Kafka): 복구 후 오프셋부터 다시 소비(유실 방지)
  • 중복 이벤트/잡: 아이덴포턴시 키와 멱등성 체크로 안전 처리