본문 바로가기
Web

SSE(Server-Sent-Event) 서비스에 적용하기

by Jun_N 2023. 12. 1.

SSE(Server-Sent-Event) 서비스에 적용하기

JOBDA 모바일 Web/APP 서비스 FE 개발하고 있습니다. SSE를 서비스에 적용한 과정을 공유드리고자 합니다.


잡다(JOBDA)에서 가장 많이 호출되고 리소스가 발생하는 API (GET /notification/v2)는 각 User의 알림 메세지를 조회하는데 사용되고 있습니다.

사용하고 있던 종 모양 Header

해당 부분에서 새로운 메세지가 왔을때 New 표시를 해줘야 하는 기능이 있었는데 이 때문에 매번 30초 간격으로 API를 호출하거나 페이지가 reload, 이동시 리렌더링 문제로 API 리소스 낭비가 일어나고 있었습니다.

(PC, MO 프론트 모두 30 초 간격으로 계속 서버에 API를 호출하고 있었습니다.)

  • 최근 9/27일자 기준 하루동안 90만건의 API 통신 발생 (990k)

개선 목표

SSE(Server-Sent-Event)를 활용하여 알림 호출 횟수를 대폭 줄이는 것이 목표입니다. 기존에는 99만 번의 알림 호출을 하지만, 이를 5만 번으로 줄이고자 합니다.

  • 목표 수치는 99만건 → 5만건

해결 방법으로는 “서버에서만 필요할 때 API를 호출하자”라는 전략을 채택했습니다. 이것은 항상 주기적으로 API를 폴링하는 것이 아니라, 서버에서 알림을 내려줄 때만 API를 호출하는 방식입니다. 이런 방식을 통해 1회의 API 호출만으로도 여러 번의 호출을 방지할 수 있을 것으로 기대됩니다.

이러한 목표를 달성하기에 가장 적합한 기술은 SSE(Server-Sent-Event)로 판단하였으며, 백엔드 개발자와 함께 이 기술을 연구하고 도입하고자 기술 연구를 시작했습니다.

기존에 사용하던 Polling 방식은 일정한 간격으로 서버에 요청을 보내기에 불필요한 트래픽이 발생하고 있었습니다. 따라서, SSE를 사용하여 불필요한 트래픽을 최대한 줄이고자 했습니다.

SSE(Server-Sent-Event) 란?

 

실시간 데이터를 전달할 수 있는 기술로는 크게 Socket, SSE가 있습니다. 

SSE와 Socket의 가장 큰 차이점은 통신의 방향입니다.

  • SSE는 Server -> Client 로 단방향 통신
  • Web Socket은 Server <-> Client 로서 양방향 통신

그 외에 두 가지를 비교하면 다음과 같습니다 .웹 소켓과 SSE의 차이점은 아래와 같습니다.

 

SSE(Server-Sent-Event)는 브라우저의 개입 없이 서버에서 브라우저로 단방향으로 이벤트를 전송하는 기술입니다. 이를 통해 서버는 언제든지 새로운 데이터를 브라우저로 보낼 수 있으며, 사용자가 실시간 정보를 필요로 하는 대부분의 애플리케이션에 적용 가능합니다. 또한, Internet Explore를 제외한 거의 모든 부라우저가 SSE를 지원합니다.

 

클라이언트는 서버로부터 이벤트(Event)를 받기 위해 대기하며, 새로운 알림(notification)이 발생하면 서버에서 해당 이벤트를 클라이언트로 보내줍니다. 이렇게 전송된 이벤트를 클라이언트에서 받아서 화면에 표시하면 됩니다. SSE를 이용하면 단 한 번의 서버 호출만으로도 클라이언트가 필요할 때 실시간 업데이트를 수신할 수 있습니다.

 
JOBDA SSE 구조

 

[PC/MO] 프론트 잡다 알림 SSE 테스트

  • 잡다 알림 SSE 명세
{
"topic":"jobda:v1:notification",
  "message":{
  "notification":{
    "notificationSn":0,
    "type":"MATCH_OFFER",
    "data":{
      ${MATCH_OFFER type 알림에 필요한 데이터 값} }, "createdDateTime":"2023-09-26T09:40:57.693Z",
      "accessYn":true
    }
  }
}
  • SSE에서 전달되는 데이터는 주로 다음과 같은 형식을 갖습니다. 데이터의 구조는 "type" 필드를 통해 식별되며, 해당 데이터를 프론트엔드에서 파싱하여 처리할 수 있습니다. 기존의 복잡한 알림 처리 로직을 간소화하고 필요한 정보를 "data"에서 추출하여 사용할 수 있습니다.

