AI 생성프론트엔드 하는 사람이라면 — 깃허브는 페이지 이동을 이렇게 ‘즉시’로 만들었다 (4%→22%)

깃허브, 이슈 페이지 '즉시 이동' 4%→22%로 끌어올린 방법 — 클라이언트 사이드 캐싱·프리페칭·서비스워커

🤖 AI 생성 콘텐츠 — 이 글은 AI가 자료를 수집하고 초안을 작성했으며, 발행 전 누슘 운영자가 검수했습니다.

깃허브가 이슈(Issues) 페이지의 내비게이션을 클라이언트 사이드 중심으로 다시 설계해, 화면 이동이 즉시 이뤄지는 비율을 4%에서 22%로 끌어올렸다. 캐싱·프리페칭·서비스워커가 핵심 조합이다.

깃허브가 이슈 페이지를 오갈 때 느껴지는 지연을 줄이기 위해 내비게이션 아키텍처를 클라이언트 사이드 중심으로 재설계했다. 2026년 7월 22일 InfoQ가 전한 바에 따르면, 깃허브 엔지니어링팀은 클라이언트 사이드 캐싱, 예측 프리페칭(predictive prefetching), 서비스워커 기반 요청 처리를 도입해 ‘즉시 이동’이 일어나는 비율을 4%에서 22%로 끌어올렸다. 반복되는 네트워크 요청과 클라이언트 초기화 때문에 생기던 지연을 줄인 게 요점이다.

목차

  • 무엇을 바꿨나: ‘로컬 퍼스트’로의 전환
  • stale-while-revalidate와 서비스워커는 어떻게 동작하나
  • 실제 지연은 얼마나 줄었나
  • 이 패턴, 내 서비스에도 그대로 쓸 수 있을까

무엇을 바꿨나: ‘로컬 퍼스트’로의 전환

깃허브 이슈 사용자는 이슈 상세·목록·연관 뷰 사이를 끊임없이 오간다. 이때 이미 한 번 받아온 정보를 매번 백엔드에서 다시 가져오던 구조가 지연의 원인이었다. 해법은 ‘로컬 퍼스트(local-first)’다. 브라우저에 있는 데이터를 즉시 화면에 그려주고, 더 최신 정보는 백그라운드에서 따로 받아오는 방식이다.

이를 위해 깃허브는 여러 겹의 클라이언트 저장소를 함께 썼다.

저장 계층 역할
IndexedDB 브라우저에 데이터를 영구 저장(세션이 끝나도 유지)
인메모리(in-memory) 캐시 활성 세션 중 자주 쓰는 데이터를 빠르게 제공
서비스워커 브라우저 요청을 가로채 로컬 자원 우선 확인

여기서 IndexedDB는 브라우저 안에 내장된 키-값/객체 데이터베이스로, 새로고침하거나 창을 닫았다 열어도 데이터가 남는 영구 저장소다. 인메모리 캐시는 그보다 휘발성이지만 접근이 훨씬 빠르다. 둘을 조합해 “빠르지만 잠깐 유지되는 것”과 “느리지만 오래 남는 것”을 층으로 나눈 셈이다.

깃허브 이슈의 다층 클라이언트 사이드 캐시 아키텍처 다이어그램

stale-while-revalidate와 서비스워커는 어떻게 동작하나

캐싱 모델은 stale-while-revalidate(오래된 걸 먼저 보여주고, 그동안 갱신) 방식을 따른다. 사용자가 이전에 본 콘텐츠에 다시 들어가면, 서버 응답을 기다리지 않고 로컬에 저장된 데이터를 곧바로 표시한다. 그런 다음 백그라운드에서 동기화를 돌려 캐시를 최신 상태로 맞춘다. “일단 보여주고 뒤에서 조용히 업데이트”인 셈이다.

여기에 깃허브는 두 가지를 더 얹었다.

  1. 프리히팅(preheating): 사용자가 요청하기 전에 필요할 법한 데이터를 미리 준비해 캐시를 채운다. 실제 내비게이션 패턴을 근거로 “다음에 이걸 볼 확률이 높다”는 항목을 앞당겨 로드한다.
  2. 서비스워커 요청 가로채기: 서비스워커가 브라우저 요청을 가로채 로컬에 자원이 있는지 확인한다. 있으면 즉시 렌더하고 뒤에서 갱신하며, 없거나 오래된 데이터는 평소처럼 백엔드 경로로 넘긴다.

결국 이 설계의 본질은 응답성과 데이터 신선도 사이의 균형 잡기다. 모든 상호작용마다 최신 서버 상태를 기다렸다 그리는 대신, 일부 콘텐츠는 먼저 보여주고 비동기로 업데이트해 대기 시간을 줄이면서도 백엔드와의 정합성을 유지한다.

실제 지연은 얼마나 줄었나

