[Spring] HTTP 실시간 통신

배창민·2025년 10월 31일
post-thumbnail

HTTP 실시간 통신

HTTP는 기본적으로 상태를 기억하지 않는 Stateless 프로토콜이다. 로그인 유지나 사용자 컨텍스트는 세션/쿠키 같은 별도 메커니즘이 필요하다. 실시간성은 HTTP 단독으로 한계가 있어, Polling·Long-Polling·SSE·WebSocket·STOMP 등의 기술을 상황에 맞게 조합한다.


1) HTTP의 Stateless 특성

  • 각 요청은 서로 독립적으로 처리된다.
  • 로그인/사용자 정보 유지는 세션·쿠키 등 별도 장치가 필요하다.

2) 실시간 기능의 한계

  • 클라이언트가 주기적으로 요청하지 않으면 최신 상태 반영이 늦어진다.
  • 짧은 간격의 Polling은 서버 부하를 키울 수 있다.

3) 실시간 통신 방식 개요

3-1) HTTP Polling

  • 일정 간격으로 서버에 “새 데이터 있니?”를 묻는 방식.
  • 장점: 구현 단순, 어디서나 동작.
  • 단점: 불필요 요청↑, 실시간성↓.

3-2) Long Polling (+ DeferredResult)

  • 요청을 보내고, 새 데이터가 생길 때까지 서버가 응답을 지연.
  • 데이터가 생기면 즉시 응답 → 클라이언트는 다시 요청.
  • 장점: 불필요 요청↓, 변화 즉시 반영.
  • 단점: 구현/자원 관리가 다소 복잡.

핵심 콜백(스프링 DeferredResult)

  • setResult(T), setErrorResult(Object)
  • onCompletion(Runnable), onTimeout(Runnable), onError(Consumer<Throwable>)

간단 예시:

@GetMapping("/long-poll")
public DeferredResult<String> longPoll() {
    DeferredResult<String> output = new DeferredResult<>(30_000L); // 30s timeout
    // 비동기 이벤트가 오면 setResult 호출
    someAsyncEventBus.register(result -> output.setResult(result));
    output.onTimeout(() -> output.setErrorResult("timeout"));
    return output;
}

3-3) Server-Sent Events, SSE (+ SseEmitter)

  • 서버→클라이언트 단방향 푸시. HTTP 기반, 가볍고 구현 쉬움.
  • 장점: 브라우저 호환성 좋고 단방향 알림에 최적.
  • 단점: 클라이언트→서버 전송은 별도 채널 필요.

핵심 메소드(SseEmitter)

  • send(Object), complete(), completeWithError(Throwable)
  • onTimeout(Runnable), onCompletion(Runnable)

간단 예시:

@GetMapping(value="/sse", produces="text/event-stream")
public SseEmitter sse() throws IOException {
    SseEmitter emitter = new SseEmitter(0L); // no timeout
    emitter.send(SseEmitter.event().name("init").data("connected"));
    // 이후 다른 스레드/이벤트에서 emitter.send(...) 반복
    return emitter;
}

3-4) WebSocket (+ WebSocketHandlerRegistry, WebSocketSession)

  • HTTP 업그레이드 후 양방향 지속 연결.
  • 장점: 채팅/게임/주가 등 실시간 양방향에 적합.
  • 단점: 초기 설정/연결 유지 관리 필요.

핵심 설정

  • addHandler(WebSocketHandler, paths...)
  • setAllowedOrigins(...), addInterceptors(...), withSockJS()

예시(핸들러 등록):

@Configuration
@EnableWebSocket
public class WsConfig implements WebSocketConfigurer {
  @Override
  public void registerWebSocketHandlers(WebSocketHandlerRegistry r) {
    r.addHandler(new ChatHandler(), "/ws-chat")
     .setAllowedOrigins("*")
     .withSockJS();
  }
}

세션 사용:

class ChatHandler extends TextWebSocketHandler {
  @Override
  public void handleTextMessage(WebSocketSession session, TextMessage msg) throws Exception {
    if (session.isOpen()) session.sendMessage(new TextMessage("echo: " + msg.getPayload()));
  }
}

3-5) STOMP (WebSocket 위 메시징 프로토콜)

  • pub/sub 모델 제공, 브로커 연동 쉬움.
  • 장점: 라우팅·구독·권한 등 메시징 로직을 표준화.
  • 단점: 학습 필요, WebSocket 관리 이슈 포함.

핵심 설정(WebSocketMessageBrokerConfigurer)

  • registerStompEndpoints(...) 엔드포인트 등록
  • configureMessageBroker(...) 브로커/프리픽스 설정
    예: enableSimpleBroker("/topic"), setApplicationDestinationPrefixes("/app")

예시(설정 + 메시지 전송):

@Configuration
@EnableWebSocketMessageBroker
public class StompConfig implements WebSocketMessageBrokerConfigurer {
  @Override
  public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
  }
  @Override
  public void configureMessageBroker(MessageBrokerRegistry registry) {
    registry.enableSimpleBroker("/topic");
    registry.setApplicationDestinationPrefixes("/app");
  }
}

@Controller
@RequiredArgsConstructor
class ChatController {
  private final SimpMessagingTemplate template;

  @MessageMapping("/chat/{roomId}")
  public void send(@DestinationVariable String roomId, ChatMessage msg) {
    template.convertAndSend("/topic/chat/" + roomId, msg);
  }
}

테스트 도구: https://jiangxy.github.io/websocket-debug-tool/


4) 선택 가이드 (요약 표)

기술방식장단점적합한 상황
Polling주기적 요청구현 단순·부하↑·실시간성↓간단한 갱신 확인
Long-Polling응답 지연 후 즉시 반환불필요 요청↓·자원관리 필요간헐 알림/변경 즉시 반영
SSE서버→클라이언트 푸시(단방향)가볍고 쉬움·단방향알림/피드/이벤트 스트림
WebSocket양방향 지속 연결강력한 실시간·관리 필요채팅/게임/주가/보드
STOMPWebSocket 위 pub/sub구조화·확장성↑·학습 필요다중 룸/브로커 연동/권한

5) 체크리스트

  • 단방향 알림이면 SSE, 양방향이면 WebSocket/STOMP
  • 방 개념/브로커 연동/권한 라우팅이 필요하면 STOMP
  • 간단·저빈도 갱신이면 Polling, 즉시성 필요하면 Long-Polling
  • 타임아웃/재연결/백프레셔/에러 처리 정책 포함
  • 운영 환경(프록시·로드밸런서·쿠버네티스)에서 커넥션/타임아웃 설정 검증

6) 한 줄 정리

  • HTTP는 Stateless라 실시간성이 기본 제공되지 않는다.
  • 요구사항(단/양방향, 빈도, 확장성)에 맞춰 Polling → Long-Polling → SSE → WebSocket/STOMP 순으로 고려하고, 운영 환경에서 연결 수/타임아웃/에러·재연결 전략을 반드시 함께 설계한다.
profile
개발자 희망자

0개의 댓글