Incident Report: Vercel Function Region 300초 타임아웃 (2026-03-07)

Incident Report: Vercel Function Region 300초 타임아웃 (2026-03-07)

작성일
2026년 03월 07일
태그
카테고리
Last edited time
Last updated August 1, 2026
날짜
🚨
P0 장애 — 마케팅 페이지 4개 완전 불능 (300초 타임아웃)
해결: Vercel Function Region을 iad1(버지니아) → sin1(싱가포르)로 변경

개요

항목
내용
날짜
2026-03-07
심각도
P0 (프로덕션 페이지 4개 완전 불능)
영향 범위
마케팅 페이지 4개 + 홈페이지 포함 전체 SSR 페이지 성능 저하
해결 시간
진단 ~3시간, 수정 적용 5분
근본 원인
Vercel Function Region(iad1, 버지니아)과 Supabase DB(sin1, 싱가포르) 간 16,000km 거리

증상

배포 직후(ISR 캐시 비어있는 상태) 아래 4개 마케팅 페이지에서 Vercel 함수 타임아웃(300초) 발생:
페이지
응답 시간
상태
/ko/categories/POPUP
300,236ms
타임아웃
/ko/categories/EXHIBITION
300,388ms
타임아웃
/ko/vocaloid
300,224ms
타임아웃
/ko/comic-world
300,202ms
타임아웃
Suspense fallback(스켈레톤)은 즉시 스트리밍되지만, 실제 데이터 컴포넌트가 300초 동안 응답 못 함.
ISR 캐시가 따뜻해지면 정상 동작 → 간헐적 문제로 오인.

진단 과정

Phase 1: DB 쿼리 자체가 느린가?

결론: 아니다. 로컬에서 프로덕션 DB 직접 연결 시 모든 쿼리 2초 이내 완료.
쿼리 그룹
로컬 실행 시간
POPUP (전체 시뮬레이션)
889ms
EXHIBITION
1,230ms
CONCERT (정상 페이지)
906ms
Vocaloid
611ms
Comic World
475ms

Phase 2: statement_timeout이 작동하는가?

결론: 완전히 무시됨. pgBouncer 트랜잭션 모드에서 SET 명령이 리셋됨.
  • statement_timeout: 3000 설정 후 pg_sleep(10)10.4초에 완료 (타임아웃 미작동)
  • statement_timeout: 15000 설정 후 pg_sleep(20)20.5초에 완료 (타임아웃 미작동)
  • 원인: pgBouncer/Supavisor 트랜잭션 모드에서 트랜잭션 종료 시 SET 명령 리셋

Phase 3: 근본 원인 — Vercel Function Region

🔥
근본 원인 발견! Vercel 함수가 DB와 반대편 대륙에서 실행 중
X-Vercel-Id: icn1::iad1::xxxxx ^^^^ Virginia, USA (미국 버지니아)
  • Vercel Function: iad1 (미국 버지니아)
  • Supabase DB: aws-1-ap-southeast-1 (싱가포르)
  • 거리: ~16,000km, 쿼리당 왕복 300-400ms
마케팅 페이지는 4~5개 순차 DB 쿼리를 실행:
1. 카테고리 조회 ~400ms (본래 <1ms) 2. 상위 이벤트 ID 조회 ~400ms 3. 전체 데이터 JOIN ~400ms 4. 카테고리 맵 ~400ms 5. 원본 콘텐츠 맵 ~400ms = 레이턴시만 합산: ~2,000ms
콜드 스타트 시 TLS 핸드셰이크 + DNS 해석 + TCP 연결 수립이 대륙 간 왕복으로 인해 극도로 느려지고, 여러 페이지 동시 콜드 스타트 시 Supavisor 커넥션 경합으로 300초 타임아웃 도달.

Sentry 트랜잭션 분석

Sentry Discover에서 transaction.duration > 10000 조회 결과:
  • 홈페이지(/:locale): 30,000ms (Sentry 캡 한도) — 여러 건
  • /vocaloid: 30,000ms
  • /comic-world: 20,641ms
  • /events/:slug: 19,382ms
