pile·
아키텍처·카카오 엔터테인먼트 FE카카오 엔터테인먼트 FE·

우당탕탕~ 영상 서비스 개발기 1탄 : 영상 CMS

카카오엔터테인먼트가 버추얼 걸그룹 서바이벌 소녀 리버스의 영상 서비스를 9개월간 만들며 영상 CMS 인 VODKA 를 구축한 기록이다. 프론트 Admin 프레임워크를 네 후보에서 Refine 으로 좁힌 과정, Apigee 로 인증을 한곳에 모은 구조, Tus 프로토콜 기반 대용량 업로드 서버를 만들며 겪은 성능 문제를 순서대로 다룬다.

핵심 포인트
  • 설계가 문서화되지 않은 시기라 DDD 의 이벤트 스토밍 워크숍을 이틀간 진행해 서브도메인과 제약사항, 소프트웨어 모델을 뽑아냈다.
  • Admin 프레임워크 후보는 React Admin, Refine, Retool, AdminJS 넷이었고 Refine 을 골랐다. React Admin 은 사용법이 엄격하고 opinionated 한 반면 Refine 은 커스텀 UI 자유도가 높아서다.
  • Retool 은 화면을 드래그로 그리는 속도가 특출났지만 직접 개발이 제한되고, 당시 셀프 호스팅이 엔터프라이즈 전용이라 검토 시간과 가격 문제로 포기했다.
  • 인증과 권한 처리를 한곳에 모으려고 GCP 의 Apigee 를 API Gateway 로 두고 Shared Flows 로 OKTA 기반 인증을 붙였다.
  • 대용량 업로드는 Tus 프로토콜로 구현했다. HTTP 기반이라 브라우저에서 바로 쓸 수 있고 청크 전송과 이어올리기를 지원한다.
상세 정리
  • 프레임워크 선정 기준은 React 기반일 것, 운영에 필요한 UI 컴포넌트 내장, 데이터 연동 자동화, 사용자 수, 문서와 예제, 커스텀 UI 자유도, 유료 지원, GraphQL 지원이었다. GraphQL 은 결국 쓰지 않았다.
  • React 를 조건에 넣은 이유는 사내 프론트 개발자 다수가 React 를 써서 막혔을 때 조언을 구할 수 있기 때문이다.
  • Refine 은 App 최상단을 Refine 컴포넌트로 감싸는 것으로 준비가 끝난다. 연동 로직은 Provider 형태로 제공돼 기본 Provider 의 함수를 오버라이드해 커스텀한다.
  • Resource 는 메뉴가 담당하는 개념 단위로 DB 한 테이블의 모델과 비슷하다. Resource 를 지정하면 사이드바 메뉴와 라우팅, 화면별 API 연결이 자동으로 만들어지고, CRUD 가 아닌 화면은 routes 를 직접 추가한다.
  • 화면은 List, Create, Edit, Show 기본 컴포넌트와 refine-antd 의 Ant Design 컴포넌트로 구성했고 그 하위는 평범한 리액트 컴포넌트로 개발했다. 파일 업로드 컴포넌트는 기존 것으로 어려워 직접 만들며 자유도의 이점을 체감했다.
  • Refine 의 아쉬운 점 둘을 적는다. CRUD 가 아닌 API 호출에는 Hook 이 제한적이라 개발 기간이 넉넉하면 연동 함수를 직접 만드는 편이 나을 수 있고, 버전업이 잦은데 문서에 버저닝이 없어 GitHub Release 탭에서 변경사항을 하나씩 확인해야 했다.
  • Tus 를 고른 이유는 스토리지 벤더가 주는 클라이언트가 플랫폼 종속적이고 설치가 필요한 경우가 많아서다. GCS 든 NFS 든 단일 진입점으로 쓸 수 있다.
  • 초기에는 서비스 백엔드가 업로드를 받아 Tus 로 넘겼는데 그만큼 시간이 더 걸리고 요청 버퍼 때문에 메모리 문제도 생겼다. 전처리 후 Signed URL 을 발급해 프론트엔드와 Tus 가 직접 통신하도록 바꿨고, 이미 인증된 URL 이라 TTL 을 필수로 걸었다.
  • 디스크에 쓴 뒤 GCS 로 옮기면 저장소가 추가로 필요하고 업로드 시간이 두 배가 돼, 오브젝트 스토리지에 바로 저장하도록 개선했다.
  • 동시 업로드 충돌을 막는 lock 이 필수인데 파일시스템 기반 lock 은 서버가 여러 대인 분산 환경에서 쓸 수 없다. Redis 의 SETNX 로 분산 lock 을 구현하고 잠금 해제 실패나 교착 상태 대비로 TTL 을 걸었다. 클러스터로 가면 redlock 으로 개선할 계획이다.
  • 런타임은 업로드가 특정 시간대에 몰리는 작업이라 처음에 GCP Cloud Run 을 골랐고, 가볍고 cold start 가 짧은 golang 을 채택했다.
  • 그런데 Cloud Run 은 HTTP/1 요청 크기가 32MB 로 제한된다. 청크가 작을수록 lock 잠금과 해제, HTTP 요청 응답 지연이 반복돼 업로드가 길어지고, 원본 영상은 수백 개 청크가 생겨 병합 후처리가 부담이 됐다.
  • HTTP/2 에서는 제한이 없지만 golang fiber 의 core 인 fasthttp 가 http/2 를 지원하지 않아, 요청 크기를 늘릴 수 있는 GKE 로 옮기는 쪽을 택했다.
  • 스트리밍 업로드를 위해 fiber 는 StreamRequestBody 옵션을 켜고, Kubernetes Ingress 에서는 nginx 의 proxy-request-buffering 어노테이션을 off 로 둬야 한다.
  • 초기에는 사내 VPN 으로만 접근 가능한 internal ingress 로 노출했는데 대용량 업로드가 너무 느렸다. 상대 속도가 internal SSL 1, internal 비SSL 4, external SSL 10 수준이었고 VPN 터널링 지연이 원인이라 판단해 external ingress 로 바꾸고 Cloud Armor 로 접근을 제어했다.
  • 마지막 병합도 병목이었다. GCS 의 compose 는 한 번에 청크 32개만 다룰 수 있어 수백 개면 수 분 이상 걸리고, 공개 코드는 업로드마다 GCS 에서 object 정보를 읽어와 청크가 늘수록 느려졌다. 병합을 병렬화하고 청크 정보를 Redis 에 캐싱해 해결했다.
  • 남은 과제로 관리자가 업로드를 즉시 중단하는 기능, 업로드 현황 대시보드, 클라이언트와 Tus 서버만 아는 진행 상황을 CMS 백엔드에 이벤트로 알리는 기능을 꼽는다.
