[강의] 백엔드 통신 디자인 패턴

Jerry·2025년 12월 9일

실시간 통신의 개념과 필요성

실시간 통신의 진화

전통적인 HTTP 요청—응답 모델의 한계

전통적인 HTTP 요청—응답 모델은 클라이언트 요청이 있어야만 서버가 응답할 수 있어 서버의 변경 사항을 즉시 전달하기 어렵다.
변경을 확인하려면 폴링을 반복해야 하므로 네트워크와 서버 자원이 지소적으로 소모된다. 이러한 구조적 특성 때문에 실시간성을 요구하는 채팅, 알림, 모니터링 서비스에는 한계가 있다.

웹 애플리케이션의 실시간성 요구 증가

웹 애플리케이션은 채팅, 알림, 스트리밍처럼 즉각적인 반응이 필요한 기능이 크게 늘어나며 실시간성 요구가 높아지고 있다.
사용자는 페이지 새로고침 없이 변화가 바로 반영되는 자연스러운 경험을 기대한다.
이에 따라 서버는 빠른 이벤트 전송과 지속 연결을 지원하는 통신 방식이 점점 더 중요해지고 있다.

실시간 기능이 필요한 서비스 사례

서비스 유형설명예시
실시간 채팅사용자가 메시지를 입력하면 상대방에게 지연 없이 전달되어야 하는 양방향 실시간 통신 서비스카카오톡, 슬랙, 디스코드
실시간 알림(Notification)서버에서 발생한 이벤트를 즉시 사용자에게 전달하는 단방향 또는 양방향 스트리밍 서비스주문 상태 변경 알림, 새 댓글/좋아요 알림
금융 서비스(Stock/Trading)주식·코인 등 시세는 밀리초 단위로 변하므로 지연 없이 클라이언트에 반영해야 하는 서비스업비트 실시간 가격, 증권사 HTS/MTS
실시간 위치 기반 서비스다수의 사용자의 이동 위치를 실시간으로 서버가 받고 클라이언트에 반영해야 하는 서비스배달의민족 배달 위치 추적, 카카오 차량 위치
온라인 게임(멀티플레이)다수 사용자 간 상태 동기화를 위한 초저지연 통신이 요구됨FPS 게임, MOBA, 실시간 전략 게임
라이브 스트리밍/라이브 커머스영상·음성을 실시간으로 전송하며 시청자 상호작용이 동시에 발생하는 서비스유튜브 라이브, 네이버 쇼핑 라이브
IoT 센서/모니터링 시스템기기·센서의 상태 변화를 서버가 실시간으로 수집하고 대시보드에 갱신해야 하는 서비스공장 설비 모니터링, 스마트홈 센서 알림
협업 서비스(문서/보드)여러 사람이 동시에 문서를 편집할 때 실시간으로 모든 변경분을 공유하는 서비스구글 Docs, 피그마

실시간 통신 패러다임

폴링(Polling)과 롱 폴링(Long Polling)의 개념

폴링: 클라이언트가 일정 간격으로 서버에 요청을 보내 업데이트가 있는지 확인하는 방식이다. 구현이 단순하지만 실시간성이 필요한 경우 오버헤드가 발생 할 수 있다.
롱 폴링: 서버가 새로운 데이터가 생길 때까지 요청을 오래 유지했다가 응답을 반환하는 방식이다. 불필요한 요청을 줄여 실시간성은 높아지지만 소켓 연결 유지 비용이 증가한다.

폴링의 비효율성

폴링은 클라이언트가 정해진 주기로 계속 요청을 보내기 때문에 서버 변화가 없어도 불필요한 트래픽이 발생한다. 요청 횟수가 많아질수록 서버·네트워크 자원이 낭비되고 지연도 커진다. 이러한 구조는 대규모 사용자 환경에서 확장성과 효율성이 크게 떨어지는 방식이다.

롱 폴링의 한계

