[Redis] Redis Pub/Sub 기반으로 SSE 구현하기

연유라떼·2025년 7월 27일
post-thumbnail

현재 우리 프로젝트의 구조
Spring 서버, Android와 HTTP 기반으로 협업 중
-> RESTful API를 기반으로 통신 중

그 중에서 특정 이벤트들에 대한 푸시알림의 기능을 적용해야함
푸시알림에 대한 방법
1. FCM 연동하기
2. SSE로 백그라운드에서도 연결하기
실시간에 더 가깝기도 하고 새로운 데이터베이스를 추가하고 싶지 않아서 SSE 기반으로 푸시 알림을 구현하기로 하였다

1. SSE 구현하기

SSE란?

Server-sent Event로, 어떤 특정 이벤트에 대하여 서버가 http 기반으로 클라이언트에게 알림을 보내는 것이다. 응답을 보내는 것.
SSEEmitter 객체를 기반으로 연결이된다면 해당 연결을 기반으로 서버에서 지정한 만료시간이 지나지 않는다면 계속 응답을 받을 수 있다

-> 그래서 SSE에 대한 설정 추가

Spring Boot에서의 SSE 관리

Emitter를 관리하는 Repository와 Service를 통하여 처음 connection이 이어진다면 이에 대하여 관리를 할 수 있도록 설정
Spring Security 인증에 등록되어있는 memberId의 고유한 값을 기반으로 각각의 SSE를 생성

전체 알림 / 개인 알림 구분

전체에 대한 공지 알림에 대해서는 memberId 값을 넣지 않고,
개인 알림에 대한 구분에는 memberId를 Emitter 생성에 key값의 일부로 집어 넣어서 해당 memberID에 속하는 SSE를 찾고, 그 SSE에 대하여 알림이 전송되도록 구현

2. Redis의 Pub/Sub를 통한 확장

SSE를 서버가 설정한 시간에 대하여는 유효하긴 하지만,
여러 클라이언트의 접속의 경우 이를 처리하기 어려울 수 있다.
그래서 이용한 것이 Redis의 Pub/Sub이다.

Redis의 EventStream 기반 채널링은
동일한 채널에 대해서는 Publish를 거치면 해당 채널을 Subcribe하는 사람은 모두가 수신이 가능하다.

그래서 알람 타입에 따라서 Redis의 채널을 설정한 뒤에,
SSE의 객체를 memberId별로 생성한 것에 대하여 전부 Redis에 저장을 하였다

설계한 구조는 전반적으로 위와 같음

Redis Publisher / Redis Subscriber
-> SseEmitterService 작동해 관리

No-SQL인 Redis의 장점답게 객체 자체를 저장할 수 있기에
DTO 자체를 그냥 Message 대상으로 넣어버림

다음과 같이 생성된 객체 내용들이 채널별로 나타나는 것을 확인 가능

채널 별로 발행 -> 이에 대하여 고유한 키 값으로 회원 별로 서버측에서 필터링(SSE 서비스 코드에서)

3. 생각해야하는 것들

비동기 처리나 그 외의 것들 추가해야함
프론트와의 연동을 위한 것들 처리 필요
sse에 대한 설정을 일단 Long.MAX_VALUE로 하였는데, 이를 30분으로 변경하고 주기적으로 연결을 위한 관리 필요

4. 트러블 슈팅

실제 배포를 하였을 때 connection이 30초만 되고 종료가 됨

그래서 왜그런지 확인해봤는데
Nginx로 리버스 프록시를 통하여 관리를 하고있었는데
Nginx의 경우, 기본적으로 HTTP/1.0 을 기반으로 작업되기 때문에 요청이 성공하고 응답이 완료되었으면 30초 후에 자동으로 연결을 끊는 것이었다

그래서 Nginx의 HTTP를 1.1로 버전을 변경해야함
추가로 connection 설정도 ''로 변경해야하며 타임아웃에 대한 체크도 필요하다

proxy_set_header Connection '';
proxy_http_version 1.1;

proxy_read_timeout 3600s;
proxy_send_timeout 3600s;

keepalive_timeout 3600s;
profile
일단 공부해보겠습니다..

1개의 댓글

comment-user-thumbnail
2026년 1월 29일

잘 읽고 갑니다

답글 달기