Next.js + TanStack Query, 전역 QueryClient 사용은

by DD
4개월 전
조회수 144

Next.js SSR 환경에서 `QueryClient`를 전역 변수로 사용하면서 메모리 누수(Memory Leak)가 발생, 서버 재시작 빈도가 증가함

Chrome DevTools의 Heap Snapshot을 활용하여 메모리 누수의 원인을 분석, QueryClient 인스턴스 공유가 문제임을 확인

`QueryClient`를 요청별로 생성하도록 수정하여 메모리 누수 문제를 해결, 서버의 안정성을 확보함

공식 문서의 권장 사항을 따르지 않은 구현 방식이 문제의 원인이었으며, 점진적 마이그레이션 과정에서 발생

메모리 누수는 프로덕션 환경 모니터링정기적인 성능 점검을 통해 조기에 발견해야 함을 강조

Next.js SSR 환경에서의 메모리 누수 원인 분석

본문에서는 Next.js SSR 환경에서 `QueryClient` 인스턴스 공유로 인해 메모리 누수가 발생한 원인을 심층 분석한다. Next.js 서버는 24/7 운영되며, 각 요청마다 새로운 컴포넌트 트리를 생성한다. 하지만 전역으로 선언된 `QueryClient`는 모든 요청에서 공유되므로, 각 요청의 데이터가 격리되지 않고 누적된다.

API 응답 데이터: 상품 상세 페이지 API 응답 데이터가 GC되지 않고 힙에 유지

Query Key: TanStack Query가 캐시를 식별하는 키가 GC 대상에서 제외

타 클라이언트 데이터: 다른 사용자의 요청 데이터까지 힙에 남아있음

결과적으로, 서버 재시작 전까지 메모리 사용량이 지속적으로 증가하며, 이는 서버 성능 저하 및 OOM(Out of Memory)으로 이어진다.

Chrome DevTools Heap Snapshot을 활용한 디버깅

저자는 Chrome DevTools의 Heap Snapshot을 사용하여 메모리 누수 원인을 효과적으로 파악했다. 힙 스냅샷은 특정 시점의 힙 메모리 상태를 기록하며, 이를 통해 “어떤 객체가 얼마나 많은 메모리를 차지하는지”와 “왜 해제되지 않는지”를 시각적으로 확인할 수 있다.

개발 서버 실행: `--inspect` 옵션을 사용하여 Next.js 서버를 디버그 모드로 실행

힙 스냅샷 촬영: Memory 탭에서 힙 스냅샷을 촬영하여 현재 메모리 상태를 저장

스냅샷 비교 분석: 여러 스냅샷을 비교하여 메모리 증가 패턴을 파악

특히, String과 Object의 증가를 통해 API 응답 데이터와 Query Key가 GC되지 않음을 확인했다.

QueryClient 인스턴스 관리 방식 개선

메모리 누수 문제를 해결하기 위해 저자는 `QueryClient` 인스턴스 생성 방식을 변경했다. 기존에는 전역 변수로 `QueryClient`를 생성했지만, 이제는 각 요청마다 새로운 인스턴스를 생성하도록 수정했다.

`useState` 활용: `_app.tsx`에서 `useState`를 사용하여 각 요청마다 새로운 `QueryClient` 인스턴스 생성

요청별 격리: 각 요청은 독립적인 `QueryClient`를 가지므로, 데이터 격리 보장

GC에 의한 자동 해제: SSR 렌더링 완료 후, 더 이상 참조되지 않는 객체는 GC에 의해 자동 제거

이러한 변경을 통해 메모리 누수 문제를 해결하고, 서버의 안정성을 확보했다.

점진적 마이그레이션의 함정과 공식 문서의 중요성

본문에서는 점진적 마이그레이션 과정에서 발생할 수 있는 함정을 지적하고, 공식 문서의 중요성을 강조한다. 펫프렌즈는 Vue.js에서 Next.js로 점진적으로 마이그레이션하는 과정에서, 기존 코드베이스를 그대로 유지한 채 SSR을 도입했다. 이로 인해 `QueryClient`가 전역 변수로 생성되어 메모리 누수가 발생했다.

점진적 마이그레이션의 함정: 기존 코드 재사용에 집중하다가 새로운 환경(SSR)에 맞는 패턴을 간과

공식 문서의 중요성: TanStack Query와 Next.js 공식 문서에서 SSR 환경에서의 `QueryClient` 사용법을 명확히 안내

프로덕션 모니터링: 로컬 환경에서는 발견하기 어려운 메모리 누수를 프로덕션 환경 모니터링을 통해 조기에 발견

결과적으로, 새로운 기술을 도입할 때는 공식 문서를 꼼꼼히 확인하고, 기존 코드와의 호환성뿐만 아니라 새로운 환경에 맞는 설계를 고려해야 한다.

개선 결과 및 운영 안정성 확보

QueryClient 개선 후, 펫프렌즈는 메모리 사용량 감소서버 운영 안정성 확보라는 긍정적인 결과를 얻었다. 개선된 시스템은 메모리 사용량이 일정 범위 내에서 안정적으로 유지되며, 서버 재시작 빈도가 감소했다.

평균 메모리 사용률: 9-10%로 안정적으로 유지

최대 메모리 사용률: 16% (피크 시간대 기준)

서버 재시작 횟수: 주 1회 → 0회

운영 안정성 확보: 메모리 모니터링 및 수동 재시작 작업 제거, 안정적인 서버 응답 속도 유지, 예측 가능한 인프라 리소스 계획 수립 가능

이러한 개선을 통해 펫프렌즈는 더욱 안정적인 서비스를 제공할 수 있게 되었다.

Next.js에서 QueryClient를 전역변수로 사용해도 될까요?

댓글 0

첫 번째 댓글을 남겨보세요!