inflearn logo
강의

Khóa học

Chia sẻ kiến thức

Dịch vụ trò chuyện WebSocket/STOMP (spring, vue, redis)

배포 오류 질문

123

KMC

42 câu hỏi đã được viết

0

안녕하세요 강사님 제가 실전이라 생각하고 프론트랑 백엔드를 배포 했습니다.
auto


	at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.5.3.jar:3.5.3]
Caused by: org.springframework.data.redis.listener.adapter.RedisListenerExecutionFailedException: org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
	at org.springframework.data.redis.listener.RedisMessageListenerContainer.lazyListen(RedisMessageListenerContainer.java:383) ~[spring-data-redis-3.5.1.jar:3.5.1]
	at org.springframework.data.redis.listener.RedisMessageListenerContainer.start(RedisMessageListenerContainer.java:361) ~[spring-data-redis-3.5.1.jar:3.5.1]
	at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:405) ~[spring-context-6.2.8.jar:6.2.8]
	... 19 common frames omitted
Caused by: org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.translateException(LettuceConnectionFactory.java:1858) ~[spring-data-redis-3.5.1.jar:3.5.1]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$ExceptionTranslatingConnectionProvider.getConnection(LettuceConnectionFactory.java:1789) ~[spring-data-redis-3.5.1.jar:3.5.1]
	at org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory$SharedConnection.getNativeConnection(LettuceC

 

Redis 에러 (백엔드 에러는 이렇게 뜨고)

 

{0CB206BF-155F-48D6-8126-A2F2729359DA}.png

 

프론트 엔드 (로그인 하고 들어가는 거 잘됩니다. 채팅만 치면 저렇게 뜹니다.)

EC2에서 redis 접속은 잘 됩니다.

프론트는 S3+cloudfront (도메인 적용 안함)를 통해 배포를 했고

둘다 https 는 적용했습니다.

 

image.png

 

백엔드는 Redis(ElastiCache(실시간 PubSub 기능을 위해) + EC2+RDS +nginx(https)+ 깃헙 액션으 로 배포했고 몇시간 쨰 하는데 저 에러가 뜹니다.

백엔드 배포 자체는 /opt ~ 를 통해서 배포 했습니다.

혹시 프론트 배포가 잘 못 된건가요?

 S3+cloudfront 면 안될수도 있나요?

 

StompWebSocketConfig

package org.example.javademo.chatserver2.chat.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.ChannelRegistration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

@Configuration
@EnableWebSocketMessageBroker
public class StompWebSocketConfig implements WebSocketMessageBrokerConfigurer {

    private final StompHandler stompHandler;

    public StompWebSocketConfig(StompHandler stompHandler) {
        this.stompHandler = stompHandler;
    }

    /**
     * 클라이언트가 WebSocket으로 접속할 수 있는 endpoint 설정
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/connect")
                .setAllowedOrigins(
                 
                )
                // SockJS를 통해 ws가 아닌 환경에서도 연결 가능하게 설정
                .withSockJS();
    }

    /**
     * STOMP 메시지 브로커 설정
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        // /publish 로 시작하는 메시지는 @MessageMapping 메서드로 라우팅
        registry.setApplicationDestinationPrefixes("/publish");

        // /topic 으로 시작하는 메시지는 메시지 브로커를 통해 구독자에게 전달
        registry.enableSimpleBroker("/topic");
    }

    /**
     * 클라이언트 → 서버 (inbound) 메시지 처리 쓰레드 풀 설정
     */
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.taskExecutor()
                .corePoolSize(10)
                .maxPoolSize(20)
                .keepAliveSeconds(60);
    }

    /**
     * 서버 → 클라이언트 (outbound) 메시지 처리 쓰레드 풀 설정
     */
    @Override
    public void configureClientOutboundChannel(ChannelRegistration registration) {
        registration.taskExecutor()
                .corePoolSize(10)
                .maxPoolSize(20)
                .keepAliveSeconds(60);
    }

    // 인증 등을 처리하고 싶을 경우 stompHandler 등록 (현재 주석처리)
    // @Override
    // public void configureClientInboundChannel(ChannelRegistration registration) {
    //     registration.interceptors(stompHandler);...
    // }
}

 이거는 조금 수정했습니다.

 

RedisConfig

package org.example.javademo.chatserver2.common.configs;

import org.example.javademo.chatserver2.chat.service.RedisPubSubService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@Configuration
public class RedisConfig {

    @Value("${spring.data.redis.host}")
    private String host;

    @Value("${spring.data.redis.port}")
    private int port;

    // 연결 팩토리 생성
    @Bean
    @Qualifier("chatPubSub")
    public RedisConnectionFactory chatPubSubFactory() {
        RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
        config.setHostName(host);
        config.setPort(port);
        return new LettuceConnectionFactory(config);
    }

    // String 기반 Redis 템플릿
    @Bean
    @Qualifier("chatPubSub")
    public StringRedisTemplate stringRedisTemplate(@Qualifier("chatPubSub") RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }

    // 메시지 수신 처리 리스너 어댑터
    @Bean
    public MessageListenerAdapter messageListenerAdapter(RedisPubSubService redisPubSubService) {
        return new MessageListenerAdapter(redisPubSubService, "onMessage");
    }

    // 수신 채널 주제 설정
    @Bean
    public PatternTopic chatTopic() {
        return new PatternTopic("chat");
    }

    // 메시지 수신을 처리하는 리스너 컨테이너.
    @Bean
    public RedisMessageListenerContainer redisMessageListenerContainer(
            @Qualifier("chatPubSub") RedisConnectionFactory connectionFactory,
            MessageListenerAdapter listenerAdapter,
            PatternTopic chatTopic
    ) {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(connectionFactory);
        container.addMessageListener(listenerAdapter, chatTopic);
        return container;
    }

    // (선택) Object 기반 Redis 템플릿
    @Bean
    public RedisTemplate<String, Object> redisTemplate(@Qualifier("chatPubSub") RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}

 

 

ElastiCache로 접속은 굉장히 잘 됩니다. (EC2 내부에서는)

{A005C155-153D-425C-8AB6-55CF13FC9277}.png

문제는 이게 UI 에 왜 안 뜨는지 모르겠습니다.

 

spring-boot websocket stomp-websocket pubsub vue-3

Câu trả lời 2

0

bradkim

안녕하세요~! 일단 제가 서버를 직접 볼수 없다보니 다소 제한적입니다.

 

일단, pub/sub설계를 제외해보시고, redis뺀상태에서 채팅이 잘 되는지 확인해보고,

 

그러면 redis 연결이 문제인것이니, 이렇게 문제의 원인을 좁혀 나가야 할것 같아요

0

KMC

EC2 내부에서 redis 자체는 연결이 굉장히 잘 되는데 저렇게 UI 에는 왜 안 뜨는지 모르겠습니다.

0

KMC

강사님 혹시 제가 구현한 방식이 문제가 있나요? (백엔드 파트 기존 코드로는 연결 자체에 문제가 생겨서 수정했습니다.) (중간에 api cors 없는 부분은 제가 뺏습니다.)

0

bradkim

일단 추측컨데, elastic cache가 설정에 따라 접속이 잘 안되는것을 저도 경험을 했어서 아래와 같은 생성방법을 정리한것을 가지고 있는데,

 

cli로 연결이 된다면, redis를 elastic caches에서 생성할떄 아래 방법을 따라 보시겠어요?

 

  • elastic cache 구성

    • 6379 port 보안그룹에서 오픈

    • 자체캐시설계 → 클러스터 캐시 → 클러스터 모드 비활성화

    • primary enpoint를 엔드포인트로 사용

0

KMC

이거는 다 해보았습니다.

0

communityai8509

안녕하세요, 인프런 AI 인턴입니다. KMC님.

배포 과정에서 발생하는 Redis 연결 문제와 관련하여 몇 가지 점검할 수 있는 사항을 안내드립니다.

  1. Redis 연결 설정 확인:

    • 백엔드에서 Redis에 접근할 때 사용하는 호스트 및 포트가 정확한지 확인해보세요. 특히, ElastiCache 클러스터의 엔드포인트를 정확히 사용하고 있는지 점검해 보시기 바랍니다.
  2. 환경 설정 파일:

    • 서버 환경(ex: application.properties 또는 application.yml)에서 올바른 Redis 호스트 정보가 설정됐는지 확인하세요. 로컬과 다른 프로파일을 사용하고 있을 수 있습니다.
  3. 방화벽 및 네트워크 설정:

    • EC2 보안 그룹 또는 VPC 설정이 ElastiCache와의 통신을 허용하는지 확인하세요. 보통 ElastiCache는 해당 VPC의 서브넷에서만 접근 가능하도록 설정됩니다.
  4. 프론트엔드와 API 백엔드 간의 CORS 설정:

    • 프론트엔드(클라이언트)와 백엔드 간의 Cross-Origin Resource Sharing(CORS) 설정을 적절히 설정하여 통신이 원활한지 확인하세요.
  5. SSL/HTTPS 통신 문제:

    • HTTPS가 잘 설정되어 있는지가 중요합니다. 특히 프론트엔드와 백엔드 간의 통신에서 발생할 수 있는 SSL 인증서 문제나 잘못된 설정이 있는지 확인하세요.
  6. 검증 로그 활용:

    • 문제의 원인을 추적하기 위해, Redis 연결 문제 관련 더 많은 로그 정보를 출력하여 실시간으로 검토하십시오.

위 내용 외에 기초부터 다시 점검하시면서, 아래 유사한 질문에 대한 토론을 추가적으로 참고하시면 도움이 될 수 있습니다:
- Spring Application과 Redis 설정 이슈

배포에는 많은 요소가 연관되어 있어 꼼꼼한 설정 재확인이 필요하므로, 문제를 지속적으로 모니터링하고 변경 사항을 적용해 보시면 좋을 것 같습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해 드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

0

KMC

  1. ro 가 아니고 그냥 기본 엔드포인트로 했습니다. 2~4 까지 다 해 봤습니다.

     

ERD 질문

0

54

2

StompHandler 관한 질문

0

79

2

리프레시 토큰은 알아서 구현하면 되는건가요??

0

79

2

cors, csrf 직접 구현

0

64

1

JWT 필터구현

0

96

2

강의 잘듣고 있습니다. 혹시 다음 강의 계획은 없으신가요?

0

57

1

STOMP 동작 과정 질문

0

48

1

chain.doFilter()

0

45

1

자바 21로 소스 작성해도 되나요?

0

60

2

메시지 브로커 선택에 관한 질문

0

64

2

WebSocket과 Spring Security 질문

0

81

2

추가 커스텀 구현 질문 있습니다.

0

59

2

connect와 동시에 구독하는데 구독 검증이 꼭 필요한가요?

0

97

2

저도 동일한 질문인데

0

78

3

token이 필요한 엔드포인트에 의도적으로 토큰 누락시 대처

0

67

2

수업자료가 왜 다 나눠져있나요?

0

78

2

메시지 전송 시 검증

0

61

2

JWT 생성 시 subject 설정에 대한 질문

0

156

3

StompHandler 질문 있습니다.

0

82

2

앱 서비스일 경우

0

82

2

웹소켓 서버 재배포시 고려해야 할 상황 질문

0

106

2

/connect 경로에 대한 토큰 검증의 필요성

0

77

1

JwtTokenProvider 작성중 오류 발생으로 문의드립니다.

0

95

2

수강료가 갑자기 인상됬던데 ㅠ

0

130

1