본문으로 바로가기

Next.js 캐시는 왜 서버마다 다르게 보일까

2026.08.283분 읽기

서버를 한 대만 쓸 때는 잘 되던 캐시가, 인스턴스를 여러 대로 늘리는 순간 이상하게 동작하는 경우가 있다. 새로고침할 때마다 다른 결과가 보이거나, 방금 무효화한 캐시가 여전히 남아있는 것처럼 보이는 식이다. 원인은 대체로 하나다. Next.js가 캐시를 서버의 로컬 파일시스템에 저장한다는 것.

캐싱이란

한 번 가져온 결과를 저장해뒀다가, 같은 요청이 오면 다시 계산하지 않고 재사용하는 기법이다. 목적은 속도 향상과 서버 부하 감소다.

다만 캐시는 항상 과거 시점의 데이터라는 대가를 진다. 실제 데이터가 바뀌었는데 캐시가 그대로면 오래된 값을 보여주게 된다(stale data). 그래서 캐싱 자체보다 "언제 캐시를 지우고 새로 가져올지" - 즉 무효화 시점을 정하는 게 더 중요한 문제가 된다.

Next.js의 네 가지 캐시 레이어

Next.js는 캐시를 하나로 뭉뚱그리지 않고 네 개의 레이어로 나눠서 관리한다.

레이어캐싱 대상유지 범위
요청 메모이제이션같은 렌더링 사이클 내 중복 fetch 제거요청 1건
데이터 캐시fetch() 결과 자체서버 재시작 전까지 유지
풀 라우트 캐시렌더링된 페이지 전체(HTML + RSC)재검증 전까지 유지
라우터 캐시클라이언트가 방문한 라우트브라우저 세션 동안

이 중 캐시 핸들러가 다루는 건 데이터 캐시와 풀 라우트 캐시 두 가지다. 기본 저장 위치는 서버의 로컬 파일시스템이고, 문제는 바로 여기서 시작된다.

로컬 파일시스템 캐시가 수평 확장에서 깨지는 이유

트래픽이 늘면 서버 한 대로는 감당이 안 된다. 같은 코드를 여러 인스턴스로 복제하고, 로드밸런서가 요청을 나눠 보내는 구조로 넘어간다.

text
요청 → [로드밸런서] → 인스턴스 A / B / C (모두 동일한 코드의 복제본)

서버리스 환경에서는 더 예측하기 어렵다

Vercel 같은 서버리스 환경은 여기서 한 단계 더 나아간다. 트래픽에 맞춰 인스턴스를 실시간으로 만들고 없앤다. 어떤 요청이 어느 인스턴스로 갈지 미리 알 수 없다.

캐시를 각 인스턴스가 자기 로컬 파일시스템에 저장하면

  • 인스턴스마다 캐시 상태가 따로 놀아서, 사용자가 새로고침할 때마다 다른 결과를 볼 수 있다.
  • 방금 뜬 인스턴스는 기존 인스턴스가 쌓아둔 캐시를 아예 볼 수 없다.

캐시가 "공유된 하나의 상태"가 아니라 "인스턴스 개수만큼 따로 존재하는 상태"가 되어버리는 것이다.

해결책: 캐시 핸들러로 외부 공유 스토어 쓰기

캐시 저장소를 로컬 파일시스템 대신 Redis 같은 외부 공유 스토어로 바꾸면, 모든 인스턴스가 같은 캐시를 바라보게 만들 수 있다. Redis는 Next.js 인스턴스들과는 별개로 항상 켜져 있는 서버이기 때문에, 인스턴스가 몇 개든 몇 번을 새로 뜨든 캐시의 기준점이 하나로 유지된다.

설정은 두 파일로 나뉜다. 먼저 Next.js에 기본 인메모리 캐시 대신 직접 만든 핸들러를 쓰라고 알려준다.

jsx
// next.config.js
module.exports = {
  cacheHandler: require.resolve('./cache-handler.js'),
  cacheMaxMemorySize: 0, // 기본 인메모리 캐시 비활성화
}

그리고 실제로 get/set/무효화를 어떻게 처리할지는 핸들러 안에서 직접 구현한다.

jsx
// cache-handler.js
class CacheHandler {
  async get(key) {
    return await redis.get(key)
  }
  async set(key, data) {
    await redis.set(key, JSON.stringify(data))
  }
  async revalidateTag(tag) {
    // 특정 태그의 캐시 무효화
  }
}
module.exports = CacheHandler

정리

캐시가 로컬에 있으면 서버 한 대에서는 문제없이 동작한다. 문제는 인스턴스를 늘리는 순간 드러난다. 인스턴스마다 캐시가 따로 놀면서 사용자에게 일관되지 않은 결과를 보여주게 된다. 캐시 핸들러로 저장소를 Redis 같은 외부 공유 스토어로 옮기면, 인스턴스 수와 무관하게 캐시를 하나의 기준으로 유지할 수 있다.

댓글

입력한 댓글은 수정하거나 삭제할 수 없어요. 또한 허위사실, 욕설, 사칭 등 댓글은 통보없이 삭제될 수 있습니다.

불러오는 중...