왜 읽나영상처럼 큰 파일을 다루는 운영툴과 업로드 서버를 처음 설계하는 팀에게 프레임워크 선정 기준부터 클라우드 런타임 제약까지 부딪힌 순서 그대로 보여주는 개발기.
카카오 엔터테인먼트 FE
카카오 엔터테인먼트 FE 블로그
원문은 여기서 이어서 읽을 수 있어요
원문 읽기
읽음 (0)

이 글과 비슷한

  1. 아키텍처·aws-architectureAWS Architecture·

    일관성이 새로운 지연이다: 데이터 레이어에서의 AI

    AI 에이전트가 데이터베이스 레이어에서 겪는 데이터 정합성 문제를 다룬다. 비동기 복제 지연(replication lag)으로 stale 데이터를 읽은 에이전트가 잘못된 판단을 내리는 "조용한 독"을 AWS 서비스 기반 세 가지 아키텍처 패턴으로 해결하는 방법을 제시한다. "빠르지만 틀린 답이 약간 느리지만 맞는 답보다 비싸다"는 주장 아래, 데이터베이스 아키텍처를 AI 신뢰성의 기반으로 재정의한다.

    요약 이어보기
    #ai-agent#data-consistency#aurora+2
  2. 아키텍처·flexflex·

    사람도 에이전트도, 덜 읽을수록 더 잘 고칩니다

    flex 팀이 코드베이스의 모듈 경계 설계가 AI 에이전트의 코드 탐색 효율에 미치는 영향을 실측한 글이다. 193개 에이전트 작업 로그를 분석하고, 잘 나뉜 모듈과 뭉친 모듈을 비교한 결과 — 도메인이 물리 모듈로 분리된 저장소에서 에이전트가 불필요한 파일을 덜 읽고 목표 코드에 더 집중했다. 사람도 에이전트도 컨텍스트 한도가 있어, 무관 코드를 덜 읽을수록 수리 성공률이 높다는 것이 핵심 결론이다.

    요약 이어보기
    #llm-agent#context-window#modular-architecture+1
  3. 아키텍처·aws-architectureAWS Architecture·

    데이터 거주 요건을 충족하는 재해 복구 전략

    데이터 거주(data residency) 규정을 지키면서 재해 복구(DR)를 구현해야 하는 조직을 위해 AWS가 세 가지 전략 프레임워크를 제시한다. 금융, 의료, 공공 부문처럼 지리적 데이터 보관 의무가 있는 환경에서도 복구 목표(RTO/RPO)를 달성할 수 있는 아키텍처 선택지를 비교한다.

    요약 이어보기
    #multi-cloud#compliance#disaster-recovery+2