예시) 기존에 잡다 알림에서 이용하던 /notifications/v2 API에서 userNotificationType: "SIMPLE_MESSAGE" 인경우 프론트에서 가져다 쓰는 정보는 다음과 같다.

-${positionName}의 ${companyName}에서 메시지를 보냈어요. 지금 자세한 내용을 확인해보세요.

-잡다 알림 클릭시 메시지 창 뜸 (positionSn 사용)

(data.positionName, data.companyName, data.positionSn 처럼 가져다가 쓰면 된다는 의미)


SSE 적용 Step. 1

  • EventSource를 사용해서 Server에 SSE 등록.
  • header에 accessToken을 넘겨줘야 하기에 브라우저에서 제공하고 있는 EventSource가 아닌 EventSourcePolyfill 사용.
  • Event 자체적으로 45초마다 네트워크 통신 여부를 확인하고 있기에 heartbeatTimeout를 10분으로 조정.
  • NotificationType(’jobda:v1:notification’)에 해당하는 Event type이 내려왔을때 브라우저에서 데이터를 받기 위한 처리 과정
  • 기존 알람에 SSE로 받은 새로운 알람 연결하기
const EventSource = EventSourcePolyfill || NativeEventSource;
const eventSource = new EventSource(`${config.host}${URIs.get_sse_subscribe}`, {
  headers: { Authorization: AuthorizeUtil.bearerAccessToken },
  heartbeatTimeout: 6000000, // 10분
  withCredentials: true,
});

await notificationModel.loadNotifications(); // 초기 알림 가져오기 위한 호출
const NotificationType = 'jobda:v1:notification';

eventSource.addEventListener(NotificationType, (event: any) => {
  const parsedData = JSON.parse(event.data);
  notificationModel.setUnRead(true); // 알람에 New 표시를 위한 처리

  notificationModel.notifications.unshift(parsedData.data); // 기존 알람에 SSE로 받은 새로운 알람 연결하기
});

return () => {
  eventSource.close(); // 브라우저 종료시 이벤트 제거 (서버측, 브라우저 자체적으로 제거해주긴 하는데 방어코드)
};

Notification 개선 추가 작업

  • EventSource에 SSE rq rs 변경

→ 이전에 사용하던 notificationRs는 필요하지 않은 데이터까지 모두 포함하여 백엔드에서 전송되었기 때문에 나중에 관리가 어려울 것으로 판단합니다. 따라서 필수값과 선택적으로 내려오는 값을 분리하여 받고 관리하는 것이 필요합니다. 이렇게 하면 필수 데이터를 보다 명확하게 관리하고 선택적인 데이터는 필요할 때만 사용할 수 있어서 효율적인 데이터 관리가 가능할 것입니다.

  • <바뀐 Rs>

data에는 선택적으로 내려주는 값들만 따로 받습니다.


결과

Push Notification API를 매 페이지마다 또는 1분 주기로 계속 호출하는 대신, 백엔드에서 SSE 관련 이벤트를 브라우저로 보내고 이를 처리하여 notification 데이터를 업데이트하는 방식으로 변경함으로써 API 호출을 최소화해주었습니다.

 

API 호출 수

변경 전
기간 : 2023–09–20 17:00 ~ 2023–09–27 17:00
총 호출 수 : 3,870,000회
초당 호출 수 : 6.4회

개선 전 

변경 후
기간 : 2023–10–17 17:00 ~ 2023–10–24 17:00
총 호출 수 : 823,000회
초당 호출 수 : 1.4회

개선 후

 

사용자가 웹사이트를 사용하면서 최초 로그인 시 한 번만 API를 호출하도록 함으로써 리소스를 절약할 수 있습니다. 이러한 변경으로 인해 실제로도 알림(notification) 호출이 90% 이상 감소한 것으로 보여졌고 성능 개선을 하였습니다. SSE를 통해 서버 및 클라이언트 리소스 사용을 최소화하면서도 사용자에게 실시간 업데이트를 제공할 수 있었습니다.