특정 4개 페이지만의 문제가 아닌, 전체 SSR 페이지 성능 이슈 확인.

수정 내역

1. Vercel Function Region 변경 (핵심)

Vercel Dashboard → Settings → Functions → Function Region → Singapore (sin1)
⚠️
vercel.jsonregions 설정은 Next.js SSR/ISR 페이지 라우트에 적용되지 않음. Vercel 대시보드 설정만 유효.

2. client.ts — 무효한 statement_timeout 제거

// Before (무효 — pgBouncer가 무시) const client = postgres(connectionString, { connection: { statement_timeout: 15000 }, }); // After const client = postgres(connectionString, { connect_timeout: 10, idle_timeout: 20, max: 6, prepare: false, // NOTE: pgBouncer/Supavisor 트랜잭션 모드에서 무시됨 });

3. vercel.json 안전장치 추가

{ "regions": ["sin1"], "functions": { "apps/web/.next/server/**": { "maxDuration": 30 } } }

수정 후 결과

페이지
Before (iad1)
After (sin1)
개선
HOME
30,000ms+
3.2s
~10x
POPUP
300,000ms (타임아웃)
1.2s
~250x
EXHIBITION
300,000ms (타임아웃)
0.8s
~375x
VOCALOID
300,000ms (타임아웃)
1.3s
~230x
COMIC_WORLD
300,000ms (타임아웃)
1.2s
~250x
CONCERT
5,400ms
0.5s
~10x
Before: X-Vercel-Id: icn1::iad1::xxxxx (Virginia) After: X-Vercel-Id: icn1::sin1::xxxxx (Singapore) ✅

교훈 (Lessons Learned)

1. Vercel Function Region은 DB와 같은 리전에 두어야 한다

Vercel 프로젝트 생성 시 기본 Function Region이 iad1 (Virginia)로 설정됨. Supabase를 싱가포르에 생성했다면 반드시 대시보드에서 Function Region도 변경해야 한다.

2. Function Region ≠ Edge Network

  • Edge Network: 전세계 PoP에서 캐시 서빙 — 유저와 가장 가까운 곳. 자동 분산.
  • Function Region: SSR 코드가 실행되는 곳 — DB와 가까워야 함.
한국+일본 유저 91%라도, DB가 싱가포르에 있으면 Function도 싱가포르가 최적. ISR 캐시 히트 시 Function 자체가 실행되지 않으므로 유저 체감 영향 없음.

3. pgBouncer 트랜잭션 모드에서 SET 명령은 무시된다

postgres.jsconnection: { statement_timeout } 옵션은 무효. Supavisor 기본 타임아웃(2분)에 의존하거나 SET LOCAL 사용.

4. ISR 캐시가 문제를 숨긴다

ISR(revalidate = 86400)은 캐시가 따뜻하면 문제를 완전히 숨김. 배포 직후에만 증상이 나타나 "간헐적 장애"로 오인하기 쉬움.

5. vercel.json의 regions는 SSR에 적용되지 않는다

vercel.jsonregions 설정은 API Routes에만 유효. Next.js SSR/ISR 페이지 라우트는 Vercel 대시보드 설정만 유효.

타임라인

시간
행동
03-05
마케팅 페이지 300초 타임아웃 최초 인지
03-07 00:00
진단 시작 — 쿼리 타이밍 테스트
03-07 01:00
statement_timeout 무효 확인
03-07 01:30
X-Vercel-Id 헤더에서 iad1 발견 — 근본 원인 식별
03-07 02:00
vercel.json regions가 SSR에 미적용 확인
03-07 02:05
Sentry 조회 — 홈 포함 전체 SSR 영향 확인
03-07 02:10
대시보드에서 Function Region → sin1 변경 + Redeploy
03-07 02:15
전 페이지 1초대 응답 확인 — 해결 완료