Skip to content

Google 장소 사진 이중 최적화로 Vercel Image Transformation 한도 소진 #126

Description

@minbros

배경

백엔드는 Google Places 사진을 요청할 때 고정된 크기로 가져오고 있다.
하지만 계획 장소 카드에서는 해당 사진을 다시 next/image로 렌더링하면서 Vercel Image Optimization을 한 번 더 거친다.

  • 운영 환경의 /_next/image 요청에서 402 Payment Required 발생
  • 응답 헤더: X-Vercel-Error: OPTIMIZED_IMAGE_REQUEST_PAYMENT_REQUIRED
  • Vercel Image Transformation 월 한도 소진 확인

현재 동작

백엔드

  • Google 사진을 고정 크기로 요청
  • 프론트엔드에 Google 사진 URL을 전달

프론트엔드

계획 장소 사진:

<Image
  src={resolvedPhotoUrl}
  alt={place.title}
  fill
  sizes="96px"
  className="object-cover"
/>

관련 위치:

  • src/app/(main)/plan/_components/itinerary/PlanPlaceCard.tsx
  • src/hooks/usePlanPlaceCardPhoto.ts
  • src/lib/places/place-photo-refresh.ts
  • next.config.ts

현재 next.config.ts에서 deviceSizes, imageSizes, qualities를 별도로 제한하지 않아 Next.js 기본 이미지 크기 목록을 사용한다.

설치된 Next.js 16.2.1 기준으로 fill + sizes="96px"는 다음 15개 폭 후보를 srcset에 생성한다.

32, 48, 64, 96, 128, 256, 384,
640, 750, 828, 1080, 1200, 1920, 2048, 3840

브라우저가 모든 후보를 요청하는 것은 아니지만, 화면 크기와 DPR에 따라 서로 다른 w 값이 요청된다. Vercel의 원격 이미지 캐시 키에는 url, w, q, Accept가 포함되므로 각 조합의 cache MISS/STALE가 별도 transformation으로 집계된다.

문제점

1. 불필요한 이중 리사이징

백엔드가 이미 고정 크기로 제한한 사진을 Vercel이 다시 여러 폭으로 변환한다. 고정된 96px 장소 썸네일에서 생성되는 후보 수에 비해 실질적인 최적화 이득이 작을 수 있다.

2. Google 사진 URL 갱신으로 인한 캐시 분산

handlePlacePhotoImageError는 이미지 로딩 실패 시 사진 URL을 갱신한다.

Vercel 402도 이미지 오류로 처리되므로 다음 흐름이 발생할 수 있다.

  1. 기존 Google URL로 /_next/image 요청
  2. Vercel 402 반환
  3. 프론트엔드에서 Google 사진 URL 갱신
  4. 변경된 URL로 새로운 /_next/image 요청
  5. 새로운 원본 캐시 키가 생성되지만 한도 초과로 다시 실패

백엔드에서 요청하는 픽셀 크기가 동일하더라도 절대 URL이 바뀌면 Vercel에서는 별도 원본으로 취급한다.

3. 이중 압축 가능성

Google에서 이미 리사이징·압축된 사진을 Vercel이 WebP 품질 75로 다시 변환한다. 원본이 작은 경우 전송량 절감보다 추가 압축에 따른 화질 저하가 커질 수 있다.

4. 사용자 영향

  • 계획 장소 사진이 표시되지 않고 alt 텍스트 또는 fallback이 노출됨
  • 이미지 실패 시 불필요한 사진 URL 갱신 요청 발생
  • 새로운 사진 조합이 계속 생성되어 Image Transformation 사용량 증가

개선 방향

고정 크기 장소 썸네일에는 아래 방향을 우선 검토한다.

권장안: Google 장소 사진의 Vercel 최적화 우회

  • 백엔드 Google 사진 크기를 실제 표시 크기 × DPR 2 수준으로 고정
    • 96px 표시 기준 약 192px 또는 256px
  • 계획 장소 사진에 unoptimized 적용 또는 네이티브 img 사용
  • CSS에서는 기존과 같이 96×96px로 표시
  • Google 사진 URL을 가능한 한 안정적으로 유지
  • Vercel 402와 원본 Google 사진 오류를 구분하여, 최적화 서비스 오류에서는 사진 URL을 갱신하지 않도록 처리

대안: Vercel 최적화 유지

  • 고정 썸네일에는 fill + sizes 대신 명시적인 width={96}, height={96} 사용
  • imageSizes를 실제 필요한 1x/2x 폭으로 제한
  • 예: 96px, 192px
  • 사진 URL 갱신으로 캐시 키가 계속 변경되지 않도록 원본 URL 안정화

완료 조건

  • 계획 장소 썸네일이 불필요한 15개 폭 후보를 생성하지 않는다.
  • 고정 크기 Google 사진에 대해 Vercel transformation이 발생하지 않거나 필요한 1x/2x 조합으로 제한된다.
  • Vercel 최적화 402 오류가 Google 사진 URL 갱신을 유발하지 않는다.
  • DPR 1 및 DPR 2 환경에서 96×96px 썸네일 화질이 적절하다.
  • 사진 로딩 실패 fallback 동작이 유지된다.
  • 변경 전후 Vercel Image Optimization 사용량 또는 네트워크 요청을 비교한다.

참고

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions