서론
기본적으로 HTTP 프로토콜을 사용하는 아키텍처에서 front-end가 back-end 서버에 데이터를 요청하는 단 방향 통신이다. 따라서 특정 이벤트가 발생했을 때 이를 front-end에서 처리하고 싶다면, back-end 서버에서 front-end에 알릴 수 있는 방법을 고안해야 한다.
여러가지 방법들
Polling

front-end에서 주기적으로 http 통신을 요청하여 특정 이벤트가 발생했는지 주기적으로 확인하는 방법이다. 통신을 할 때마다 연결하고 연결을 끊기 때문에 리소스 낭비도 심하고 비효율적이다.
Long Polling

front-end에서 http 통신을 요청하고 서버에서는 이벤트가 발생하기 전까지 통신을 유지한다. 그리고 이벤트가 발생했을 때 응답을 하는 방식이며, 응답을 받으면 곧 바로 다시 요청을 하며 다음 이벤트를 기다리는 방식이다.
이 또한 이벤트가 자주 발생하게 되면 그 만큼의 연결 및 연결 해제 리소스가 낭비되는 단점이 있다.
Server-Sent-Event (SSE)

Server Sent Event, SSE는 통신을 유지하며 이벤트가 발생할 때마다 text나, event를 전송해주는 방식이다.
event를 스트림형식으로 계속 보낼 수 있어서, 프론트는 해당 이벤트를 비동기적으로 처리하는 콜백함수를 정의하면 된다. 웹 소켓과 달리 한번 연결을 유지하고 back-end → front-end로 이벤트를 전송하는 단방향 통신이기 때문에 푸시 알림같은 기능에 용이하다.
- 예시 코드 (custom event)
const sse = new EventSource("/api/v1/sse");
sse.addEventListener("notice", (e) => {
console.log("notice 이벤트 수신:", e.data);
});
sse.addEventListener("update", (e) => {
console.log("update 이벤트 수신:", e.data);
});
sse.addEventListener("message", (e) => {
console.log("기본 메시지 또는 event: message 수신:", e.data);
});
채팅 시스템이나, 게임 등 양방향으로 상호작용이 필요한 통신방식에는 적합하지 않다. 이럴 때는 웹 소켓을 사용하는 것이 일반적이다.
그 외에 단점으로는, HTTP기반의 통신방법이라 HTTP 메소드를 사용하는데, GET 메소드밖에 사용하지 못한다. 그리고 브라우저를 닫거나 새로고침을 하게되면 DOM, JavaScript가 초기화되기 때문에 기존에 연결된 것도 끊기게 된다.
물론 SSE의 Last-Event-id 를 통해 마지막으로 받은 이벤트 부터 현재까지 발생한 이벤트를 받을 수 있는 방법이 있다. 이를 구현하기 위해 back-end에서 송신하지 못한 이벤트를 처리해주는 로직이 필요하다. 방법은 여러가지가 있겠지만, 현재 생각 나는건 3가지 정도 있다.
- 메모리 캐시 사용
- 서버가 재시작하거나 다운되면 사라짐 → 비추천
- Redis와 같은 인메모리 DB 사용
- TTL을 사용하여 유동적인 이벤트처리 가능
- 하지만, 이것또한 영속성을 보장하지않음 → 비추천
- Kafka 같은 이벤트 소싱 사용
- 데이터 영속성을 보장해줌. disk에 이벤트들을 저장하기 때문 → 괜찮을 것 같음
마무리
지금까지 서버 → 클라이언트 방향으로 데이터를 전달하는 방식에 대해 알아보았다. 여기서 다루지 않은 Service Worker를 통한 푸시 알림 기능은 다음에 비교분석 해보겠다.