Next Caching

이종경·2024년 7월 3일
0

Next, 너 뭐 돼?

목록 보기
7/8
post-thumbnail

Next 13의 App Router부터는 프론트서버의 부담이 많이 늘었다.
이에 캐싱 전략을 적절히 활용하지 않으면 서버가 과부하가 올 수가 있다.
따라서 Next에서는 4가지의 캐싱 전략을 제공한다.

MechanismWhatWherePurposeDuration
Request MemoizationReturn values of functionsServerRe-use data in React Component treePer-request lifecycle
Data CacheDataServerStore data across user requests and deploymentsPersistent (can be revalidated)
Full Route CacheHTML and RSC payloadServerReduce rendering cost and improve performancePersistent (can be revalidated)
Router CacheRSC PayloadServerReduce server requests on navigationUser session or time-based

caching overview

  • Build Time : 서비스를 배포할 때 (배포하기 직전에 압축하거나 등등..)
    Build Time일때 최대한 최적화를 많이 해주면 된다.
  • Request Time : 배포를 한 후에 실제 요청이 사용자로 부터 왔을 때

Request Memoization

request memoization
Next에서는 하나의 페이지에서 동일한 fetch 요청이 여러개 있을 경우,
자동으로 요청을 압축해서 비효율적인 fetch를 최소화한다.

즉, 페이지를 처음에 렌더링 할 때 중복된 요청이 있으면 중복을 제거해주기 때문에, 다음번에 페이지를 방문할 땐 캐시들이 아예 초기화되어 데이터를 새로 불러온다.

  • Duration : 캐시 지속기간
  • Revalidating : 언제 다시 새로운 캐시를 받아 올지
  • Opting out : 이 캐시를 사용하지 않게 설정

Data Cache

페이지와 상관 없이 프론트 서버에서 백엔드 서버로 보낸 요청을 얼마나 오래 캐시할 것인지 설정한다.

기본적으로 캐싱이 되며, 한번 캐싱하면 이 값이 계속 유지 된다.

Revalidating

export async function getFollowingPosts() {
  const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/posts/followings`, {
    next: {
      revalidate: 3600, // 캐시 주기 설정, 1시간 후 새로운 데이터를 받아온다.
      tags: ["posts", "followings"],
    }
  });
  return res.json();
}
  • Time-based Revalidation : 일정 시간이 지나면 자동으로 캐시를 갱신한다.
    예시에 작성된 { revalidate: 3600 }를 적용하면 캐시를 초단위로 적용할 수 있다.

  • On-demand Revalidation : 개발자가 직접 코드로 캐시를 갱신한다.
    예시에 작성된 { tags: ["posts", "followings"] }를 서버에서 revalidateTag("posts")와 같은 함수를 사용하여 revalidate할 수 있다.

Opting out

예시

type Props = {
  pageParam?: number;
};

export async function getPostRecommends({ pageParam }: Props) {
  const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/posts/followings`, {
    next: {
      tags: ["posts", "recommends"], 
    },
    cache: "no-store", // 캐시 사용하지 않음
  });
  return res.json();
}

예시에 작성된 { cache: 'no-store' }를 적용하면 데이터 캐시를 사용하지 않는다.

만약, 라이브러리에서 어떤 서버에 요청을 보내는 경우 그런 요청도 Next는 캐싱을 하는데. 캐시를 사용하지 않으려면 page.tsx 상단에 아래와 같이 작성한다.

export const dynamic = 'force-dynamic'

이렇게 작성하면 해당 페이지에서 보내는 모든 요청을 캐싱하지 않게 설정이 된다.

Full Route Cache

page.tsx를 빌드 타임에 얼마동안 캐시할지 설정한다.

  1. 서버 컴포넌트랑 클라이언트 컴포넌트를 미리 빌드한다.
  2. 페이지에 넘어갈 때마다 미리 빌드한 서버 컴포넌트와 클라이언트 컴포넌트를 제공한다.

페이지 내에 변하는 요소가 하나라도 있다면 다시 캐시를 받아오기 때문에 Full Route Cache가 제대로 동작되려면 페이지에 변하는 요소가 없어야 한다.

즉, 정적인 페이지를 설계할 때 의미있게 사용되는 캐시이다.

  • Duration : 기본적으로 지속된다.
  • Invalidation
    • Data Cache가 수정되면 Full Route Cache도 갱신된다. 즉, cache: no-store 가 페이지 내에 하나라도 존재한다면 캐시되지 않는 부분(매번 새로운 데이터로 갱신)이 있는 것이기 때문에 사실상 Full Route Cache는 의미가 없다.
    • 재배포하게 되면 새롭게 빌드하기 때문에 재배포 될 때 Full Route Cache가 갱신된다.
  • Opting Out: Dynamic Functions(cookies, headers, useSearchParams, searchparams)를 사용하거나 데이터 캐시를 Opting Out하면 Full Route Cache를 Opting Out 할 수 있다.

Router Cache

Next에는 사용자 세션 동안 개별 경로 세그먼트로 분할된 React 서버 컴포넌트 페이로드를 저장하는 메모리 내 클라이언트 측 캐시가 있는데 이를 Router Cache라 한다.

Router Cache는 다른 페이지내 동일한 레이아웃을 갖는다면 해당 레이아웃을 캐싱한다.
router cache

  • Duration: 페이지를 새로고침하기 전까지 계속 유지된다.
    • Statically Rendered: 5분 유지 (Dynamic Functions를 사용하지 않고 Data Cache는 사용하는 경우)
    • Dynamically Rendered: 30초 유지
      동적으로 렌더링 되지만 5분간 캐시를 유지하고 싶다면 컴포넌트에 prefetch={true} 를 추가한다. ex)
  • Invalidation
    • revalidatePath 또는 revalidteTag 사용하는 경우
    • cookie.set 또는 cookie.delete 사용하는 경우
    • router.refresh 사용하는 경우
  • Opting out : Router Cache에서는 Opting out 할 수 없다.

참고
Next + React Query로 SNS 서비스 만들기
Building Your Application: Caching | Next.js텍스트

profile
작은 성취들이 모여 큰 결과를 만든다고 믿으며, 꾸준함을 바탕으로 개발 역량을 키워가고 있습니다

0개의 댓글