롱 폴링은 요청을 오래 유지해 실시간성을 높이지만, 연결이 많아지면 서버가 유지해야 하는 세션 수가 급격히 증가한다. 또한 응답 후 다시 요청을 재수립해야 해 완전한 지속 연결처럼 매끄럽지 않다. 결국 대규모 트래픽 환경에서는 서버 부하와 지연 문제가 여전히 남아 확장성에 한계가 생긴다.

단방향/양방향 통신의 특성

단방향 통신: 서버 또는 클라이언트 한쪽에서만 데이터를 보낼 수 있는 구조로, 메시지 흐름이 단순하고 구현이 가볍다. 그러나 상호작용이 필요한 서비스에는 제약이 있어 활용 법위가 제한된다.
양방향 통신: 클라이언트와 서버가 서로 데이터를 주고 받을 수 있어 실시간 상호작용이 가능하다. 게임, 채팅처럼 즉각적인 반응이 필요한 서비스에 적합하지만 연결 상태를 지속 관리해야 한다.

실시간 통신 기술의 분류

WebSocket

WebSocket은 클라이언트와 서버가 하나의 연결을 지속적으로 유지하며 데이터를 주고받을 수 있는 양방향 통신 프로토콜이다. 초기에는 HTTP로 핸드셰이크를 수행하지만 이후에는 독립된 전용 소켓 연결로 전환된다. 이를 통해 실시간 상호작용이 필요한 서비스에서 낮은 지연과 효율적인 통신을 제공한다.

Server-Sent Events

Server-Sent Events는 서버가 클라이언트에게 일방향으로 지속적인 이벤트 스트림을 전송하는 기술이다. HTTP 기반의 단일 연결을 유지하며 서버에서 새로운 데이터가 생길 때마다 즉시 전달한다. 구현이 가볍고 브라우저 지원이 좋아 실시간 알림이나 모니터링에 적합하다.

웹훅(Webhooks)

웹훅(Webhooks)은 서버에서 특정 이벤트가 발생했을 때 등록된 외부 서버로 즉시 HTTP 요청을 보내 알림을 전달하는 방식이다. 클라이언트가 주기적으로 요청을 보내지 않아도 되어 폴링 대비 효율적이다. 주로 결제 완료, 상태 변경, Git push 같은 이벤트 기반 자동화를 위해 사용된다. (카카오 로그인, 페이, 토스 페이 등)

실시간 통신 기술 비교

기술통신 방식주요 특징적합한 활용 사례
Polling클라이언트 → 서버 (반복 요청)구현 간단하나 불필요 요청 많아 비효율적간단한 주기적 갱신
Long Polling요청 유지 후 서버 이벤트 시 응답실시간성↑, REST와 쉽게 통합, 그러나 연결 비용 부담알림, 메시지 갱신
SSE (Server-Sent Events)서버 → 클라이언트 단방향 스트리밍HTTP 기반, 브라우저 지원 좋음, 구현 쉬움실시간 알림, 모니터링
WebSocket서버 ↔ 클라이언트 양방향낮은 지연, 상호작용 서비스 최적채팅, 게임, 공동 편집
gRPC Streaming스트림 기반 양방향/단방향고성능 바이너리, MSA 간 통신 적합서버 간 실시간 데이터 처리
WebHook서버 → 외부 서버(HTTP 요청)이벤트 발생 시 즉시 외부 시스템으로 푸시,폴링 불필요결제 알림, GitHub 이벤트, 자동화 트리거

기타 실시간 프로토콜 비교

프로토콜통신 방식주요 특징사용 사례
MQTTPub/Sub매우 경량, 저전력·저대역폭 환경 최적화IoT 센서, 스마트홈
AMQP메시지 큐 기반라우팅·보장 전달·트랜잭션 등 고급 메시징 지원RabbitMQ, 금융·백엔드 메시징
CoAPREST 기반 (UDP)IoT 장치용 경량 프로토콜, 빠르고 단순임베디드 IoT, 소형 디바이스
WebRTCP2P 실시간오디오·비디오·데이터 전송, 브라우저 내장 지원화상회의, 화면 공유
STOMP메시징 (WebSocket 기반)WebSocket 위에서 동작하는 텍스트 기반 Pub/Sub웹 채팅, 알림 서비스
RTMP스트리밍 (TCP)지연이 낮은 스트리밍 업로드에 최적화OBS → 서버 라이브 방송, 라이브 플랫폼 업로드
RTP/RTCP스트리밍 (UDP)실시간 오디오·비디오 전송 표준, QoS 관리Zoom, WebRTC 내부 미디어 전송 구성요소

