개요
이전 포스팅에서 HLS 단일 화질 송출 환경을 구축했다면, 본 포스팅에서는 가변 네트워크 대역폭에 대응하기 위한
ABR(Adaptive Bitrate) 기술 적용과 이를 제어하는 Java 기반 Control Plane 설계 과정을 다룹니다.
특히 다중 트랜스코딩 시 발생하는 리소스 경합 문제와 외부 프로세스 제어의 안정성 확보를 중점으로 기록합니다.
[ABR(Adaptive Bitrate) 설계 및 최적화]
시청자의 네트워크 상태에 따라 1080p, 720p, 480p 화질을 동적으로 전환하기 위해서는
각 해상도별 세그먼트의 키프레임 위치(GOP)가 물리적으로 일치해야 합니다.
FFmpeg 트랜스코딩 최적화 과정 및 트러블슈팅
스트림 매핑 및 인덱스 충돌 (Elementary Stream Conflict)
- 현상: 단일 오디오 소스를 복수의 비디오 스트림에 매핑 시 Same elementary stream found... 에러 발생 및 프로세스 중단.
- 원인: HLS Variant Stream 구성 시 동일한 오디오 스트림 인덱스(a:0)를 중복 참조할 경우, 하위 뮤서(Muxer)에서 리소스 점유 충돌이 발생함.
- 대처: asplit 필터를 사용하여 오디오 스트림을 물리적으로 복제([a1][a2][a3])한 뒤, var_stream_map을 통해 각 해상도 스트림에 독립적인 오디오 인덱스를 할당하여 해결.
파이프라인 효율화 (Resource Optimization)
- 현상: 각 해상도별로 독립적인 FFmpeg 인스턴스를 실행할 경우 CPU 점유율 및 I/O 부하 급증.
- 원인: 원본 소스 디코딩이 중복 발생하며 발생하는 리소스 낭비.
- 대처: -filter_complex 내에서 split 필터를 적용. 단일 디코딩 파이프라인에서 메모리 상의 데이터를 분기하여 멀티 해상도로 인코딩하는 구조로 전환, 연산 효율성 극대화.
[Java Control Plane: 프로세스 수명 주기 관리]
Spring Boot 서버는 FFmpeg 프로세스의 실행뿐만 아니라 상태 모니터링 및 자원 회수를 담당하는 오케스트레이터 역할을 수행합니다.
외부 프로세스 제어 시 고려사항
중복 실행 방지 및 원자성 확보
- 현상: 동시 다발적인 API 요청 시 중복된 FFmpeg 프로세스 생성으로 인한 시스템 패닉.
- 대처: AtomicReference와 synchronized 키워드를 활용하여 송출 상태를 추상화(IDLE, STREAMING, ERROR). 프로세스 실행 전 상태 검증 로직을 배치하여 원자적 실행 보장.
비동기 상태 감시 및 좀비 프로세스 방지
- 현상: 상위 프로세스(Java) 종료 후에도 하위 프로세스(FFmpeg)가 잔존하여 시스템 자원을 지속 점유.
- 대처: * Process.onExit(): 비동기 콜백을 등록하여 프로세스 종료 코드(Exit Code)를 실시간 모니터링하고 상태값 갱신.
- @PreDestroy: 컨테이너 종료 시그널 수신 시 Process.destroy() 및 waitFor를 호출하여 안전한 프로세스 종료(Graceful Shutdown) 보장.
[구현 결과 및 검증]
- ABR 전환 테스트: Chrome Network Throttling을 통해 대역폭 제한 시 master.m3u8 지표에 따라 Chunk 요청 경로가 하위 해상도 폴더로 즉각 전환됨을 확인.
- 안정성: 수차례의 반복 요청 및 강제 프로세스 종료 테스트에서도 자바 서버가 상태를 정확히 복구하며, 시스템 자원 누수 없이 안정적으로 동작함.
[결론]
실시간 미디어 서비스에서 백엔드의 역할은 단순히 데이터를 중계하는 것에 그치지 않습니다. 외부 프로세스의 생명 주기를 정밀하게 제어하고, 가용 자원 내에서 최적의 파이프라인을 설계하는 Resource Management 능력도 중요함을 확인했습니다.
향후에는 송출된 데이터를 기반으로 VOD 자산을 자동 생성하는 워크플로우, 채팅창과의 싱크 등 생각 나는 기능들을 차근차근히 붙여 나갈 예정입니다.