깃허브는 개선 효과를 하나의 평균값이 아니라 지연 분포(latency distribution) 전체로 측정했다. 백분위(percentile)별로 보면 다음과 같다.

지표 개선 전 개선 후
P10 약 600ms 약 70ms
P25 약 800ms 약 120ms
중앙값(median) 약 1,200ms 약 700ms
P75 약 1,800ms 약 1,400ms
P90 약 2,400ms 약 2,100ms

여기서 P10은 “가장 빠른 10% 요청” 구간을 뜻하는데, 이 구간이 600ms에서 70ms로 극적으로 줄었다. 즉 캐시가 잘 맞는 경우엔 체감상 ‘즉시’에 가까워졌다는 뜻이다. 반면 P90처럼 무거운 꼬리(tail) 구간은 상대적으로 개선 폭이 작다 — 캐시가 안 맞아 결국 서버까지 가야 하는 요청이 여기 몰리기 때문이다.

깃허브의 알렉산더 렐리디스(Alexander Lelidis) 시니어 소프트웨어 엔지니어는 “지연은 단순한 지표가 아니라 맥락 전환(context switch)“이라고 표현했다. 0.6초의 멈칫함이 개발자의 집중 흐름을 끊는다는 관점이다.

깃허브 이슈 내비게이션 백분위별 지연 개선 전후 비교 그래프

이 패턴, 내 서비스에도 그대로 쓸 수 있을까

주의할 점도 함께 공유됐다. 한 참여자(BareStack)는 “프리페칭은 데이터 그래프가 작고 읽기 위주일 때(이슈처럼) 이득“이라며, 읽기·쓰기 충돌이 많은 큰 그래프에서는 프리페칭한 뷰가 착지 후 다시 요청될 수 있다고 지적했다. 그러면서 재사용 가능한 핵심 패턴은 프리페칭 그 자체가 아니라 “셸(shell) 먼저 렌더 + 캐시 적중 시 하이드레이션“이라고 정리했다.

정리하면, 깃허브가 보여준 건 특정 마법 같은 기술 하나가 아니라 로컬 퍼스트 + 다층 캐시 + stale-while-revalidate라는 조합을, 읽기 중심 워크플로에 정교하게 맞춘 설계다. 내 서비스에 적용하려면 먼저 “우리 데이터가 읽기 위주인가, 쓰기 충돌이 잦은가”부터 따져봐야 한다는 뜻이다.

자주 묻는 질문 (FAQ)

Q. 여기서 ‘즉시 이동(instant navigation)’이란 정확히 뭘 뜻하나? A. 페이지를 이동할 때 서버 왕복을 기다리지 않고 로컬 캐시로 화면이 곧바로 뜨는 경험을 말한다. 깃허브는 이 비율을 전체의 4%에서 22%로 늘렸다.

Q. stale-while-revalidate가 뭔가? A. ‘오래됐을 수 있는 캐시를 일단 보여주고, 그 사이 백그라운드에서 최신 데이터로 갱신’하는 캐싱 전략이다. 대기 시간을 줄이면서도 데이터를 최신으로 맞추는 절충안이다.

Q. IndexedDB와 인메모리 캐시를 왜 둘 다 쓰나? A. IndexedDB는 창을 닫아도 남는 영구 저장소지만 접근이 상대적으로 느리고, 인메모리 캐시는 빠르지만 세션이 끝나면 사라진다. 둘을 층으로 나눠 속도와 지속성을 동시에 챙긴다.

Q. 이 방식은 모든 웹앱에 좋은가? A. 아니다. 읽기 위주에 데이터 그래프가 작은 워크플로(이슈 목록 탐색 등)에 특히 잘 맞는다. 읽기·쓰기 충돌이 잦은 서비스라면 프리페칭 이득이 줄 수 있어 ‘셸 먼저 렌더 + 캐시 하이드레이션’ 패턴부터 검토하는 게 안전하다.

마치며

‘빠른 앱’은 결국 네트워크를 얼마나 덜 기다리게 만드느냐의 문제다. 깃허브 사례는 서버 성능을 갈아 넣기보다 작업이 일어나는 위치를 클라이언트로 옮기고, 캐시를 층으로 설계하는 접근이 체감 속도에 얼마나 크게 작용하는지 보여준다. 실제로 프론트엔드에서 IndexedDB나 서비스워커로 캐시 계층을 짜본 경험이 있다면, 어떤 함정에 빠졌고 어떻게 빠져나왔는지 댓글로 나눠 달라. 다음 글에서는 서비스워커 캐싱의 흔한 실수와 무효화(invalidation) 전략을 더 파고들어 보겠다.

참고자료


태그: #GitHub #프론트엔드 #캐싱 #IndexedDB #서비스워커 #웹성능 #로컬퍼스트 #아키텍처

이 게시판의 글

개발 뉴스