[ Spring Boot ] 웹소켓 통신에서 메모리 누수 제어

2025. 7. 21. 21:28·Spring

웹소켓 통신에서의 메모리 누수

현재 stomp 기반의 실시간 영상 스트리밍 기술을 개발하고 있다.

하지만 화면 새로고침이나 화면 이동 등의 상황에서 서버의 메모리가 급격하게 늘어나는 것을 확인했다.

 

이 부분을 해결하기 위해서 다음과 같은 방안들을 사용했다.

 


효과적인 소켓 연결 관리 방법

Stomp에서의 메모리 누수를 막기 위해서 서버에서만 동작이 필요한 것이 아니다.

프론트엔드와 백엔드 모두 적절한 처리를 해주어야 작업이 완료될 수 있다.


React에서 효과적으로 소켓 연결 관리하기

React에서 서버의 메모리 누수를 발생시키는 원인은 주로 불필요한 연결 유지나 중복 연결로 인해서다.

이를 위해서 적절한 시점에 적절한 방법으로 연결 및 연결 해제해야 한다

연결 해제 로직 관리하기

우선 이번 프로젝트에서는 다음과 같이 연결 해제용 함수를 만들어서 관리했다.

function disconnect(){
    subscriptionRef.current.unsubscribe();
    clientRef.current.deactivate();
}

이 코드에서는 useRef를 활용하여 연결정보와 구독정보를 관리하고 있다.

또한, 연결 해제 시 구독 해제 후 client 연결을 종료한다.

 

이를 통해서 중복과 실수를 줄일 수 있고, 공통으로 연결 해제 기능을 관리할 수 있기에 이점이 있다.

연결 해제 이벤트 관리

위 기능은 사실 매우 간단하고 누구나 할 수 있는 방법이다

하지만 위 함수를 적절한 때에 호출하지 않는다면 이는 중복 연결이나 메모리 누수로 이어질 수 있다.

연결 정보 변경 등의 당연한 상황을 제외하면 대표적으로 두 가지 이벤트에서 연결을 해제하는 것이 좋다.

  • visibilityChange : 화면 활성화 / 비활성화에 대한 이벤트
  • beforeunload : 현재 페이지를 떠나기 전에 발생

해당 이벤트에서 연결을 해제해야 정상적으로 작동하는 서비스를 만들 수 있고 메모리 누수를 줄일 수 있다.


Spring Boot에서 효과적으로 Stomp 연결 관리하기

다음으로는 서버에서 효과적으로 연결을 관리하고 자원을 관리하는 것이 중요하다.

실시간 스트리밍에서 다양한 방법으로 메모리 누수를 막을 수 있겠지만 이번에는 효과적인 웹소켓 연결 관리에 대해서만 알아보겠다.

Stomp Event 처리하기

첫 번째는 Stomp 연결 해제 및 구독 해제 이벤트 발생 시 필요 없는 자원을 제거하는 것이다.

대표적으로 아래 두 가지 이벤트에 대한 이벤트 핸들러를 만들어서 관리한다.

 

우선 아래 코드를 살펴보자.

@Component
@RequiredArgsConstructor
public class SocketEventHandler  {
    @EventListener
    public void handleDisconnect(SessionDisconnectEvent event) {
        // do something
    }
    
    @EventListener
    public void handleDisconnect(SessionUnsubscribeEvent event) {
        // do something
    }
}

 

이 코드에서는 총 두 가지 이벤트에 대한 처리를 진행한다.

  • SessionDisconnectEvent : Stomp 연결이 종료되었을 때 발생
  • SessionUnsubscribeEvent : Stomp 구독 해제 시 발생

우선 이 정도면 정상적인 상황에 대해서는 연결을 효과적으로 관리할 수 있다.

 

하지만 예기치 않게 연결이 종료되는 경우에 대비해서 한 가지 더 설정할 수 있다.

Stomp HeartBeat 

Stomp HeartBeat는 간단히 말해서 일정 간격으로 패킷을 전송하여 대상이 정상적으로 작동하는지 확인하는 것이다.

만약에 네트워크 장애 등으로 인해서 세션이 예기치 않게 종료되면 이는 메모리 누수로 이어질 수 있기에 중요한 작업이다.

 