WebSocket 활용하기

WebSocket 활용하기

WebSocket의 개념

WebSocket은 클라이언트와 서버가 하나의 연결을 지속적으로 유지하며 데이터를 주고받을 수 있는 양방향 통신 프로토콜이다. 초기에는 HTTP로 핸드셰이크를 수행하지만 이후에는 독립된 전용 소켓 연결로 전환된다.
이를 통해 실시간 상호작용이 필요한 서비스에서 낮은 지연과 효율적인 통신을 제공한다.

WebSocket 프로토콜 상세 분석

HTTP 핸드셰이크 과정 상세

WebSocket은 처음에 HTTP 요청을 보내며 Upgrade: websocket 으로 프로토콜 전환을 요청한다.
서버는 요청을 검증한 뒤 101 Switching Protocols 응답을 보내 업그레이드를 승인한다.
이후 기존 HTTP 연결은 WebSocket 전용의 지속 연결로 전환된다.
핸드셰이크가 끝나면 클라이언트와 서버는 WebSocket 프레임을 통해 양방향 실시간 통신을 수행한다.

TCP 기반 전이중(Full-Duplex) 통신

WebSocket은 TCP 위에서 동작하며 단일 연결로 동시에 송수신이 가능한 전이중(Full-Duplex) 통신을 제공한다.
클라이언트와 서버는 서로의 응답을 기다리지 않고 독립적으로 메시지를 주고받을 수 있다.
이 덕분에 낮은 지연과 실시간 상호작용이 필요한 서비스에 최적화되어 있다.

프레임 구조와 데이터 전송 메커니즘

WebSocket 프레임은 FIN, opcode, MASK, payload length 등의 헤더 정보로 구성되어 데이터의 종류·길이·전송
방식을 정의한다. 필요 시 확장 길이와 마스킹 키가 추가되며, 본문은 Payload Data 영역에 담겨 전송된다.
클라이언트는 항상 데이터에 마스킹을 적용해 전송하며, 서버는 이를 해제하고 필요 시 다중 프레임을 조합해 메시지를 완성한다.

Spring Boot WebSocket 고급 구현

Spring Boot WebSocket의 개념

Spring WebSocket은 클라이언트와 서버가 하나의 지속 연결을 통해 양방향으로 데이터를 주고받는 실시간 통신 기술이다.
HTTP 핸드셰이크 후 WebSocket 프로토콜로 전환되어 낮은 지연의 메시지 송수신이 가능하다.
Spring은 메시지 기반 아키텍처(Channel, Handler)를 사용해 확장성과 구조적 처리를 지원한다.
STOMP 프로토콜과 연계하면 Pub/Sub 방식으로 브로커 기반의 메시지 전달도 쉽게 구성할 수 있다.

STOMP 주요 구조체

STOMP는 메시지를 목적지 기반으로 라우팅하는 구조로, 클라이언트의 SEND/SUBSCRIBE 명령, 메시지를 분배하는 브로커, 메시지를 처리하는 애플리케이션 핸들러, 그리고 이를 전달하는 채널(Request/Response Channel) 로 구성된다.
이 구성요소들이 결합되어 WebSocket 기반의 안정적인 Pub/Sub 메시징 모델을 완성한다.

STOMP 프로토콜의 흐름

  1. 클라이언트는 먼저 CONNECT 명령으로 STOMP 연결을 열고, 서버는 CONNECTED 프레임으로 이를 승인한다.
  2. 그 후 클라이언트는 SUBSCRIBE로 특정 목적지를 구독하고 SEND로 메시지를 전송한다.
  3. 브로커는 목적지에 따라 메시지를 라우팅하여 구독자들에게 전달한다.
  4. 모든 처리가 끝나면 클라이언트는 UNSUBSCRIBE와 DISCONNECT로 구독을 해제하고 연결을 종료한다.

