요즘 학점가방 서비스를 제작하면서 바쁜 나날을 보내고 있다.
해당 서비스에는 학교 과제를 관리하는 기능이 있으며 팀장으로부터 과제 마감 전 푸시 알림을 전송하는 기능을 구현해달라는 부탁을 받았다.
처음에는 단순히 FCM으로 구현해야지 생각했다가 다른 방식도 있지 않을까라는 생각에 여러 기술들을 찾아보고 정리해보았다.
FCM(Firebase Cloud Message)
Firebase Cloud Messaging(FCM)은 무료로 메시지를 안정적으로 전송할 수 있는 크로스 플랫폼 메시징 솔루션이다. 쉽게 이야기하면 서버에서 클라이언트로 메시지를 전달할 수 있는 서비스라고 생각하면 된다.
동작방식
FCM의 동작 방식을 간단하게 설명하면 다음과 같다.
- FCM에서 클라이언트 기기에 대한 토큰을 발급 받는다.
- 해당 토큰을 앱 서버(예: Spring Boot, Node.js 등)로 전송한다.
- 앱 서버에서 전달할 메시지와 토큰을 FCM 서버로 전송한다.
- FCM 서버에서 해당 메시지를 특정 클라이언트의 기기로 전송한다.
장점
- FCM은 교차 플랫폼이기 때문에 , 특정 플랫폼에 종속되지 않고 메시지를 전송할 수 있다.
- 클라우드 메시징 서버를 중간에 둠으로써, 클라이언트 어플리케이션은 적은 배터리와 네트워크만을 사용하며 메세지를 실시간으로 수신할 수 있다.
- Firebase API를 이용하기 때문에 구현이 쉽고 이로 인해 기능 구축에 대한 오버헤드를 줄일 수 있다.
단점
- Real-time 서비스이긴 하지만 장치 연결 상태, 메시지의 크기와 포맷, 그리고 네트워크 상태 등 전송 시간이 지연될 수 있는 요소들이 존재한다.
- Firebase API에 의존하기 때문에 커스텀마이징이 불가능하다.
SSE(Server Send Event)
SSE(Server Send Event)는 서버의 데이터를 실시간으로, 지속적으로 Streaming 하는 기술이다.
SSE는 단방향 통신이며 클라이언트의 별도 추가요청 없이 서버에서 업데이트를 스트리밍할 수 있다는 특징을 가진다.
장점
- HTTP를 통해 통신하므로 다른 프로토콜은 필요가 없다.
- HTML과 JavaScript만으로 쉽게 구현할 수 있다.
- 네트워크 연결이 끊겼을 때 자동으로 재연결을 시도한다.
- 실시간으로 서버에서 클라이언트로 데이터를 전송할 수 있다.
- 전송하고자 하는 데이터를 자유롭게 커스텀마이징이 가능하다.
단점
- 구현에 대한 오버헤드가 존재한다.
- GET 메소드만 지원하고, 파라미터를 보내는데 한계가 있다.
- WebSocket과 달리 단방향 통신이다.
- 클라이언트가 페이지를 닫아도 서버에서 감지하기가 어렵다
- SSE는 지속적인 연결을 유지해야 하므로, 많은 클라이언트가 동시에 연결을 유지할 경우 서버 부담이 커질 수 있다.
- 지원되지 않는 브라우저를 사용하는 사용자의 경우에는 중요한 알림을 아예 받지 못할 가능성이 존재한다.
WebSocket
WebSocket은 클라이언트(웹 브라우저)와 서버 간에 양방향(full-duplex) 통신을 할 수 있도록 해주는 프로토콜이다.
서버는 응답을 보낸 뒤 연결을 종료하는 '비연결성'을 갖는 것이 HTTP의 특징인데, WebSocket은 HTTP의 비연결성으로 데이터 전송 시 발생하는 오버헤드를 극복하기 위해 고안된 기술이다.
특징
- 웹소켓은 HTTP 통신과 달리 TCP/IP 응용 계층에서 동작한다.
- HTTP는 클라이언트가 요청해야 서버가 응답하지만, 웹소켓은 요청과 응답 없이 서버와 클라이언트가 자유롭게 데이터를 주고받을 수 있다.
- 그렇기 때문에 클라이언트 끼리도 자유롭게 데이터를 전달하고 전송 받을 수 있다.
- 서버와 클라이언트가 처음 연결 될 때 HTTP를 통해 연결되며 연결이 완료되면 Websoket 프로토콜을 사용한다.
- HTTP는 요청이 끝나면 연결을 끊지만, 웹소켓은 한 번 연결되면 계속 유지된다.
이러한 특징들 덕분에 웹 소켓은 채팅, 게임, 실시간 알림, 주식 데이터 등에 사용된다.
동작 방식

