728x90

개요

어떤 특정 행위에 대한 알림 기능은 유저의 요청 없이도 실시간으로 서버의 변경 사항을 웹 브라우저에 갱신해줘야 하는 서비스이다. 하지만 전통적인 Client-Server 모델의 HTTP 통신에서는 이런 기능을 구현하기가 어렵다. 클라이언트의 요청이 있어야만 서버가 응답을 할 수 있기 때문이다. HTTP 기반으로 해당 문제를 해결하려면 다음과 같은 방식들이 있다.

 

 

일단 알림 기능을 위해 사용되는 방법 4가지를 간략하게 정리해보았다. 

 

실시간 통신의 방법

Polling

  • 특징
    • 일정 주기로 서버 API 호출하는 방법
    • 클라이언트에서 5초마다 한 번씩 알림 목록을 호출한다면, 업데이트 내역이 5초마다 갱신되며 변경 사항을 적용할 수 있다.
      • 주기가 길다면? : 데이터의 실시간성을 보장할 수 없다.
      • 주기가 짧다면? : 갱신된 내용 없어도 불필요한 요청이 자꾸 들어오기 때문에 불필요한 서버 부하가 발생한다.

 

Long-Polling

  • 특징
    • Polling과 비슷하나, 업데이트 발생 시에만 응답을 보내는 방법
    • 서버에 요청 들어왔으면 일정 시간 대기하다가 업데이트 된 내용이 있을 경우 웹 브라우저에 응답을 보낸다.
      • 불필요한 응답을 주는 경우를 줄일 수 있다. (장)
      • 연결이 되어있는 경우 실시간으로 데이터가 올 수 있다. (장)
      • 데이터 업데이트가 빈번할 경우, 연결을 위한 요청이 계속 발생하기에 서버 부하 발생한다. (단)

 

SSE (Server-Sent Event)

  • 특징
    • 웹브라우저에서 서버 쪽으로 특정 이벤트를 구독하면, 서버에서 해당 이벤트 발생 시에 웹 브라우저로 이벤트를 보내주는 방법
    • 따라서 한 번만 연결 요청을 보내면, 연결이 종료될 때까지 재연결 과정 없이 서버에서 웹 브라우저로 데이터를 계속해서 보낼 수 있다.
      • 서버에서 웹 브라우저로만 데이터 전송 가능(단방향)
      • 최대 동시 접속 횟수가 제한되어있다.
      • 한번만 연결요청 보내면, 연결 종료 전까지는 재연결 없이 계속 데이터를 전송할 수 있다. (안끊김)

 

Web Socket

  • 특징
    • 서버와 웹브라우저 사이 양방향 통신이 가능한 방법이다.
    • 변경 사항에 빠르게 반응해야하는 채팅이나, 리소스 상태에 대한 지속적 업데이트가 필요한 문서 동시 편집과 같은 서비스에 많이 사용되는 방식이다.
      • 양방향 통신이 지속적으로 이루어진다.
      • 연결을 유지하는 것 자체가 비용이 들기에, 트래픽 많으면 서버에 부담이 된다.

 

결론

  • Polling 방식은 실시간성을 높이려면 그 주기를 짧게 해야 하는데, 트래픽이 많아질 경우 서버에 걸리는 부하가 커지기 때문에 알림 서비스에는 부적합하고 할 수 있다.
  • Long-Polling 역시 마찬가지로, 트래픽이 많아지면 요청도 그만큼 많아지므로 부적합하다.
  • 그렇다면 HTTP 연결 방식에 대한 부담이 적은 SSE와 WebSocket 방식이 남는데, 알림 서비스의 경우 클라이언트에서 서버로 데이터를 전송하지 않아도 되어서 단방향 통신만으로도 구현할 수 있으므로, SSE 방식을 택하는 것이 좋겠다.

 

해결 과정

  • 알림의 경우 전통적인 client-server 모델의 http 통신에서는 구현하기 어렵다.
  • 해당 방식은 클라이언트의 요청이 있어야만 서버가 응답하는데, 알림은 ‘클라이언트의 요청이 없이’ 실시간으로 서버의 변경 사항이 웹 브라우저에 갱신 되어야하기 때문이다.
  • 제시된 4가지 방법 중 http 연결에 대한 부담이 적은 방식은 SSE, Web socket 이며 실시간성도 보장이 된다.
  • 이 중 알림은 단방향 통신만 해도 된다. (서버 → 클라이언트) 그래서 보통 알림은 SSE 방식을 많이 채택한다.

 

알아보니 Spring에서 제공하는 SSE 프레임워크 사용하면 알람 기능이 쉽게 구현될 것 같아 SSE 방식의 알림 기능을 구현하기로 정했다.

 

크게 보면 작업은 아래와 같이 진행될 것이라 예상된다.

  1. 웹 브라우저와 서버 연결하기 (한번 연결하면 재연결 자주 안해도 된다.)
    1. 연결 관련해서 설정해주기 (연결 , 알림 전송 메소드 생성 포함)
  2. 생성해둔 알림 전송 메소드를 각 이벤트가 발생하는 서비스 메소드 내에 추가한다.
    1. 크루장 승인의 경우, 승인 메소드 내에 알림 전송 메소드 포함하여 알림 전송될 수 있도록 한다.

 

이 때, 고민했던 내용들

 

Q. SSE는 실시간 접속 중일 때만 알림을 보낼 수 있다. 사용자가 오프라인일 때는 어떻게 할지?

 

위의 질문에 대해 3가지 해결 방법을 생각해보았다. 

 

A. 

  1. 서버가 사용자의 접속여부를 파악하여서 따로 처리한다. 이 때, 지금 프로젝트는 토큰 방식으로 인증을 하기에, 서버에서 사용자의 접속 여부 알 수 없다. 따라서 접속여부 파악하는 방법?
    1. 접속여부 DB 생성하고, 클라이언트에서 heartbeat 5초에 한번씩 서버로 보내서 접속 여부 파악 → 주로 프론트 개발자가 해야할 일들이라서 패스
  2. 푸시 알람 전송하기.
    SSE의 경우 오프라인일 경우 실시간 전송이 안됨. 물론 푸시 알림으로 처리할 수 있지만 이 부분은 프론트 개발자가 처리해야해서 일단 패스
  3. 알림함 만들기.
    특정 이벤트가 발생했을 때, 아래의 a,b 두 가지를 모두 실행한다.
    1. SSE로 실시간 알림을 전송한다 →
      1. 만약 오프일 경우, 그냥 알림 못받는 것으로 처리
      2. 온라인일 경우, 알림함 빨간 표시 + 팝업창 띄우기 정도
    2. 알림함 DB에 알림 내용을 저장한다. → 온, 오프 상관 없이 모두 DB에 저장하고, t/f로 읽음 여부 판단하기
      1. 알림함은 최초 접속 1회일 때만 조회해서 안읽은 알람 여부 판단하고, 이 후 실시간 알람 왔을 때에만 알림함 한번씩 조회하기. (실시간 알림 안왔으면 알림 조회할 이유 없으니까)

⇒ 결론으로는 3번째 방법으로 진행하기로 했다. 

 

 

 

 

 

 

참고 링크 

[백엔드|스프링부트] 알림 기능은 어떻게 구현하는게 좋을까? | TaemHam

728x90

+ Recent posts