effidevFlutter · Cloudflare 엣지 · 클라우드 비용 최적화
한국어

React Server Components(RSC) 스트리밍 SSR과 Cloudflare Edge SSR 아키텍처 실전 패턴

React Server Components Streaming SSR and Cloudflare Edge Architecture

React Server Components(RSC) 스트리밍 SSR과 Cloudflare Edge SSR 아키텍처 실전 패턴

모던 웹 프론트엔드 아키텍처는 클라이언트 사이드 렌더링(CSR)에서 서버 사이드 렌더링(SSR), 그리고 이제는 React Server Components(RSC)스트리밍 SSR(Streaming SSR) 의 시대로 전환되었습니다.

기존 SSR은 서버에서 전체 페이지의 HTML 생성이 완료될 때까지 브라우저가 아무것도 렌더링하지 못하는 지연(TTFB, Time to First Byte) 병목이 존재했습니다. RSC와 스트리밍 SSR을 활용하면 서버 연산이 준비된 HTML 조각부터 브라우저로 실시간 스트리밍할 수 있습니다.

여기에 Cloudflare Workers와 같은 에지(Edge) 런타임을 결합하면, 유저와 가장 가까운 PoP(Point of Presence)에서 0ms 수준의 cold start로 스트리밍 렌더링을 시작할 수 있습니다. 이번 글에서는 이 아키텍처의 원리와 구현 실전 패턴을 상세히 알아봅니다.


1. 전통적 SSR vs RSC 스트리밍 SSR 비교

전통적인 SSR과 RSC 기반 스트리밍 SSR의 주요 차이점은 데이터 페칭 및 HTML 전달 파이프라인에 있습니다.

구분 전통적 SSR RSC + Streaming SSR
렌더링 단위 페이지 전체 (All-or-Nothing) 서스펜스(Suspense) 경계 기준 조각(Chunk) 단위
TTFB (Time to First Byte) 모든 DB 데이터 조회가 끝날 때까지 렌더링 대기 (느림) 셸(Shell) HTML을 즉시 전송하여 초고속 TTFB 달성
번들 사이즈 서버 렌더링 컴포넌트의 JS 라이브러리도 클라이언트에 전달 서버 전용 컴포넌트의 JS는 클라이언트 번들에서 완전히 제거됨
하이드레이션 (Hydration) 전체 DOM 하이드레이션 필요 필요한 클라이언트 컴포넌트만 부분적(Selective) 하이드레이션

2. Suspense와 React DOM Server Streaming API

React 18/19의 renderToReadableStream API를 사용하면 Node.js 버퍼링 없이 Web Standard Stream 기반으로 HTML 조각을 전송할 수 있습니다.

실전 코드: RSC 스트리밍 파이프라인

다음은 React Server Components와 Suspense를 결합하여 스트리밍 SSR을 구현하는 예시입니다.

// Server Component: 느린 API/DB 조회를 포함하는 컴포넌트
async function SlowRecommendedProducts() {
  // 1.5초 소요되는 데이터 페칭
  const products = await fetchProductsFromDB();

  return (
    <div className="recommendations">
      {products.map((p) => (
        <ProductCard key={p.id} product={p} />
      ))}
    </div>
  );
}

// Main Page Component
export default function ProductDetailPage({ params }: { params: { id: string } }) {
  return (
    <main className="product-page">
      {/* 셸 영역: 즉시 스트리밍 전송됨 */}
      <ProductHeader id={params.id} />

      {/* 무거운 영역: 로딩 폴백을 먼저 보내고, 완료되면 HTML 덮어쓰기 스트리밍 */}
      <React.Suspense fallback={<ProductSkeleton />}>
        <SlowRecommendedProducts />
      </React.Suspense>
    </main>
  );
}

3. Cloudflare Workers Edge SSR 아키텍처 파이프라인

Cloudflare Workers는 V8 Isolate 기반으로 작동하므로 무거운 Node.js 런타임 오버헤드 없이 전 세계 300개 이상의 에지 데이터 센터에서 SSR을 실행합니다.

[User Browser]
      │  1. HTTP Request

[Cloudflare Edge Worker (V8 Isolate)]
      │  2. Fast Shell HTML Stream (0~10ms)
      ├──────────────────────────────────────────► [Browser Render Shell]
      │  3. Async Fetch DB/Cache (D1 / Hyperdrive)
      │  4. Stream Suspense Chunks via HTTP/2
      └──────────────────────────────────────────► [Browser Replace Skeleton]

Worker Entry Point 구현 예시

import { renderToReadableStream } from 'react-dom/server';
import App from './App';

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);

    // React 18/19 Web Stream API를 사용하여 에지에서 스트리밍 렌더링
    const stream = await renderToReadableStream(<App url={url.pathname} />, {
      onError(error) {
        console.error('Streaming SSR Error:', error);
      },
    });

    // HTTP/2 DATA 프레임 스트리밍으로 즉시 반응형 응답 반환
    return new Response(stream, {
      headers: {
        'content-type': 'text/html; charset=utf-8',
        'cache-control': 'no-transform',
      },
    });
  },
};

4. 실전 최적화 팁: Edge Caching과 Selective Hydration

  1. Static Shell 에지 캐싱: 렌더링 셸(Header, Navigation, Layout)은 Cloudflare Workers KV나 Cache API를 활용해 에지에 1차 캐싱해 두고, 동적 RSC 조각만 스트리밍합니다.
  2. 에지 DB 결합 (Hyperdrive / D1): 에지 런타임에서 중앙 데이터베이스(PostgreSQL 등)에 접근할 때 커넥션 풀링 지연을 최소화하기 위해 Cloudflare Hyperdrive를 배치합니다.
  3. 클라이언트 컴포넌트 분리: 'use client' 지시어는 꼭 사용자 인터랙션(onClick, useState)이 필요한 최하단 노드에만 최소한으로 선언합니다.

요약 및 결론

RSC 스트리밍 SSR과 Cloudflare Edge 인프라의 결합은 현대 웹 아키텍처가 지향하는 최고의 성능 조합입니다.

[!NOTE]

  1. Suspense 경계를 적절히 설정하여 페이지 셸(Shell)이 즉시 응답하도록 설계하세요.
  2. Node.js 네이티브 API 대신 Web Standard Stream API (renderToReadableStream)를 사용하여 에지 런타임 호환성을 확보하세요.
  3. Cloudflare Workers를 통해 유저와 가장 가까운 PoP에서 스트리밍하여 체감 TTFB를 극소화하세요.

이 패턴을 도입하면 클라이언트 JS 번들 크기를 획기적으로 줄이면서도 글로벌 유저 모두에게 지연 없는 웹 경험을 제공할 수 있습니다.