- 웹 소켓 핸드쉐이크
- 클라이언트가 웹소켓 연결을 요청하면, HTTP 요청을 이용해 서버와 초기 연결을 설정한다.
- HTTP 요청 헤더에
Upgrade: websocket 이라는 값을 포함하여 웹소켓을 사용하겠다고 선언한다.
- 이 과정을 웹소켓 핸드셰이크(WebSocket Handshake) 라고 한다.
- 즉, 웹소켓 연결도 HTTP를 사용해 시작하지만, 연결이 성공하면 HTTP에서 웹소켓 프로토콜로 변경된다.
- 서버가 웹소켓 연결 수락
- 서버는 클라이언트의 요청을 받고 웹소켓 통신을 허용할지 결정한다.
- 만약 웹소켓을 지원하고 연결을 허용한다면, HTTP 101 Switching Protocols 응답을 보낸다.
- 여기서 101 응답 코드는 "프로토콜을 HTTP에서 웹소켓으로 변경한다" 는 의미한다.
- 이제부터 클라이언트와 서버는 웹소켓 프로토콜을 사용하여 실시간으로 데이터를 주고받을 수 있다.
- 데이터 송수신
- 연결이 설정된 후에는 클라이언트와 서버가 자유롭게 데이터를 주고받을 수 있다.
- HTTP와 다르게, 새로운 요청을 하지 않아도 서버에서 클라이언트로 직접 메시지를 보낼 수 있다.
- 이를 서버 푸시(Server Push) 라고 한다.
- 즉, 클라이언트가 서버로 데이터를 보낼 수도 있고, 서버가 클라이언트에게 데이터를 보낼 수 있는 양방향(Full-Duplex) 통신이 가능해진다.
- 웹소켓 연결 종료
- 클라이언트 또는 서버 중 한쪽에서 연결을 종료할 수 있다.
- 연결을 종료하면, 웹소켓 프로토콜이 "CLOSE 프레임" 을 전송하며, 서버가 연결을 닫았는지, 클라이언트가 닫았는지를 서로 확인한다.
- 정상적으로 종료되면, 더 이상 데이터를 주고받을 수 없다.
장점
- 양방향 통신이 가능하다.
- 대부분 브라우저에서 지원한다.
- 전송하고자 하는 데이터를 자유롭게 커스텀마이징이 가능하다.
단점
- 구현에 대한 오버헤드가 존재한다.
- 배터리 소모량이 클 수도 있다.
- FCM과 달리 서버에서 모든 부하를 감당 해야한다.
결론
지금까지 푸시 알림 구현이 가능한 3가지 방식에 대해 알아보았다. 지금 현재 중요한 것은 시간과 비용이다. SSE와 Websocket을 구현하기 위해서는 프론트와 벡엔드 모두 구현을 위한 오버헤드가 존재한다. 또한 우리는 간단한 푸시알림을 각 유저에게 전달하면 된다. 이러한 점들을 따져보았을 때 현재 가장 적합한 방식은 FCM이라고 생각한다. 그래서 우리 팀은 FCM을 통해 푸시 알림을 구현하기로 결정하였다.
참고 자료