채팅 서버 구축 고민점
- 다중 서버 세션관리는 어떻게 구현해야할까?
- 메세지 전달 방식 및 클라이언트 서버 구성은 어떻게 해야할까?
오늘은 간단한 테스트로 WAS + NoSQL + Redis로 테스트 개발로 진행했다.
Redis를 이용하여 pub/sub 방식의 STOMP 프로토콜로 진행해보고자 한다.
NoSQL
몽고 디비를 사용하였고 NoSQL을 이용하하여 채팅방 설정 정도로 간단하게 적용해보았다.
Redis
redis를 통하여 pub/sub 방식으 채널 구독자가 메세지를 가져감으로써 다중 서버에서도 메세지 교환이 원할하게 이루어질 수 있게 진행했다. 추후에 해당 내용을 정리 할 예정이다.
WAS (Spring boot)
spring boot + thymeleaf로 하나의 WAS에서 처리하는 방식으로 진행했다. 개발 이후에 리팩토링을 진행 할 예정이며 처음 도전해보는 개발이여서 최소한의 규모로 결과물을 뽑기로 결정했다.
몽고 DB 설정
@Configuration
public class MongoConfig extends AbstractMongoClientConfiguration {
@Value("${spring.data.mongodb.database}")
private String database;
@Value("${spring.data.mongodb.host}")
private String host;
@Value("${spring.data.mongodb.port}")
private int port;
@Override
protected String getDatabaseName() {
return database;
}
@Bean
@Override
public MongoTemplate mongoTemplate(MongoDatabaseFactory databaseFactory, MappingMongoConverter converter) {
MongoClient mongoClient = MongoClients.create("mongodb://" + host + ":" + port);
MongoDatabaseFactory factory = new SimpleMongoClientDatabaseFactory(mongoClient, getDatabaseName());
converter = new MappingMongoConverter(new DefaultDbRefResolver(factory), new MongoMappingContext());
converter.setTypeMapper(new DefaultMongoTypeMapper(null));
return new MongoTemplate(factory, converter);
}
}
- 몽고 디비 config 클래스를 만들어서 간단하게 만들었으며 다큐멘터리를 등록하여 채팅방 처리를 진행했다.
Redis 설정
@Configuration
@RequiredArgsConstructor
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
private final SimpMessageSendingOperations messagingTemplate;
public static String CHANNEL_TOPIC = "your_topic";
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
@Bean
public RedisTemplate<String, String> redisTemplate() {
final RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
final RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory());
redisMessageListenerContainer.addMessageListener(messageListenerAdapter(), channelTopic());
return redisMessageListenerContainer;
}
@Bean
public MessageListenerAdapter messageListenerAdapter() {
return new MessageListenerAdapter(new MessageSubscriber(messagingTemplate));
}
@Bean
public ChannelTopic channelTopic() {
return new ChannelTopic(CHANNEL_TOPIC);
}
}
- 레디스를 설정 config를 만들었고 채널을 설정하였다.
Web Socket STOMP 설정
@RequiredArgsConstructor
@Configuration
@EnableWebSocketMessageBroker // STOMP 사용
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/open/chat")
.setAllowedOriginPatterns("*")
.withSockJS();
}
}
- STOMP 프로토콜을 이용한 broker 설정을 진행했고 해당 endpoint로 sokectjs를 이용하게 설정했다.
@Slf4j
@Service
@RequiredArgsConstructor
public class MessageSubscriber implements MessageListener {
private final SimpMessageSendingOperations messagingTemplate;
@Override
public void onMessage(Message message, byte[] pattern) {
log.info("String Message received: " + message.toString());
try {
Map map = new ObjectMapper().readValue(message.toString(), Map.class);
messagingTemplate.convertAndSend("/sub/message/" + map.get("id"), map.get("content")); // 구독 메세지 전달
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
- 이후에 두개의 다른 포트서버를 띄워두고 각 서버에 요청을 날리면 모두 공유되게 채팅이 발생될 수있는지 테스트 진행하였으며, 동작이 되는것을 확인했다. 아직은 간단하게 사용하여 테스트 정도만 진행했고 이제는 하나씩 찾아보면서 진행할 예정이다.
'Web Socket' 카테고리의 다른 글
Spirnb WebSocket 서버 구현 (0) | 2024.03.24 |
---|---|
WebSocket - SockJs (1) | 2024.03.24 |
WebSocket (0) | 2024.03.24 |
Spring Web Socket 서버 생성 (0) | 2024.03.02 |