
https://develoyummer.tistory.com/112
https://velog.io/@idonymyeon/알림-구현하기-1-알림을-구현하는-다양한-방법
https://velog.io/@idonymyeon/알림-구현하기-2-완전-쉽게-알아보는-FCM
https://taemham.github.io/posts/Implementing_Notification/
https://velog.io/@haron/PUBSUB-PUBSUB을-파헤쳐보자
https://velog.io/@xogml951/Server-Sent-EventsSSE-Redis-pubsub-Kafka로-알림-기능-개선하기
일반적으로 클라이언트와 서버의 상호작용은 클라이언트가 서버로 HTTP 요청을 보내면 그에 맞는 응답을 서버가 보내주는 형식
그러나 알림은 클라이언트의 요청 없이 서버가 먼저 알림 정보를 전송해주는 형식으로 동작
이러한 알림 기능을 구현하는 기술로는 여러가지 기술이 있음
어떠한 값을 갱신하는 과정
폴링은 일정한 간격 또는 주기적으로 데이터를 확인하거나 갱신하는 정기적 폴링과 특정 이벤트가 발생했을 때만 데이터를 확인하거나 갱신하는 이벤트 기반 폴링으로 나눌 수 있음
정기적 폴링의 대표적인 예시로 Short Polling이 있음
클라이언트가 일정한 짧은 주기로 지속해서 요청을 보내고, 서버는 이러한 요청에 대하여 새로운 데이터가 없다면 빈 응답을, 있다면 데이터를 담은 응답을 보내주는 방식
그러나 새로운 데이터가 없는 경우에도 계속 요청과 응답 작업이 반복되어 불필요한 부하가 생길 수 있음
또한 이벤트가 발생했을 때 알려주는 것이 아닌 일정 주기를 두고 요청과 응답이 오가기 때문에 이벤트 발생을 실시간으로 반영하지 못함
이벤트 기반 폴링의 대표적인 예시로 Long Polling이 있음
클라이언트가 데이터 갱신 요청을 보내면 서버는 Short Polling과 달리 데이터가 없다고 빈 응답을 보내는 것이 아닌 줄 데이터가 생겼을 때까지 대기 후 응답을 보내는 방식
불필요한 요청과 응답을 반복할 필요가 없이 서버에 이벤트가 발생하면 바로 응답을 줄 수 있음
그러나 클라이언트와 서버가 연결을 계속 유지하면 서버 자원을 지속해서 소모하고 있게 됨
Polling은 결국 클라이언트가 먼저 요청을 해야 한다는 점에서 아쉬움이 있음
WebSocket은 HTTP와는 별도의 프로토콜
클라이언트와 서버가 연결을 맺으면 직접적으로 연결을 끊을 때까지 연결이 쭉 유지되며, 이 연결을 통해 클라이언트와 서버는 언제든 양방향 통신이 가능함
즉, 서버에서 새로운 이벤트가 발생한 경우 그 정보를 별다른 클라이언트 요청 없이 보내줄 수 있음 → 실시간 알림 기능에 적합할 수 있음
클라이언트와의 연결이 유지되고 있다는 측면에서 Long Polling과 같이 서버 자원 소모 문제가 있을 수 있음
또한 알림 기능은 ‘서버 → 클라이언트’ 단방향 통신만 되면 구현할 수 있는 기능이라 무겁고 양방향 통신인 WebSocket을 꼭 사용할 필요는 없어 보임
클라이언트에서 서버로 요청을 보내면 일정 시간 동안 연결을 유지하면서 서버에서 이벤트가 발생했을 때 실시간으로 클라이언트에게 데이터를 넘겨주는 서버 → 클라이언트 단방향 통신 방법
Long Polling과 달리 응답을 보내도 연결이 끊어지지 않고 계속 유지함
만약 서버에서 이벤트 발생이 잦아 데이터를 자주 넘겨줘야 한다면 데이터를 받을 때마다 연결을 새로 하는 Long Polling은 부담스러움
WebSocket처럼 별도의 프로토콜을 사용하지 않고 HTTP를 그대로 사용
앱에서는 인터넷 연결이 지속적으로 유지되지 않을 수 있기 때문에 연결이 끊긴 경우 다시 요청을 보내는 로직이 필요함
Spring에서는 SseEmitter 클래스를 통해 SSE 통신을 지원
무료로 메시지를 보낼 수 있는 교차 플랫폼 메시징 클라우드 서버
전자기기는 제조사 별로 운영체제가 다르고 푸시 알림을 보내는 방법 또한 운영체제별로 다름
ex) Android - GCM, iOS - APNS,,
FCM은 애플리케이션에서 FCM을 이용해 알림 기능을 개발해두기만 하면 GCM, APNS 등의 디바이스별 실제 알림 발송 방법은 FCM에서 알아서 작업해 알림을 전송해 줌
위에서 설명한 Long Polling, WebSocket, SSE는 연결을 유지하는 동안 서버 자원이 지속적으로 소모된다는 단점이 있었음
FCM은 클라이언트와 서버 사이에 메시지 전송 전용 클라우드 서버를 하나 두고, 클라이언트는 서버가 아닌 이 클라우드 서버와 연결을 유지하도록 함
그리고 서버는 알림 발송이 필요한 순간에만 FCM 클라우드 서버로 요청을 보내고 응답도 즉시 받는 Stateless 상호작용을 함
이로 인해 서버 자원 고갈 문제를 해결할 수 있음
또한 FCM은 다양한 최적화 기능을 제공하기 때문에 클라이언트 입장에서도 비교적 적은 배터리와 네트워크 사용만으로 알림을 수신할 수 있음
우리 서비스에서 알림을 이용하는 대표적인 경우는 누군가 내가 게시한 사진에 댓글을 남기거나 좋아요를 남긴 경우일 것임
누군가 댓글 생성 API를 호출한 경우 그 사진 글에 대하여 알림을 받아야할 사용자(아마 글의 작성자)에게 알림을 보내면 됨
이 과정에서 글의 작성자는 서버에 딱히 요청을 보내서 알림을 받는 것이 아님
우리 서비스의 알림 기능들은 대부분 이런 방식으로 진행이 될 것이고 이는 ‘서버 → 클라이언트’ 단방향 통신만 이루어진다면 해결이 됨
Polling 방식은 불필요한 오버헤드가 발생할 것이고, WebSocket 방식처럼 양방향 통신은 필요가 없음
즉, SSE or FCM
그런데 SSE는 주로 웹에서, FCM은 주로 앱에서 사용한다고 함 (우리 서비스는 일단 앱 서비스)
또한 FCM을 사용하는 것이 여러 장점도 있고 쓰지 않을 이유가 없을 것 같음
구체적인 발행/구독 방식 및 명칭은 서비스마다 다를 수 있으며, 대표적인 서비스로 Kafka, Redis가 존재
Producer/Consumer가 Publisher/Subscriber 역할을 함
Producer가 특정 Topic에 이벤트를 보내고, 이 이벤트는 Topic의 여러 Partition들에 분산되어 저장됨
이 Topic을 구독하고 있는 Consumer Group 내의 Consumer들은 각각 1개 이상의 Partition으로부터 이벤트를 가져옴
만약 Partition 개수보다 Consumer 개수가 많다면 아무 일도 하지 않는 Consumer가 생겨버리기 때문에 항상 Partition의 수는 Consumer보다 같거나 크게 해야 함
그룹이라는 개념은 존재하지 않음
각 Subscriber가 Channel을 구독하고 있음
Channel은 이벤트를 저장하지 않음 → 이벤트가 도착했을 때 해당 채널에 Subscriber가 존재하지 않는다면 해당 이벤트는 저장되지 않고 사라짐
PUB/SUB은 MSA처럼 운영하는 서버가 많은 경우 이벤트 형식으로 다른 서버의 API를 실행할 때 사용하는 것이 유리한 것 같음
나중에 수평 확장을 하게 되면 고려해보면 좋을 것 같음