Next Image DiceBear SVG OOM
이 문제 해결 노트는 3be71e0에 의해 도입되고 37adf6e에 의해 수정된 2026년 5월 회귀를 다룹니다.
증상
- 많은 아바타 카드를 렌더링한 후 학생 또는 교직원 목록 페이지에서 프런트엔드 창에 충돌이 발생합니다.
- 포드 메모리가 256MiB 한도에 가까워지고 컨테이너가
OOMKilled상태가 됩니다. next/image를 통해 DiceBear 아바타를 렌더링하는 페이지 주변에 오류가 클러스터됩니다.
진단
현재 아바타 호출 지점는 lumie-frontend/src/shared/ui/PersonCardGrid.tsx에서 확인하세요. 이제 DiceBear 아바타가 unoptimized로 렌더링됩니다.
<Image
src={getAvatarUrl(item.avatarSeed, 80)}
width={40}
height={40}
unoptimized
/>
이는 lumie-frontend/next.config.ts에 남겨진 경고와 일치합니다. DiceBear SVG는 Sharp 기반 최적화 프로그램을 거치지 않아야 합니다.
근본 원인
DiceBear SVG 아바타를 최적화할 수 있도록 next.config.ts에서 3be71e0 images.dangerouslyAllowSVG 활성화를 커밋합니다. 이로 인해 Next.js의 기본 SVG 블록이 제거되었지만 최적화 파이프라인을 통해 각 아바타도 전송되었습니다.
카드 그리드 페이지에서 PersonCardGrid는 한 번에 많은 아바타를 렌더링했습니다. SVG 최적화가 허용되면 Next.js는 처리 중인 각 SVG를 래스터화하고 다시 인코딩했습니다. 37adf6e 커밋은 관찰된 결과를 문서화합니다. 포드 RSS는 256MiB 제한에 대해 약 254MiB로 급증했습니다.
0652e18는 나중에 AVIF를 제거하고 이미지 크기를 제한하여 일반 이미지 최적화 프로그램 로드를 줄였지만 이는 DiceBear 근본 원인이 아니라 후속 최적화였습니다.
수정
내구성 있는 수정 사항은 현재 존재하는 조합입니다.
lumie-frontend/src/shared/ui/PersonCardGrid.tsx는unoptimized를 사용하여 DiceBear 아바타를 렌더링합니다.lumie-frontend/next.config.ts는 더 이상dangerouslyAllowSVG를 활성화하지 않습니다.- 정적 랜딩 미디어는 더 무거운 런타임 변환에 의존하는 대신 사전 최적화된 WebP 자산을 통해 별도로 처리됩니다.
예방 및 검증
- 원격 DiceBear 아바타를 이미 최적화된 SVG 자산으로 취급합니다. 새로운 아바타 구성요소는
PersonCardGrid와 동일한unoptimized패턴을 따라야 합니다. - 렌더링 경로가 프로세스 내 최적화 프로그램에서 벗어나 변경되지 않는 한 DiceBear용
images.dangerouslyAllowSVG를 다시 도입하지 마세요. - 소스의 현재 가드레일을 확인합니다.
lumie-frontend/src/shared/ui/PersonCardGrid.tsx에는 DiceBear 아바타 이미지에unoptimized가 포함되어 있습니다.lumie-frontend/next.config.ts에는 SVG 최적화가 비활성화된 이유를 설명하는 설명이 포함되어 있습니다.
운영 세부사항
이 문제는 아바타 제공 실패가 아니라 메모리 압박 실패였습니다. DiceBear endpoint는 SVG를 계속 반환했지만, SVG 최적화가 켜지면서 frontend pod가 비싼 변환 지점이 되었습니다.
중요한 구분은 다음과 같습니다.
| 경로 | 동작 | 메모리 위험 |
|---|---|---|
| 브라우저가 DiceBear SVG를 직접 렌더링 | SVG를 브라우저가 가져와 그립니다. | Next.js 서버에는 낮습니다. |
next/image가 DiceBear SVG를 최적화 | Next.js가 각 아바타를 가져와 rasterize하고 다시 encode합니다. | list page에서 많은 아바타를 렌더링할 때 높습니다. |
| Static WebP media | 미리 준비된 asset으로 제공됩니다. | 제한적이고 예측 가능합니다. |
page가 grid 또는 roster 크기가 커진 뒤에만 죽는다면 React component tree leak을 의심하기 전에 image optimizer request 수를 먼저 확인합니다.
복구 절차
- pod 종료 사유가
OOMKilled인지 확인하고 memory limit을 기록합니다. - 실패 page가 많은 DiceBear URL을
next/image로 렌더링하는지 확인합니다. next.config.ts에서dangerouslyAllowSVG가 켜져 있지 않은지 확인합니다.- DiceBear avatar
Imagecall site에unoptimized를 추가하거나 이미 그 처리를 하는 shared avatar component로 대체합니다. - 재배포 후 가장 큰 현실적인 roster 또는 staff grid로 재현합니다.
검증 증거
닫기 전에 다음을 기록합니다.
- 이전과 현재 pod memory ceiling.
- 재현에 사용한 가장 큰 roster 또는 grid 크기.
- DiceBear SVG URL에 대해
/_next/image요청이 더 이상 만들어지지 않는지. - 반복 navigation 후 pod RSS가 memory limit 아래에 머무는지.
- static image optimization 설정은 SVG가 아닌 media에 여전히 맞는지.
앞으로 안전한 변경
SVG 최적화 재검토는 다음 중 하나가 참일 때만 합니다.
- DiceBear avatar가 request path 밖에서 PNG 또는 WebP로 pre-render됩니다.
- avatar가 bounded raster asset을 반환하는 service 뒤에 cache됩니다.
- frontend pod memory limit과 image optimizer concurrency를 의도적으로 재산정하고 load test했습니다.
그 전까지 unoptimized는 avatar 계약의 일부이지 단순한 표시 옵션이 아닙니다.