[태호] 답변 알림 API 구현방식 - boostcampwm2023/web04-ALGOCEAN GitHub Wiki

event를 client에 보내는 방법

  • 숏폴링, 롱폴링, SSE, Web Socket이 있음
    • 폴링/SSE/Socket
      • 숏 폴링
        • 정보의 갱신 여부를 client가 server에게 빠른 주기로 요청하는 것
      • 롱 폴링
        • 정보의 갱신 여부를 client가 요청하고 갱신이 되었을 때 비로소 server에서 client로 응답 전달
      • SSE
        • 단방향 통신
      • Socket
        • 양방향 통신
  • 폴링 방식들은 client의 수가 증가함에 비례하여 서버의 부담이 증가함
  • Web Socket을 socket 연결 자체가 서버에 부담이 많이 갈 수도 있음
    • 연결이 끊어졌을 때 적절히 대응해야함 → 구현 부담
    • 트래픽 많으면 CPU에 부담이 감
  • SSE는 로그인 된 사용자만 이벤트에 대한 알림을 받을 수 있음
    • 실시간성은 보장되지만 로그아웃된 상태에서 발생한 이벤트는 알 수 없음
  • 웹 푸시
    • 우리 프로그램 기획에서 생각한 알림이 아님
    • 이벤트 발생 시 웹으로 푸시알람을 보내는 것

사용할 기술

SSE

SSE를 활용하여 이벤트 기반의 알림을 만드려고 함

고민 과정

  • nest 공식 문서에서 제공하는 sse의 예시는 이벤트 기반이 아니고 일정 주기마다 data를 client로 전송하는 것임
  • event 기반의 sse를 작성하고 싶어서 event emitter를 고려해보았지만 유저의 수가 증가함에 따라 event를 관리하기 어려워짐
  • 이에 대한 대책으로 RxJS도입을 결정함
    • RxJS is a library for composing asynchronous and event-based programs by using observable sequences. It provides one core type, the [Observable](https://rxjs.dev/guide/observable), satellite types (Observer, Schedulers, Subjects) and operators inspired by Array methods ([map](https://rxjs.dev/api/index/function/map)[filter](https://rxjs.dev/api/index/function/filter)[reduce](https://rxjs.dev/api/index/function/reduce)[every](https://rxjs.dev/api/index/function/every), etc) to allow handling asynchronous events as collections.
    • RxJS의 Observable 객체를 이용하면 event에 관한 Promise객체들을 Array처럼 관리할 수 있음
    • 이는 곧 함수형 프로그래밍이 적용 가능하다는 것과 동치임
  • naive한 구현을 통해 작동이 됨을 확인하고 구현을 구체화 시킬 목적으로 in-memory기반의 user관리 Map을 도입함
    • 예상되는 문제점
    • 로그인한 유저가 증가함에 따라 memory가 터질 수도 있음
    • 분산 서버 환경에서 in-memory 공유가 안됨
    • 배포할 때마다 서버가 재시작되는데 이때 in-memory가 초기화됨
    • redis도입으로 해결 가능할 듯
  • 로그인할 때마다 RxJS로 Observable 객체를 만들어 준 후 userId:observer 형식으로 Map에 삽입
  • sse connection을 성공했지만 data를 보내주지 않을 때 연결이 끊기는 현상 발생
    • 몇 초 안에 데이터를 전송해야 끊기지 않는 지 모르겠음
    • 때로는 10초안에 끊길 때도 있고 때로는 3분이 넘어갔는데 끊기지 않음
    • data 전송 시 오류 나면 재연결 요청
  • 로그아웃 상황에서 발생한 이벤트를 저장하고 로그인 했을 때 해당 이벤트들을 보내주는 과정이 필요함
    • 이 또한 redis로 해결 가능

구현

  • 발생할 알림들을 모두 db에 저장하면서
  • 사용자가 sse연결이 되어있는 경우 redis를 통해 알림을 받을 수 있음
  • 사용자가 sse연결이 되어있지 않은 경우 연결 시 밀린 알림들을 받을 수 있음
  • user와 연결을 나타내는 stream관련 정보는 in-memory 방식으로 안 다룰수가 없음

참고 링크

[https://inpa.tistory.com/entry/WEB-📚-Polling-Long-Polling-Server-Sent-Event-WebSocket-요약-정리](https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-Polling-Long-Polling-Server-Sent-Event-WebSocket-%EC%9A%94%EC%95%BD-%EC%A0%95%EB%A6%AC)

https://blogs.windows.com/windowsdeveloper/2016/03/14/when-to-use-a-http-call-instead-of-a-websocket-or-http-2-0/

https://yozm.wishket.com/magazine/detail/1753/