Vercel 빌드시 발생한 sharp 라이브러리 에러
Fatal glibc error malloc.c:3211
서론
프로젝트를 Vercel
에서 빌드할 때, 로컬에선 발생하지 않던 메모리 관련 오류가 발생했습니다.
마주친 에러들
- Fatal glibc error: malloc.c:3211 (__libc_malloc): assertion failed: !victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))
Error: Command "npm run build" exited with SIGABRT - node: malloc.c:3082: __libc_malloc: Assertion `!victim || chunk_is_mmapped (mem2chunk (victim)) || ar_ptr == arena_for_chunk (mem2chunk (victim))' failed.
Error: Command "npm run build" exited with SIGABRT - free(): invalid size
Error: Command "npm run build" exited with SIGABRT
할당 되지 않은 메모리에 접근하였기 때문에 SIGABRT
시그널을 던져서 발생한 에러들 입니다.
에러의 원인 찾기
Vercel
에서 Next.js 프로젝트를 배포할 때 발생한 Fatal glibc error
와 관련된 에러는 빌드 도중 사용하는 네이티브 라이브러리와 관련된 문제라고 합니다.
네이티브 모듈(C/C++ 기반)의 사용이 문제가 되는 이유는 크게 두 가지로 나눌 수 있습니다.
-
해당 바이너리 코드가 없음 (플랫폼 종속성):
네이티브 모듈은 플랫폼 종속적입니다. 즉, 해당 모듈이 사용하는 바이너리가 현재 런타임 환경(예: Vercel)에서 사용 가능하지 않거나, 호환되지 않는 경우에 문제가 발생할 수 있습니다.
예를 들어, 로컬 개발 환경에서
sharp
은 로컬 시스템의 아키텍처와 호환되는 바이너리를 사용하지만, Vercel과 같은 서버리스 환경에서는 동일한 바이너리를 사용할 수 없습니다.
이 경우malloc
또는 메모리 관련 오류가 발생할 수 있다고 합니다. -
런타임 환경에서 메모리 한계 초과 (리소스 제한):
서버리스 환경에서는 메모리 사용량이 제한적입니다.
네이티브 모듈은 메모리를 많이 사용하며, 이로 인해 Vercel의 제한된 메모리를 초과할 수 있습니다. 메모리 초과로 인해malloc
이나 메모리 관리 관련 오류가 발생할 수 있다고 합니다.
네이티브 모듈은 자바스크립트에서 사용할 수 있는 모듈이지만, 네이티브 언어(C/C++ 등)로 작성되어 실행됩니다. 즉, 모듈이 동작하려면 해당 플랫폼에 맞는 컴파일된 바이너리가 필요합니다.
문제의 라이브러리
에러 메세지를 구글링 하던 중 한 일본 개발자분의 커밋을 발견했고, 브랜치명을 보고 sharp
가 원인임을 특정할 수 있었습니다.
Native Addon
Node.js에서 네이티브 라이브러리를 사용하기 위해서는 네이티브 애드온(Navite Addon)을 생성해야 합니다.
Native Addon
은 Node.js 어플리케이션에서 C++ 코드를 직접 호출할 수 있도록 해주는 다리 역할을 합니다.
sharp
라이브러리는 이러한 Native Addon
을 통해 libvips
의 네이티브 코드를 호출합니다.
Native Addon의 동작 방식
sharp
는 사전에 빌드된 바이너리를 이용하거나 필요에 따라 환경에 맞게libvips
를 빌드합니다.- Node.js가 애드온을 로드하면, 자바스크립트 함수를 호출할 때 애드온의 C++함수가 실행됩니다.
- 애드온 내부에서는
libvips
의 함수를 호출하여 이미지 처리 작업을 수행합니다.
libvips와 sharp의 흐름
-
사용자 코드
사용자는
sharp
라이브러리의 자바스크립트 API를 호출합니다.const sharp = require('sharp'); sharp('input.jpg') .resize(200) .toBuffer() .then(data => { /* ... */ });
-
sharp 자바스크립트 레이어
sharp
의 자바스크립트 코드는 위 단계에서 받은 요청(resize
,toBuffer
)을 처리하고 네이티브 애드온으로 전달할 준비를 합니다.이 과정에서 적절한 이미지 처리 옵션을 구조화합니다.
-
네이티브 애드온 (C++ 코드)
sharp
라이브러리에는 C++로 작성된 애드온 부분이 있습니다. 자바스크립트 코드에서 이미지 변환 작업을 요청하면, 이 C++ 애드온 함수를 호출합니다.해당 애드온은 Node.js 및
libvips
간의 다리 역할을 합니다. -
libvips 호출 (C/C++ 코어 라이브러리)
sharp
의 C++ 애드온은libvips
라이브러리의 함수를 직접 호출합니다.
이미지를 리사이즈하거나 포맷을 변환하는libvips
의 네이티브 함수를 실행합니다.libvips
는 C와 C++로 작성된 고성능 이미지 처리 함수들을 포함하고 있습니다.이 단계에서 실제 이미지 변환 작업이 수행됩니다.
-
결과 반환
libvips
에서 처리된 결과 이미지 데이터는 C++ 애드온으로 반환됩니다.
C++ 애드온은 이 데이터를 자바스크립트에서 사용할 수 있는 형식(Buffer 등)으로 변환합니다.최종적으로 자바스크립트 환경에 결과를 반환합니다.
에러의 원인 발견
Vercel은 기본적으로 sharp
를 지원하고, 배포 환경에서 사용을 적극 권장하고 있습니다.
하지만 Vercel 같은 서버리스 플랫폼에서는 제한된 메모리와 CPU 리소스를 제공하며, 일반적으로 표준 빌드 환경과는 차이가 있습니다.
sharp
와 같은 네이티브 모듈은 플랫폼 종속적이어서, 라이브러리가 Vercel의 서버리스 환경과 호환되지 않으면 문제가 발생할 수 있습니다.
Vercel의 issue에 올라온 글을 보면 @vercel/nft
가 sharp
에 필요한 플랫폼별 바이너리 파일들을 제대로 포함하지 못하고 있음을 알 수 있습니다.
@vercel/nft
: Node.js에서 파일 추적(File Tracing)을 담당하는 라이브러리로, 애플리케이션에 필요한 의존성을 자동으로 식별하고 패키징합니다. 빌드 시애플리케이션이 실제로 필요로 하는 파일들을 트래킹하여 최종 번들에 포함시킵니다.
즉, 빌드 과정에서 특정 운영체제나 환경에 맞는 바이너리 파일을 선택하지 않고, 공통된 바이너리만 추적하기 때문에 에러가 발생한 것이었습니다.
시도한 방법
1. 😅 sharp update
sharp의 버전 문제인가 싶어 최신 버전으로 업데이트 해봤습니다.
프로젝트 내 설치된 버전은 0.33.4
였고, 최신 버전은 0.33.5
였습니다.
npm update sharp
실패했습니다.
2. 😂 Node.js 버전 명시
Vercel에서 사용하는 Node.js 버전이 문제가 될 수 있기 때문에 로컬 환경의 버전과 Vercel 환경의 버전을 일치 시켰습니다.
package.json
에 Node.js 버전 명시
{
"engines": {
"node": "18.x"
}
}
실패했습니다.
3. 😰 sharp 설치 방법 수정
패키지를 설치한 후에 실행하는 postinstall
스크립트를 pakage.json에 추가했습니다.
npm rebuild는 해당 모듈을 을 다시 설치하는 명령어입니다. 새로운 버전의 노드를 설치하고 모든 C++ 애드온을 새로운 바이너리로 다시 컴파일해줍니다.
{
"scripts": {
"postinstall": "npm rebuild"
}
}
실패했습니다.
4. 🤯 현실 부정
제 에러 로그엔 sharp
라는 문구가 없었기에, 프로젝트 내 사용된 네이티브 모듈이 sharp
이외에 더 존재할 수도 있다는 생각을 해봤습니다.
나약한 생각이었습니다.
5. 🥳 sharp downgrade
1시간정도 더 찾아 보다 레딧의 댓글을 발견했습니다. (위의 Vercel issue 댓글에도 해결 방법이 존재했습니다.)
there are some known issues on Vercel (and other places) with v0.33, and I see people have fixed it by pinning to v0.32
맙소사. 사용하던 버전인 0.33이 문제가 있다고 합니다. 다른 버전으로 설치하겠습니다.
npm uninstall sharp
npm install sharp@0.32
빌드에 성공했습니다.
회고
버전이슈… 남에게만 일어나는 일인 줄 알았습니다.
에러를 해결하고 나니 sharp의 issue에 비슷한 글들이 올라와 있던 걸 확인했습니다.
그분들의 에러는 런타임에서 발생했고 아래와 같았습니다.
Error: Could not load the "sharp" module using the linux-x64 runtime
친절한 에러 메세지가 아닐 수 없습니다. sharp
와 관련된 문제인 걸 말해주니까요..
징징대도 소용 없는 일입니다. 스캔해 징징윙윙 칼날보다 차갑게 그 껍질 벗겨내
덕분에 네이티브 애드온에 대해서 배워갈 수 있던 좋은 기회였습니다.
또한, 저와 같은 에러 메세지를 맞닥뜨린 분들에게 도움이 되었으면 좋겠습니다.
잘못된 부분이 있다면 알려주시길 바랍니다.