안녕하세요! 현재 개발 중인 PMS(Project Management Service)에서 사용자에게 실시간으로 변경 사항이나 새로운 정보를 전달하는 것은 매우 중요한 기능입니다. 저희는 이 실시간 알림 기능을 구현하기 위해 Spring Boot 환경에서 SSE(Server-Sent Events) 방식을 선택했고, SseEmitter 클래스를 핵심적으로 활용했습니다.

이 글에서는 왜 SSE와 SseEmitter를 선택했는지, 그리고 많은 분들이 우려하시는 실시간 연결 유지에 따른 자원 소모 문제와 이를 어떻게 비동기 처리 등을 통해 완화했는지 공유하고자 합니다.

왜 SseEmitter를 사용했는가?

알림 기능을 구현하는 데 SseEmitter를 사용한 주된 이유는 다음과 같습니다.

  1. Server-Sent Events (SSE) 프로토콜 지원: SseEmitter는 Spring에서 SSE 프로토콜을 표준적으로 지원하는 클래스입니다. 이를 통해 서버에서 클라이언트로 단방향 이벤트를 실시간으로 푸시(push)하는 기능을 쉽게 구현할 수 있습니다. 알림처럼 서버 주도로 발생하는 정보를 전달하는 데 매우 적합합니다.
  2. 비동기 통신: SseEmitter는 내부적으로 비동기/논블로킹(Non-blocking) I/O를 기반으로 동작합니다. 즉, 서버에서 이벤트가 발생했을 때, 다른 작업의 완료를 기다리지 않고 해당 이벤트를 연결된 클라이언트에게 즉시 전송할 수 있습니다. 이는 실시간성이 중요한 알림 기능에 필수적이며, 사용자 경험을 크게 향상시킵니다.
  3. 클라이언트 연결 관리 및 재시도 지원 (표준): SSE 프로토콜 자체는 클라이언트가 연결이 끊어졌을 때 자동으로 재연결을 시도하고, 마지막으로 수신한 이벤트 ID(Last-Event-ID 헤더)를 서버에 보내 유실된 이벤트를 다시 요청할 수 있는 메커니즘을 표준으로 정의하고 있습니다. SseEmitter는 이러한 표준 프로토콜을 따르므로, 클라이언트 측 라이브러리(EventSource API)와 함께 사용하면 연결 안정성을 높일 수 있습니다. (물론 서버 측에서도 재전송 로직 등 추가 구현이 필요할 수 있습니다.)
  4. 확장성 (기본 지원): 하나의 서버 인스턴스 내에서 SseEmitter는 여러 클라이언트와의 동시 연결을 효율적으로 관리할 수 있습니다. 즉, 동일한 유형의 알림(예: 공지)이나 각기 다른 알림을 다수의 클라이언트에게 동시에 전송하는 것이 가능합니다.

자원 소모에 대한 우려: 계속 유지되는 연결, 괜찮을까?

SSE의 가장 큰 특징 중 하나는 클라이언트와의 연결을 지속적으로 유지한다는 점입니다. 여기서 많은 개발자들이 "로그인한 사용자가 많아지면 서버 자원을 너무 많이 소모하는 것 아닌가?", "병목 현상이 발생하지 않을까?" 하는 합리적인 우려를 하게 됩니다.

네, 그 우려는 타당합니다. 활성 SSE 연결은 다음과 같은 서버 자원을 분명히 사용합니다.

우리의 해결책: 비동기 처리와 효율적인 관리

이러한 자원 소모 문제를 인지하고, 저희는 다음과 같은 방법으로 시스템의 안정성과 성능을 확보하고자 노력했습니다.

  1. 알림 전송 로직 비동기 처리 (@Async):
  2. 효율적인 Emitter 생명주기 관리:
  3. Spring Security 설정 최적화: