본문 바로가기

프론트의 CSR과 SSR에 따른 백엔드의 대응 방식 연구

배경

본인 허락 받고 인용함

최근 프론트 팀원들의 컴포넌트 CSR과 SSR에 대한 열띤 논의가 있었다.

그런데, CSR과 SSR은 프론트 측의 단순 UI 렌더링만 관련있을까?

백엔드 api 설계는 이와 완전 무관할까?

 

이 게시글을 통해 프론트와 백엔드 모두 컴포넌트 및 api 설계에 도움이 되길 바란다.

목표

백엔드 api에 따른 프론트 컴포넌트의 csr과 ssr의 영향을 분석하고자 한다.

가설

이를 원활히 테스트 할 수 있도록 다음과 같이 범용적인 상품 판매 시나리오를 가정했다.

결과

우선 가장 직관적으로 크롬 디버깅 툴로 직접 조사해보았다.

- Full SSR과 Full CSR로 SSR과 CSR을 분석하고

- 백엔드 V1과 V2를 통해 백엔드 api의 영향을 분석한다.

Full SSR 
+ 백엔드 V1(단일응답)
Full CSR 
+ 백엔드 V1(단일응답)
Hybrid
+ 백엔드 V1(단일응답)
Hybrid
+ 백엔드 V2(분할응답)

 
 

가장 오래걸린 api

 

이를 상세하게 표로 정리하면 다음과 같다.

갱신 기준은 Price&Stock 정보를 매번 새롭게 갱신하는 것을 가정한다.

  Full SSR
+백엔드v1
Full CSR
+백엔드v1
Hybrid
+백엔드v1
Hybrid
+백엔드v2
TTFB SSR 744.84ms Html 로드 110ms
API 갱신 711.91ms
(+ 갱신시마다 711.91ms)
SSR 734.18ms
API 갱신 716.21ms
(+ 갱신시마다 716.21ms)
SSR 73.54ms
API 갱신 305.44ms
(+ 갱신시마다 203.83ms)
설명 전체 SSR 로딩
백엔드 API 통합
전체 CSR 로딩
백엔드 API 통합
SSR + CSR 분리
백엔드 API 통합
SSR + CSR 분리
백엔드 API 분리
API 호출 수 1회 (서버) 1회 (클라이언트) 2회+ (중복!) 4회 (분리)
초기 HTML 완전한 콘텐츠 빈 껍데기 완전한 콘텐츠 기본정보만 포함
실시간 갱신 불가 가능 가능 가능
데이터 낭비 없음 없음 중복 전송 없음
캐시 효율 불가 (통합) 불가 (통합) 불가 (통합) static 캐시

 

웹 자체에 메트릭 분석을 포함해본 결과는 다음과 같다.

단순하게 useEffect/useCallback를 통해 로드되는 시점과 이후의 시간을 비교했다.

분석

  • 프론트가 CSR + SSR 구조를 가져가고, 이에 맞춰 백엔드가 api를 설계하면 베스트이다.
    그러나 하나라도 어긋나면 성능이 극도로 저하된다.
    • 즉, 프론트/백엔드 소통이 이루어지지 않으면 무용지물이다.
    • 프론트가 SSR ALL 또는 CSR ALL을 쓰면, 백엔드가 api 설계를 잘해도 의미가 없다.
    • 프론트가 CSR + SSR을 써도,
      백엔드가 어느 포인트에서 api 분리가 필요한지 알지 못한다면 api 응답은 중복되어 성능이 극감할수있다.
  • SSR이 근소하게 빠르다.
    로컬호스트에서 진행된 만큼, 프로덕션에서는 서버 환경이 가장 큰 예외 변수일 것 같다.
  • API 호출 수가 많으면 TCP Connection이 많아져 더 느려질 거라고 생각했는데,
    어차피 동시에 비동기 요청하므로 의미 없다는걸 깨달았다. 그냥 서버만 죽어나갈 뿐..

마치며

이 게시글은 성능만 언급했다. 그러나 SSR 이 도입될수록 서버 관리는 극악이다.

 

조사 중, 토스도 유사한 고민을 했다는 것을 알 수 있었다.

다음 토스 서버비를 보면 알 수 있다.

출처 : https://toss.tech/article/ssr-server

놀라웠던 사실은 토스는 코드 상의 최적화를 넘어, 인프라 팀과 협업하며 지표를 분석했다.

이를 확인하는 과정이 매우 놀라운데, 꽤나 재밌다.

 

특히 재밌던건 OpenTelemetry 지원안한다고 최신버전에서 hook 빼내서 삽입하고,
Next.js 커스텀서버에서 Express를 제거해 Node 내장 http 서버로 돌리는 등 프레임워크를 가지고 놀더라는 점이다.

 

토스에서 직접 제시한 교훈을 마지막으로 이 글을 마친다. 꽤나 토스의 철학과 일치하는 질문인 것 같다.

Node.js SSR 서버의 성능을 개선하고 싶다면, 다음의 과정을 한 번 고민해보시면 좋겠습니다.
1. 현재의 런타임은 어떻게 구성되어 있는가? 네트워크 토폴로지는 어떻게 구성되어 있으며, 어떤 요청이 오가는가?
2. 측정이 필요한 성능은 무엇이 있는가? 측정할 수 있는가?
3. 개선 전후를 확인할 수 있는, 변인이 통제된 재현 환경이 존재하는가?
NORMAL j/k: 이동 · Enter: 열기 · /: 검색 · ?: 도움말