우선 아래 코드를 살펴보자.

@Configuration
@RequiredArgsConstructor
public class SocketHeartbeatConfig implements WebSocketMessageBrokerConfigurer {
    private final ThreadPoolTaskScheduler taskScheduler;

    /**
     * add stomp broker endpoint for subscription
    * */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/your/destination")
                .setHeartbeatValue(new long[]{10000, 10000})
                .setTaskScheduler(taskScheduler);
    }
}

@Configuration
public class CustomTaskSchedular {
    @Bean
    public ThreadPoolTaskScheduler taskScheduler(){
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        scheduler.setPoolSize(50);
        scheduler.setThreadNamePrefix("stomp-heartbeat-");
        scheduler.setDaemon(true);
        scheduler.initialize();
        return scheduler;
    }
}

이 코드에서는 구독 설정 중 HeartBeat 설정을 진행하고, 이 때 사용할 작업 스케줄러를 정의하고 있다.

  • configureMessageBroker() : 구독 정보 설정
    • setHeartbeatValue : 서버에서 클라이언트  / 클라이언트에서 서버로의 heart beat 시간을 의미한다.
      • 해당 시간이 경과되면 server가 client의 / client가 server의 소켓 연결을 종료한다
    • setTaskScheduler : heartbeat 처리용 스케줄러를 등록
  • taskScheduler() : 작업 스케줄러 설정
    • setPoolSize : 사용할 쓰레드 수
    • setTheradNamePrefix : 쓰레드 이름 앞에 붙는 접두사를 설정함
    • setDaemon : 데몬 스레드로 설정하여 jvm이 종료되면 자동 종료됨
    • initialize : 명시적으로 스레드 풀을 초기화함

위 코드 기준 10초 이내로 패킷이 오지 않으면 연결을 종료한다.

이걸 통해서 유령 세션으로 인한 메모리 누수를 어느 정도는 막을 수 있다.

 


마무리

이번에는 Stomp의 효과적인 연결 관리 방법에 대해서 알아보았다.

단순 채팅 기능을 만드는 것보다 더 고차원적인 연결 관리를 요구했고, 해당 부분을 해결하기 위해서 열심히 공부한 것 같다.

 

이를 통해서 기존에 약 1GB이었던 메모리 사용량을 약 500MB까지 줄일 수 있었다.

실시간 영상 스트리밍 기술이 많은 메모리를 필요로하는 만큼, 약 500MB의 메모리 누수가 있었다는 것을 의미한다.

 

다만 아직 해결되지 않은 메모리 누수가 있기 때문에 해당 부분도 보완해볼 예정이다.

 

'Spring' 카테고리의 다른 글

[ Spring Boot ] JPA 연관 관계 매핑  (1) 2025.08.26
[ Spring Boot ] 스트리밍 서비스에서 Buffer Pool로 ByteBuffer 관리  (6) 2025.07.29
[ Spring ] Spring의 디자인 패턴과 아키텍처  (1) 2025.07.14
[Spring Boot] Spring Boot 설정 파일 분리 : submodule  (0) 2025.03.31
'Spring' 카테고리의 다른 글
  • [ Spring Boot ] JPA 연관 관계 매핑
  • [ Spring Boot ] 스트리밍 서비스에서 Buffer Pool로 ByteBuffer 관리
  • [ Spring ] Spring의 디자인 패턴과 아키텍처
  • [Spring Boot] Spring Boot 설정 파일 분리 : submodule
코드래곤
코드래곤
코드래곤 님의 블로그 입니다.
  • 코드래곤
    코드래곤 님의 블로그
    코드래곤
  • 전체
    오늘
    어제
    • 분류 전체보기 (61)
      • 알고리즘 (3)
        • 그리디 (1)
        • 그래프 (2)
      • 시스템 설계 (6)
      • CS 및 기본 개념 (17)
      • Docker (5)
      • Spring (23)
        • 백준 서비스 구현하기 (1)
        • 기초 개념 (14)
        • MSA (2)
        • JPA (1)
      • Dart (3)
      • Flutter (1)
      • Kubernetes (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
코드래곤
[ Spring Boot ] 웹소켓 통신에서 메모리 누수 제어
상단으로

티스토리툴바