개발

SSE 이벤트 푸쉬로 불필요한 polling 제거하기

senyalog 2024. 10. 23. 23:00

1. 도입 배경

  •  증권 화면에서 준실시간으로 가격을 보여주기 위하여 polling으로 데이터를 불러옴 -> 사용자가 늘어나면서 CPU 사용률이 커짐

 

2. Push Server 구성

  • WebSocket  vs ServerSentEvents (SSE)
  WebSocket ServerSentEvent
Protocol HTTP WebSocket
Direction 서버 사이드 단방향 양방향
Auto Reconnect O X
Cookie O X
Response Type Text text or byte
  • 증권 페이지에서 WebSocket은 양방향 통신이 필요할 때, 송/수신 데이터량이 많을 때, 시세 조회할 때(화면이동 할 때마다 시세를 구독할 지 말지) 주로 사용
  • 증권 페이지에서 불필요한 polling 제거할 때, 개인화된 데이터를 이용한 event push
  • client가 정확히 언제 끊어졌는지 잘 모름 때문에 hearbeat을 통해 좀비 커넥션 없는지 확인 필요
    • 하지만 이미 끊어진 connection에 ACK를 응답하니 RST가 날라옴(장비 문제였음. 때문에 모니터링환경은 필수로!)

3. ServerSentEvents(SSE) 구성

출처 : https://tecoble.techcourse.co.kr/post/2022-10-11-server-sent-events/

  • content-type : text/event-stream
  • 연결이 된 이후에는 서버에서 데이터가 변경되면 주기적으로 메시지를 보냄

  • client는 SSE server와 연결을 맺음
  • client가 받는 데이터는 메시지 브로커를 통해 받게됨
  • 다양한 서버에서 메시지 브로커로 전송할 메시지를 전달
  • 때문에 크게 client side message(SSE server to client)와 server side message( *-server to 메시지 브로커 )를 나눌 수 있음

3-a) Client Side Message 전략

  • BroadCasting
    • 메시지 브로커로부터 SSE-server가 메시지를 전달 받을 경우 모든 클라이언트에게 메시지를 전달
    • webFlux로 구현가능
      • client와 연결될 브로드캐스팅 채널을 생성
      • 서버가 실행되는 시작부터 브로커로부터 모든 메시지를 수신받게됨
      • 수신 받은 모든 메시지를 SSEMsg로 변환 후 client로 전달하는 순서로 BroadCastingHandler가 완성
      • connect 메서드를 호출하면 BroadCasting채널이 완성됨
    • 사용 사례
      • 이벤트성 단일 채팅방(빠른 개발을 위하여, fomc 실시간 의견 )
        • client --메시지--> api-server --메시지--> 메시지 브로커 --메시지--> SSE server --메시지--> client
  • Unicasting
    • SSE server가 유저별로 채널을 각각 만들어주게됨(유저별 단독 채널)
    • client는 본인의 채널만 구독하여 SSE server 연결
    • webFlux로 구현가능
      • unicast() 채널을 생성 후 client와 연결
      • 연결이 끝나면 개인화된 데이터 스트림을 주입받고 SSE msg로 변환하여 채널로 전달
        • 개인용 data stream은 어떻게 만들까?
          • Flux스트림을 만들어서, 본인의 메시지를 필터링 할 수 있는 리스너를 발급함
          • client와 연결이 끊어지면 SSE server와 구독 취소를 함
    • 사용 사례
      • 개인화된 데이터 (보유 자산)

3-a) Server Side Message 전략

  • 메시지 브로커 선택 전략
    • kafka
      • server마다 groupId를 발급해서 모든 메시지를 수신해서 연결된 사용자한테만 데이터를 내려줄 수 있음
      • atLesatOnce 지원하기에 SSE와는 어울리지 않음 왜냐하면 접속/미접속 사용자 모두 SSE server로 메시지가 발행됨
        • 불필요한 IO 그리고 불필요한 필터링이 필요하게됨
    • redis pub/sub
      • atMostOnce, SSE server는 redis pub/sub에 연결된 사용자만 subscribe 요청
      • publisher는 무작위로 Redis Pub/Sub에만 요청함
      • 모든 데이터를 받진 않음
      • 성능 테스트 결과 60K나옴
    • NATS
      • GoLang기반 + Pub.Sub 기반으로 만들어진 도구
      • 노드 종류
        • 단일노드
        • 클러스터 노드
          • redis pub/sub보다 성능이 5배 좋음
        • 슈퍼 클러스터 노드

참고 문헌

https://www.youtube.com/watch?v=JDeZNxIk5Ko