TL;DR
플러터 웹뷰 위 Next.js 15 서비스에서 2주간 4번의 CPU 사건. "Next/Image의 효과는 인프라가 결정한다"로 수렴. 분산 CDN 전제가 약한 셀프호스팅(Cloud Run)에서는 자산 종류별로 최적화 적용 여부를 분리하는 방향 검토 중. 5/15 Dockerfile 권한 결함 → 5/19 /_next/image 부하(응급 unoptimized) → 5/20~26 Cloud CDN 도입 → 5/28 AVIF 인코딩+업로드 사진 동시 변환이 잔존 원인.
아파트케어2 사용자 앱은 플러터 네이티브 셸 안에서 Next.js 웹앱이 웹뷰로 동작하는 구조입니다. 서버 구성은 GCP asia-northeast3 Cloud Run + 그 앞에 HTTP(S) LB + Cloud CDN(5/28 활성). Cloud Run 1개 인스턴스는 평소 CPU 2 / 메모리 1Gi / 동시 요청 80 한계로 설정되어 있습니다.
CRA처럼 브라우저에서만 렌더링하는 SPA는 서버가 정적 파일만 보내 CPU 부담이 거의 없습니다. 반면 Next.js 15 App Router는 같은 요청에 서버가 더 많은 일을 합니다 — SSR, 미들웨어, 이미지 최적화(Sharp 변환), fetch 캐싱. 즉 서버 CPU가 일정 부분 드는 것은 설계에 내재된 특성이고, 줄여야 할 대상은 불필요하게 많이 드는 경우와 한 인스턴스에 과도 적재되는 경우입니다.
본 글은 이미지 변환 CPU(/_next/image 경로) 만 다룹니다. SSR 자체의 부하는 별도 트랙(논의 단계)입니다.
Cloud Run은 minScale 1로 평소 1개가 상시 동작합니다. 스케일아웃에 지연이 있고, 그 사이 들어온 무거운 요청(AVIF 인코딩·대용량 리사이즈)이 단일 인스턴스 CPU를 포화시킵니다. CDN은 이를 크게 완화하지만 캐시에 없는 신규 요청(첫 변환)은 여전히 origin에 도달합니다.
| 항목 | v2front (메인 아파트아이) | webapp-aptcare2-user |
|---|---|---|
| 인프라 | GAE Flex (cpu 1 / mem 1.6GB) | Cloud Run (cpu 2 / mem 1Gi) |
| Next.js | 14.2.35 | 15.3.8 |
| 라우터 | Pages Router | App Router |
| 기본 렌더링 | CSR 위주 | SSR 기본 |
| 정적 자산 | assetPrefix로 별도 CDN | 자체 서버 직접(5/28 CDN 전) |
| 이미지 | img 134파일·370회, next/image 0건 | Image 42파일·59회 → /_next/image 변환 |
| 운영 이력 | 동일 CPU 이슈 없음 | 본 시리즈 4건 |
v2front는 정적 자산을 assetPrefix로 별도 CDN에서 서빙하고 이미지는 img 직접 사용이라 /_next/image Sharp 변환 경로가 아예 없습니다. 본 프로젝트는 App Router 기본 동작에 올라타 있고 CDN도 5/28까지 없어, 정적 자산·이미지·SSR HTML이 모두 단일 인스턴스로 도달했습니다.
| 시점 | 트리거 | 진단 | 처방 | 사후 평가 |
|---|---|---|---|---|
| 5/15 | 단지 오픈+알림톡 | Dockerfile EACCES → 45회 재시도 → 인스턴스 27개 | COPY --chown + .next/cache 사전 생성 | 정확. 일괄 해소 |
| 5/19 | /bridge 진입 132명 | /_next/image 변환을 Cloud Run이 직접 처리 | unoptimized: true 전역 | 응급 효과, 정적 자산 최적화 일시 중단 |
| 5/20~26 | APTI-CPU 후속 | 인스턴스 로컬 캐시 한계 | Cloud CDN + 30일 TTL + unoptimized 제거 | CDN 성공. 변환 비용은 후속 보강 |
| 5/28 | CDN 적용+리비전 배포 동시 | cold+콜드스타트+단일 인스턴스 + 잔존 4건 | AVIF 제거(적용 완료) + 업로드 선택적 우회(논의 중) | AVIF 제거 후 후속 72.5h 안정 확인 |