728x90

1. 개요

웹 애플리케이션 개발에서 대용량 데이터를 처리하는 것은 중요한 과제 중 하나다.

특히 클라이언트가 요청한 데이터를 한 번에 모두 제공하기 어려운 경우, 스트리밍 방식으로 점진적으로 전송하는 것이 효율적이다.

Spring에서는 이러한 요구를 충족하기 위해 StreamingResponseBody를 제공한다.


2. StreamingResponseBody란?

StreamingResponseBody는 Spring MVC에서 제공하는 인터페이스로,

HTTP 응답을 스트리밍 방식으로 처리할 때 사용된다.

 

이는 클라이언트가 데이터를 한 번에 모두 받는 것이 아니라,

서버가 데이터를 점진적으로 생성하여 전송할 수 있도록 돕는다.

 

  • 주요 특징
    • 비동기 데이터 전송: 데이터를 한 번에 모두 보내지 않고, 필요할 때마다 생성하여 전송할 수 있다.
    • 메모리 효율성: 전체 데이터를 메모리에 적재하지 않고 스트리밍 방식으로 처리할 수 있어 메모리 사용량을 줄일 수 있다.
    • 실시간 처리 가능: 파일 다운로드, 로그 스트리밍, IoT 데이터 송수신 등의 실시간 처리 작업에서 활용할 수 있다.

3. API 구현 예제

  1. 클라이언트가 /stream/data 엔드포인트에 요청을 보낸다.
  2. 서버는 StreamingResponseBody를 사용하여 데이터를 스트리밍 방식으로 전송한다.
  3. outputStream.write()를 사용하여 데이터를 부분적으로 클라이언트에게 전송하고 flush()를 호출하여 즉시 응답을 보낸다.
  4. 클라이언트는 1초마다 한 번씩 데이터를 받아 화면에 출력할 수 있다.
  5. 10개의 데이터가 전송된 후 스트리밍이 종료된다.
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;

import java.io.IOException;
import java.io.OutputStream;
import java.util.stream.IntStream;

@RestController
@RequestMapping("/stream")
public class StreamingController {

    @GetMapping("/data")
    public ResponseEntity<StreamingResponseBody> streamData() {
        StreamingResponseBody responseBody = outputStream -> {
            for (int i = 1; i <= 10; i++) {
                String data = "Chunk " + i + "\n";
                outputStream.write(data.getBytes());
                outputStream.flush(); // 즉시 클라이언트로 전송
                Thread.sleep(1000); // 1초 대기 후 다음 데이터 전송
            }
        };

        return ResponseEntity.ok()
                .header("Content-Type", "text/plain")
                .body(responseBody);
    }
}

4. Front 구현 예제

fetch()를 활용하여 데이터를 받아 처리할 수 있다.

async function fetchStreamData() {
    const response = await fetch('http://localhost:8080/stream/data');
    const reader = response.body.getReader();
    const decoder = new TextDecoder();
    
    while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        
        const chunk = decoder.decode(value, { stream: true });
        console.log("Received chunk:", chunk);
        document.getElementById('output').innerText += chunk;
    }
}

5. StreamingResponseBody가 유용한 경우

  • 대용량 파일 다운로드: 한 번에 모든 파일을 로드하지 않고, 스트리밍 방식으로 다운로드
  • 실시간 로그 스트리밍: 서버 로그를 실시간으로 클라이언트에 제공할 때 사용
  • IoT 데이터 스트리밍: 센서 데이터와 같은 실시간 데이터를 주고받을 때 적합
  • 비동기 처리 성능 개선: 서버에서 무거운 작업을 수행하면서 클라이언트에 점진적으로 데이터를 제공

StreamingResponseBody는 Java 8 이상 환경에서 사용할 수 있다.

대용량 데이터 전송과 실시간 데이터 스트리밍을 위한 강력한 도구다.

기존의 ResponseBodyResponseEntity와 비교했을 때, 보다 효율적으로 메모리를 사용할 수 있으며,

실시간 데이터 전송이 필요한 상황에서 유용하게 활용 가능!

728x90
복사했습니다!