1. ์น์์ผ(WebSocket)์ด๋?
1.1 ์น์ ๊ธฐ๋ณธ ํต์ ๋ฐฉ์: HTTP์ ํ๊ณ
์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ์๋ฒ์ ํด๋ผ์ด์ธํธ ๊ฐ์ ๋ฐ์ดํฐ ๊ตํ์ ์ผ๋ฐ์ ์ผ๋ก HTTP๋ฅผ ์ฌ์ฉํ๋ค.
ํ์ง๋ง HTTP๋ ๋น์ฐ๊ฒฐ์ฑ(stateless) ํ๋กํ ์ฝ๋ก, ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ๋ณด๋ด์ผ๋ง ์๋ฒ๊ฐ ์๋ตํ๋ ๋จ๋ฐฉํฅ ํต์ ๋ฐฉ์์ด๋ค.
์ด ๋ฐฉ์์ ์ค์๊ฐ์ฑ์ด ์ค์ํ ์ ํ๋ฆฌ์ผ์ด์ (์: ์ฑํ , ์ฃผ์ ๊ฑฐ๋, ์๋ฆผ ์๋น์ค ๋ฑ)์์๋ ๋นํจ์จ์ ์ด๋ค.
์ฃผ๊ธฐ์ ์ผ๋ก ์๋ฒ์ ์์ฒญ์ ๋ณด๋ด๋
ํด๋ง(Polling), ๋กฑ ํด๋ง(Long Polling), ์๋ฒ ์ผํธ ์ด๋ฒคํธ(Server-Sent Events, SSE) ๊ฐ์ ๊ธฐ์ ์ด ์ฌ์ฉ๋์ง๋ง,
์ฑ๋ฅ๊ณผ ํ์ฅ์ฑ์์ ํ๊ณ๊ฐ ์๋ค.
1.2 ์น์์ผ(WebSocket)์ ๋ฑ์ฅ
์น์์ผ์ ํด๋ผ์ด์ธํธ์ ์๋ฒ ๊ฐ์ ์ง์์ ์ธ ์ฐ๊ฒฐ์ ์ ์งํ๋ฉฐ ์๋ฐฉํฅ ํต์ ์ ์ง์ํ๋ ํ๋กํ ์ฝ์ด๋ค. HTTP ๊ธฐ๋ฐ ์ฐ๊ฒฐ์ด์ง๋ง, ์ต์ด ์ฐ๊ฒฐ ์ดํ์๋ ์ง์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์์ด ์ค์๊ฐ์ฑ๊ณผ ํจ์จ์ฑ์ด ๋ฐ์ด๋๋ค.
์น์์ผ์ ๋ฑ์ฅ ๋ฐฐ๊ฒฝ
์น์ด ๋ฐ์ ํ๋ฉด์ ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ์๋น์ค๋ค์ด ๋์ด๋ฌ๋ค.
๊ทธ๋ฌ๋ ๊ธฐ์กด HTTP ๊ธฐ๋ฐ ํต์ ๋ฐฉ์๋ค์ ์ด๋ฌํ ์๊ตฌ๋ฅผ ์ถฉ์กฑํ๊ธฐ ์ด๋ ค์ ๋ค.
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋ฑ์ฅํ ๊ฒ์ด ์น์์ผ(WebSocket)์ด๋ค.
์น์์ผ์ ๋จ์ํ ์์ฒญ-์๋ต ํจํด์ ๋์ด,
์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ์ง์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์๋๋ก ์ค๊ณ๋ ํ๋กํ ์ฝ์ด๋ค.
์น์์ผ์ ํน์ง
- ์๋ฐฉํฅ ํต์ (Full-Duplex): ์๋ฒ์ ํด๋ผ์ด์ธํธ๊ฐ ์๋ก ์์ ๋กญ๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์๋ค.
- ์ ์ง์ฐ์ฑ(Low Latency): ์์ฒญ-์๋ต ๋ฐฉ์๋ณด๋ค ๋น ๋ฅด๊ฒ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ ์ ์๋ค.
- ์ฐ๊ฒฐ ์ ์ง(Persistent Connection): ํ ๋ฒ ์ฐ๊ฒฐ๋๋ฉด ์ง์์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์์ด ์ค๋ฒํค๋๊ฐ ์ ๋ค.
2. ์๋ฐฉํฅ ํต์ ๊ณผ WebSocket
2.1 ์๋ฐฉํฅ ํต์ ์ด๋?
์๋ฐฉํฅ ํต์ (Full-Duplex Communication)์ ํด๋ผ์ด์ธํธ์ ์๋ฒ๊ฐ
์๋ก ๋ ๋ฆฝ์ ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ ์ ์๋ ํต์ ๋ฐฉ์์ด๋ค.
๊ธฐ์กด HTTP ์์ฒญ-์๋ต ๋ชจ๋ธ์ ๋จ๋ฐฉํฅ(Half-Duplex)์ด๋ผ ์๋ฒ๊ฐ ๋จผ์ ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ ๊ฒ์ด ๋ถ๊ฐ๋ฅํ์ง๋ง,
์น์์ผ์ ์๋ฒ์์๋ ํด๋ผ์ด์ธํธ์๊ฒ ๋ฐ์ดํฐ๋ฅผ ์์ ๋กญ๊ฒ ๋ณด๋ผ ์ ์๋ค.
2.2 ์น์์ผ vs ๊ธฐ์กด ๋ฐฉ์
ํน์ง | HTTP Polling | Long Polling | SSE | WebSocket |
ํต์ ๋ฐฉ์ | ํด๋ผ์ด์ธํธ ์์ฒญ ํ ์๋ต | ํด๋ผ์ด์ธํธ๊ฐ ์์ฒญ์ ์ ์ง | ์๋ฒ์์๋ง ๋ฐ์ดํฐ ์ ์ก ๊ฐ๋ฅ | ์๋ฐฉํฅ ํต์ |
์ฑ๋ฅ | ๋ฎ์ | ๋ณดํต | ๋์(์๋ฒ → ํด๋ผ์ด์ธํธ) | ๋งค์ฐ ๋์ |
์ฐ๊ฒฐ ์ ์ง | ๋ถ๊ฐ๋ฅ | ๊ฐ๋ฅ | ๊ฐ๋ฅ | ๊ฐ๋ฅ |
์๋ฐฉํฅ์ฑ | ์์ | ์์ | ์๋ฒ → ํด๋ผ์ด์ธํธ | ์๋ฐฉํฅ ๊ฐ๋ฅ |
์น์์ผ์ ํนํ ์ฑํ ์๋น์ค, ๊ฒ์, ์ค์๊ฐ ์ฃผ์ ์ ๋ณด ์ ๊ณต, ์๋ฆผ ์์คํ ๋ฑ์ ์ ํฉํ๋ค.
3. Spring์์ WebSocket ํ์ฉํ๊ธฐ
Spring Boot์์๋ Spring WebSocket ๋ชจ๋์ ์ ๊ณตํ์ฌ ์ฝ๊ฒ ์น์์ผ์ ๊ตฌํํ ์ ์๋ค.
ํ์ง๋ง ์น์์ผ๋ง์ผ๋ก๋ ๋ฉ์์ง ๋ผ์ฐํ ๋ฐ ํ์ฅ์ฑ์ด ๋ถ์กฑํ๋ฏ๋ก
STOMP(Simple Text Oriented Messaging Protocol) ํ๋กํ ์ฝ์ ํจ๊ป ์ฌ์ฉํ๋ค.
3.1 STOMP๋?
STOMP๋ ํ ์คํธ ๊ธฐ๋ฐ ๋ฉ์์ง ํ๋กํ ์ฝ๋ก, ์น์์ผ์ ๋ ์ฝ๊ฒ ์ฌ์ฉํ ์ ์๋๋ก ๋์์ค๋ค.
์ด๋ฅผ ํตํด ๋ฉ์์ง ๋ธ๋ก์ปค(Message Broker)๋ฅผ ํ์ฉํ ๋ฉ์์ง ์ ๋ฌ์ด ๊ฐ๋ฅํ๋ค.
3.2 Spring Boot์์ WebSocket & STOMP ์ค์
1) WebSocket ์ค์
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic"); // ๋ฉ์์ง๋ฅผ ์ ๋ฌํ ๊ฒฝ๋ก
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
}
}
2) ๋ฉ์์ง ์ปจํธ๋กค๋ฌ ๊ตฌํ
@Controller
public class ChatController {
@MessageMapping("/chat")
@SendTo("/topic/messages")
public String sendMessage(String message) {
return message;
}
}
3) ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ (JavaScript ์์ )
var socket = new SockJS('/ws');
var stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/messages', function (message) {
console.log("Received: " + message.body);
});
});
function sendMessage() {
stompClient.send("/app/chat", {}, "Hello WebSocket!");
}
4. Kafka์ WebSocket ์ฐ๋
4.1 Kafka๋?
Kafka๋ ๋์ฉ๋์ ๋ฐ์ดํฐ๋ฅผ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌํ ์ ์๋ ๋ถ์ฐ ๋ฉ์์ง ์์คํ ์ด๋ค.
์ค์๊ฐ ๋ฐ์ดํฐ ์คํธ๋ฆฌ๋ฐ, ๋ก๊ทธ ์์ง, ๋น๋๊ธฐ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฑ์ ๋ง์ด ํ์ฉ๋๋ค.
4.2 Kafka๋ฅผ WebSocket๊ณผ ํจ๊ป ์ฌ์ฉํ๋ ์ด์
- ํ์ฅ์ฑ(Scalability): ๋ค์์ ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ๋ ๊ฒฝ์ฐ ๋ถํ๋ฅผ ์ค์ด๊ธฐ ์ํด ๋ฉ์์ง๋ฅผ Kafka๋ก ๋ถ์ฐํ ์ ์๋ค.
- ๋ด๊ฒฐํจ์ฑ(Fault Tolerance): ๋ฉ์์ง๊ฐ ์ ์ค๋์ง ์๊ณ ์์ ์ ์ผ๋ก ์ ์ก๋๋ค.
- ๋น๋๊ธฐ ์ฒ๋ฆฌ: ์น์์ผ์ด ์ง์ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ๋ ๋์ Kafka๋ฅผ ํ์ฉํ๋ฉด ๋ ํจ์จ์ ์ธ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
4.3 Spring Boot์์ Kafka ์ฐ๋ํ๊ธฐ
1) Kafka ์ค์
spring.kafka.bootstrap-servers=localhost:9092
spring.kafka.consumer.group-id=chat-group
2) Kafka Producer (๋ฉ์์ง ์ ์ก)
@Component
public class KafkaProducer {
private final KafkaTemplate<String, String> kafkaTemplate;
public KafkaProducer(KafkaTemplate<String, String> kafkaTemplate) {
this.kafkaTemplate = kafkaTemplate;
}
public void sendMessage(String message) {
kafkaTemplate.send("chat-topic", message);
}
}
3) Kafka Consumer (๋ฉ์์ง ์์ ํ WebSocket์ผ๋ก ์ ๋ฌ)
@Component
public class KafkaConsumer {
private final SimpMessagingTemplate messagingTemplate;
public KafkaConsumer(SimpMessagingTemplate messagingTemplate) {
this.messagingTemplate = messagingTemplate;
}
@KafkaListener(topics = "chat-topic", groupId = "chat-group")
public void listen(String message) {
messagingTemplate.convertAndSend("/topic/messages", message);
}
}
5. ๊ฒฐ๋ก
- WebSocket์ ์ค์๊ฐ ์๋ฐฉํฅ ํต์ ์ ๊ฐ๋ฅํ๊ฒ ํ๋ฉฐ, STOMP๋ฅผ ์ฌ์ฉํ๋ฉด ๋ ํจ์จ์ ์ผ๋ก ๋ฉ์์ง๋ฅผ ๊ด๋ฆฌํ ์ ์๋ค.
- Kafka๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ฉด ํ์ฅ์ฑ๊ณผ ์์ ์ฑ์ ํ๋ณดํ ์ ์์ด ๋๊ท๋ชจ ์๋น์ค์์๋ ์ ์ฉํ๋ค.
- Spring Boot๋ฅผ ํ์ฉํ๋ฉด WebSocket๊ณผ Kafka๋ฅผ ์ฝ๊ฒ ํตํฉํ์ฌ ํจ์จ์ ์ธ ์ค์๊ฐ ์์คํ ์ ๊ตฌ์ถํ ์ ์๋ค.
๐ ์ค์๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ๊ฐ ํ์ํ ํ๋ก์ ํธ์์ WebSocket๊ณผ Kafka๋ฅผ ํจ๊ป ํ์ฉํด๋ณด์!