Redis Pub/Sub에 대해

Dal col·2025년 4월 22일

WebSocket

목록 보기
4/6

Java Websocket을 통해 채팅방을 만들려하면 많이들 쓰는게 Redis의 Pub/Sub입니다.
다른 SQL과 달리 NoSQL로 채팅같은 실시간 데이터 처리를 할때 매우 유용한 친구입니다.

Redis Pub/Sub 특징

subscribe

응답의 두 번째 요소로 제공된 채널을 성공적으로 구독했음을 의미합니다. 세 번째 인수는 현재 구독 중인 채널의 개수를 나타냅니다.

subscribe <채널명>
## 응답
["subscribe", "<채널명>", <현재 구독 중인 채널 개수>]

unsubscribe

응답의 두 번째 요소로 제공된 채널 구독이 성공적으로 취소되었음을 의미합니다. 세 번째 인수는 현재 구독 중인 채널 수를 나타냅니다. 마지막 인수가 0이면 더 이상 어떤 채널에도 구독되지 않으며, Pub/Sub 상태 밖에 있으므로 클라이언트는 모든 종류의 Redis 명령을 실행할 수 있습니다.

unsubscribe <채널명>
## 응답
["unsubscribe", "<채널명>", <현재 구독 중인 채널 개수>]

message

다른 클라이언트가 실행한 명령의 결과로 수신된 메시지입니다 Publish. 두 번째 요소는 발신 채널의 이름이고, 세 번째 인수는 실제 메시지 페이로드입니다.

["message", "<채널명>", "<메시지 내용>"]

채널의 생성, 삭제 구조

그럼 Redis의 Pub/Sub의 채널은 따로 만들어야하는가?

Redis는 별도로 채널을 생성할 필요가 없습니다. 예를 들어 chatroom1 채널을 subscribe 하면, Redis는 해당 채널을 자동으로 생성하고 메시지를 주고받을 수 있는 상태가 됩니다.

Redis는 채널을 만드는것이 아닌 구독을 통해 생성되는 구조로 이루어져있습니다.

그렇다면 Redis 채널 삭제하는 방법은?

Redis는 채널을 명시적으로 생성하거나 삭제하지 않습니다. 구독자가 존재하지 않는 채널은 Redis 내부적으로 유지되지 않기 때문에, unsubscribe를 통해 모든 구독자가 떠나면 해당 채널도 사라지는 구조입니다.

왜 사용할까?

Redis Pub/Sub은 채팅같은 실시간 데이터 처리하는 기능을 구축할 때 탁월한 성능을 보여줍니다. 특히 웹소켓과 결합하면 다중 사용자 채팅 시스템을 손쉽게 구현을 할 수 있어 많은 사람들이 Redis Pub/Sub을 사용합니다.

자바에서 사용 방법

RedisConfig

package com.example.demo.App.Chat.config;


import com.example.demo.App.Chat.Service.RedisSubscriber;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;

@Configuration
public class RedisConfig {
    @Bean
    RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory, MessageListenerAdapter listenerAdapter) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        // 레디스 서버와의 연결 관리
        container.setConnectionFactory(connectionFactory);
        // Redis의 "chat-room-*" 채널에서 실시간으로 메시지를 수신할 수 있는 설정을 의미
        container.addMessageListener(listenerAdapter,new PatternTopic("chat-room-*"));
        return container;
    }
    // handleMessage는 redisSubscriber 객체에서 reids 메시지를 처리하는 메서드
    // Redis 채널에서 수신한 메시지를 handleMessage 메서드로 전달해서 처리
    @Bean
    MessageListenerAdapter listenerAdapter(RedisSubscriber redisSubscriber) {
        return new MessageListenerAdapter(redisSubscriber,"handleMessage");
    }

    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }
}

RedisMessageListenerContainer

  • Redis 연결 유지
  • 특정 채널의 메시지를 구독합니다.
  • "chat-room-*" 패턴으로 시작하는 모든 채널의 메시지를 수신하도록 설정합니다. 예를 들어 chat-room-1, chat-room-abc 등의 채널에서 메시지가 오면 모두 처리 대상이 됩니다.

MessageListenerAdapter

  • redisSubscriber 객체에서 redis 메시지를 처리하는 메서드
  • Redis 메시지를 수신하면, 지정한 메서드로 전달해주는 중개자
  • Redis 채널에서 수신한 메시지를 handleMessage 메서드로 전달해서 처리

RedisTemplate

  • Redis의 명령 실행을 위한 도구

RedisConfig를 왜 생성하는가?

RedisConfig을 만드는 이유는 Bean에 등록하기 위해서입니다. Bean으로 등록해야 우리가 Spring에 의존성 주입할 때 객체를 계속 필요없이 private final로 불러 와줄 수 있습니다.

@Slf4j
@RequiredArgsConstructor
@Service
public class RedisSubscriber {

    private final SimpMessageSendingOperations messagingTemplate;

    // Redis에서 메시지 수신 시 호출
    public void handleMessage(String message) {
        log.info("Redis Subscriber 수신: {}", message);
        // 받은 메시지를 웹소켓 구독자들에게 전달
        messagingTemplate.convertAndSend("/sub/chat/room", message);
    }
}

이렇게 생성을 하고 service에서 사용을 하여 우리는 Redis를 자바에서도 이용할 수 있습니다.

profile
백엔드 개발자가 되기까지의 과정

0개의 댓글