STOMP 프로토콜 심층 분석

STOMP는 텍스트 기반 메시징 프로토콜로, 목적지(/topic, /queue)에 따라 메시지를 라우팅하는 Pub/Sub 모델을 WebSocket 위에서 단순하게 구현한다.
클라이언트는 SEND와 SUBSCRIBE 명령을 사용해 메시지 전달과
구독을 수행하고, 브로커는 이를 기반으로 메시지를 여러 구독자에게 효율적으로 분배한다.

STOMP 프로토콜 명령어 종류

명령어용도설명
CONNECT세션 초기화 요청클라이언트가 STOMP 세션을 시작하기 위해 서버에 연결을 요청함.
CONNECTED세션 수립 확인서버가 CONNECT 요청을 승인하고 세션이 활성화되었음을 알림.
SEND메시지 전송클라이언트가 서버의 Application endpoint로 메시지를 전송할 때 사용.
SUBSCRIBE메시지 수신 구독특정 Topic/Queue를 구독하여 서버가 push하는 메시지를 받음.
UNSUBSCRIBE구독 해지기존 SUBSCRIBE 요청을 취소해 더 이상 메시지를 받지 않도록 함.
ACK메시지 처리 확인메시지를 정상적으로 수신·처리했음을 서버에 알림.
NACK메시지 처리 실패 알림처리 중 오류 발생을 서버에 알리고 재전송 전략에 활용됨.
BEGIN트랜잭션 시작여러 SEND 메시지를 하나의 트랜잭션 단위로 묶기 위함.
COMMIT트랜잭션 커밋BEGIN 이후의 작업을 확정하여 메시지 전송을 실제 반영.
ABORT트랜잭션 취소BEGIN 이후의 메시지 처리 작업을 취소함.
DISCONNECT세션 종료 요청클라이언트가 STOMP 세션 종료 및 연결 정리를 요청.
MESSAGE서버 메시지 전달서버가 구독자에게 메시지를 push할 때 사용하는 프레임.
RECEIPT명령 처리 확인서버가 특정 명령(SEND, SUBSCRIBE 등)을 정상 처리했음을 알림.
ERROR오류 알림서버가 오류를 감지하여 클라이언트에 상세 오류 정보를 전달함.

메시지 브로코 고급 설정

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    // 1) 클라이언트가 접속할 STOMP WebSocket 엔드포인트
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws")
                .setAllowedOriginPatterns("*")
                .withSockJS(); // 필요 없으면 제거 가능 (순수 WebSocket만 사용)
    }

    // 2) 메시지 브로커(SimpMessaging) 설정
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.setApplicationDestinationPrefixes("/app");  // 서버 메시지 핸들러(@MessageMapping)
        registry.setUserDestinationPrefix("/user");          // 1:1 메시징 prefix
        registry.enableSimpleBroker("/topic", "/queue");     // 구독자에게 push하는 내장 메시지 브로커
    }

    // 3) 클라이언트 → 서버 요청(Inbound) 처리 쓰레드풀
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.taskExecutor()
                .corePoolSize(4)
                .maxPoolSize(16)
                .queueCapacity(100);
    }

    // 4) 서버 → 클라이언트 응답(Outbound) push 쓰레드풀
    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        registration.taskExecutor()
                .corePoolSize(4)
                .maxPoolSize(16)
                .queueCapacity(200);
    }

    // 5) WebSocket 전송 옵션 설정
    @Override
    public void configureWebSocketTransport(WebSocketTransportRegistration registry) {
        registry.setMessageSizeLimit(64 * 1024)        // 최대 메시지 크기 (64 KB)
                .setSendTimeLimit(20_000)              // 메시지 전송 timeout (20초)
                .setSendBufferSizeLimit(512 * 1024);   // 서버 버퍼 크기 (512 KB)
    }
}
profile
Backend engineer

0개의 댓글