Spring Boot · 2026-03-29

Spring Boot로 대용량 미디어 파일 스트리밍 최적화

Spring Boot 환경에서 대용량 미디어 스트리밍 성능을 개선하기 위한 아키텍처, HTTP Range 처리, 리소스 관리, 네트워크 최적화 방법과 코드 예제 모음

작성일 : 2026-03-29 ㆍ 작성자 : 관리자
post
목차

개요

대용량 미디어 전송은 서버 자원과 네트워크에 큰 부담을 준다. 본문에서는 spring boot media streaming 관점에서 효율적으로 파일을 전달하는 방법을 정리한다. 초보자도 이해할 수 있도록 HTTP Range와 서버 측 처리 흐름을 단계별로 설명한다.

핵심 개념 정리

HTTP Range와 부분 응답

클라이언트가 특정 바이트 범위만 요청하면 서버는 206 Partial Content로 응답한다. 이 과정은 seek, 재생 시작점 변경, 일정 구간만 전송할 때 유리하다. range 요청 spring boot 구현은 이 동작을 정확히 지원해야 한다.

스트리밍 모델 선택

  • 서블릿(Blocking) 기반: 기존 Spring MVC로 구현. 간단하지만 스레드 수에 민감.
  • 리액티브(Non-blocking) 기반: Spring WebFlux. 많은 동시 연결에 유리.

설계 원칙

  • 파일을 한 번에 메모리에 올리지 않는다. 스트리밍으로 전송한다.
  • Range 요청을 정확히 처리해 클라이언트 재생을 지원한다.
  • 헤더로 캐싱과 콘텐츠 길이를 명확히 전달한다.
  • 서버 자원(스레드, I/O)을 병목 없이 사용하도록 구성한다.

Spring Boot 구현 전략

1) Range 파싱과 응답 생성

요청 헤더의 Range 값을 파싱해 시작·끝 바이트를 결정한다. 이때 유효성 검사를 엄격히 한다. 잘못된 범위는 416 Range Not Satisfiable를 반환한다. 정상 범위면 Content-Range, Accept-Ranges, Content-Length 등을 설정하고 206으로 응답한다.

2) 스트리밍 전송 코드 예시 (Spring MVC)

import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class StreamController {

  @GetMapping("/media")
  public ResponseEntity<InputStreamResource> stream(
      @RequestParam("path") String path,
      @RequestHeader(value = "Range", required = false) String rangeHeader) throws IOException {

    File file = new File(path);
    long fileLength = file.length();
    long start = 0;
    long end = fileLength - 1;

    if (rangeHeader != null && rangeHeader.startsWith("bytes=")) {
      String[] ranges = rangeHeader.substring(6).split("-");
      start = Long.parseLong(ranges[0]);
      if (ranges.length > 1 && !ranges[1].isEmpty()) {
        end = Long.parseLong(ranges[1]);
      }
      if (start > end || end >= fileLength) {
        return ResponseEntity.status(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE).build();
      }
    }

    long contentLength = end - start + 1;
    InputStream inputStream = new FileInputStream(file);
    inputStream.skip(start);
    InputStreamResource resource = new InputStreamResource(inputStream);

    HttpHeaders headers = new HttpHeaders();
    headers.add("Accept-Ranges", "bytes");
    headers.add("Content-Range", String.format("bytes %d-%d/%d", start, end, fileLength));

    return ResponseEntity.status(rangeHeader == null ? HttpStatus.OK : HttpStatus.PARTIAL_CONTENT)
        .headers(headers)
        .contentLength(contentLength)
        .contentType(MediaType.APPLICATION_OCTET_STREAM)
        .body(resource);
  }
}

3) Non-blocking 접근 (WebFlux)

많은 동시 접속이 예상되면 WebFlux로 전환을 고려한다. 파일을 ResourceRegion으로 잘라서 전송하면 효율적이다. 리액티브 스트림은 스레드를 효율적으로 사용한다.

성능 최적화 포인트

  • 버퍼 크기 조절: 너무 작으면 오버헤드가 크고, 너무 크면 메모리 사용이 증가한다. 8KB~64KB 범위에서 테스트.
  • 스레드 풀 조정: 서블릿 환경에서는 커넥션 수와 스레드 수를 맞춘다.
  • 컨텐츠 인코딩: 미디어는 일반적으로 압축 이득이 적다. 불필요한 gzip은 비활성화.
  • CDN 사용: 대역폭과 지연을 줄이는 데 효과적이다.

운영과 모니터링

로그에 요청 범위와 전송 크기를 남기고, 전송 지연과 재시도율을 모니터링한다. 메트릭을 통해 스로틀 지점과 병목을 식별한다.

요약

spring boot 파일 스트리밍 최적화는 Range 지원, 메모리 효율적 스트리밍, 적절한 아키텍처 선택이 핵심이다. 작은 설정과 코드 변경만으로도 전송 안정성과 확장성이 크게 개선된다. 추가로 CDN과 네트워크 설정을 병행하면 실사용 환경에서 더 좋은 성능을 기대할 수 있다.

spring boot media streaming spring boot 파일 스트리밍 최적화 range 요청 spring boot HTTP Range 대용량 파일 스트리밍 Spring MVC Spring WebFlux 미디어 스트리밍 최적화