회사에서 GQL을 쓰고 있는데 사용 과정에서 Fragment와 Apollo Client의 InMemoryCache의 관계에 대해 알아보고 정리했던 자료를 공유해 봅니다! 회고는 아직 작성중이에요ㅠㅠ 작성 완료 후 바로 올리겠습니다!
요약 :
캐시 히트율(cache hit rate)은 _“총 요청 수 중 캐시만으로 응답한 비율”_을 뜻한다. Apollo Client의
InMemoryCache는 GraphQL 응답을 정규화해 저장하고, 동일 데이터를 요청할 때 네트워크 대신 캐시에서 즉시 반환한다.
Fragment를 일관되게 사용하면 동일한 필드 집합으로 캐시에 저장·조회가 이뤄져 캐시 히트율이 높아진다. 반대로 서로 다른 필드 구성이면 히트율이 떨어지거나 추가 네트워크 요청이 발생한다.
1. 캐시 히트율이란?
용어 정의 그래프큐엘/아폴로 맥락
| Cache Hit | 클라이언트가 요청한 데이터를 캐시에서 완전히 찾아 바로 반환한 경우 | useQuery·watchQuery 등이 캐시에서 필요한 모든 필드를 찾았을 때 |
| Cache Miss | 캐시에 일부 또는 전혀 없어서 네트워크로 다시 요청한 경우 | 캐시가 필드를 완전히 충족 못 하면 Apollo가 네트워크 요청(또는 오류) 발생 |
| Cache Hit Rate | Hit ÷ (Hit + Miss) | 값이 높을수록 네트워크 왕복이 줄어 애플리케이션이 빠르고 효율적 |
2. InMemoryCache가 히트율을 높이는 방식
- 정규화(Normalization)같은 엔티티가 다른 쿼리에서도 재사용되면 동일 캐시 레코드를 가리키므로 중복 저장이 없다.
- 응답 객체를 __typename:id 키로 평탄한 테이블 형태로 저장한다.
- 필드 병합(Merging)이후 요청이 같은 필드를 요구하면 hit가 난다.
- 동일 객체의 새 필드가 들어오면 기존 캐시 엔트리에 병합된다.
- fetchPolicyno-cache 등을 쓰면 히트율 계산 자체가 의미 없어진다.
- cache-first (기본값)는 캐시가 충족되면 네트워크를 건너뛴다.
3. Fragment가 히트율에 미치는 영향
3-1. 왜 Fragment가 중요한가?
Fragment는 재사용 가능한 필드 묶음 이다.
동일 Fragment를 여러 쿼리에 사용하면 항상 같은 필드 집합이 캐시에 저장·조회된다.
- 결과: 두 번째부터는 캐시가 모든 필드를 이미 갖고 있어 hit가 발생.
3-2. 서로 다른 Fragment가 히트율을 깎는 사례
fragment BasicUser on User { id name }
fragment EmailUser on User { id name email }
- 목록 페이지 → ...BasicUser 로 사용자 1-100을 조회
- 캐시에 id·name만 저장됨.
- 주소록 페이지 → ...EmailUser 로 같은 사용자 요청
- 캐시는 email 필드가 없어 miss 발생, 네트워크 추가 호출.
Apollo 문서도 필드 집합이 달라지면 “캐시 hit rate가 크게 줄어든다” 고 지적
3-3. 효율 높이는 전략
- 계층적 Fragment 구성
- 목록은 UserList, 상세는 UserDetail 사용
- 공통 부분(UserBase) 은 항상 hit → 기본 정보 렌더링이 즉시 가능
- 때문에 Fregment를 계층적으로 구성하는게 성능 측면에서 유리함
- 계층 구성을 통해 Fregemrnt로만 이루어진 반환된 결과 객체 자체가 캐싱되기 때문에 캐시 hit → 성능적으로 이점 챙김
- fragment UserBase on User { id name } fragment UserList on User { ...UserBase } fragment UserDetail on User { ...UserBase email phone }
- 필드 통제 & fetchPolicy
- 목록 컴포넌트에서 **email**이 정말 필요 없다면 요청하지 않는다.
- 상세 컴포넌트는 cache-and-network 등으로 먼저 캐시를 쓰고 부족분만 보충.
- readFragment / writeFragment 활용
- 특정 객체를 ID 기반으로 직접 읽거나 써서 필요 필드만 갱신 가능.
- UI는 즉시 업데이트되고, 네트워크 왕복 없이 히트율 유지.
- readFragment / writeFragment 활용 사례
// Fragment로 캐시 읽기 const userData = client.readFragment({ id: 'User:123', fragment: gql` fragment UserInfo on User { id name email } ` }); // Fragment로 캐시 쓰기 client.writeFragment({ id: 'User:123', fragment: gql` fragment UserInfo on User { id name email } `, data: { id: '123', name: 'Updated Name', email: 'updated@example.com' } }); - Fragment를 사용해 캐시와 상호작용할 때는 readFragment, writeFragment 메서드를 사용
4. 히트율 최적화를 위한 체크리스트
체크포인트 설명
| Fragment 일관성 | 동일 엔티티에 대해 가능한 한 같은 Fragment를 재사용 |
| 과도한 필드 요구 방지 | 목록 페이지에 상세 필드 포함 X |
| keyFields, keyArgs 설정 | 잘못된 키 설정은 중복 엔티티 생성 → 히트율 저하 |
| fetchPolicy 조정 | cache-first(기본), 필요 시 cache-and-network |
| 캐시 검사 도구 | Apollo DevTools → “cache” 탭으로 엔티티·필드 저장 여부 확인 |
'GraphQL-Apollo_Client' 카테고리의 다른 글
| [Apollo Client] Next.js에서 2개의 Apollo Client 운영하기 (feat. Codegen) (0) | 2025.12.14 |
|---|---|
| [Apollo Client] 실제 API를 사용하는 것처럼 데이터 Mocking 하기 (0) | 2025.11.09 |