[Nextjs] Sharp Missing In Production ( memory leak 이슈 )
두둥서비스는 한 ec2 안에
nginx를 프록시로 활용하여
next js , redis , spring , react 어플리케이션을 도커로 띄우고 있다.
금일 오후 오후 1시 3분...
nextjs 프론트 도커이미지가 다운되어버렸다.
출시이후 3개월만에 처음 있는 일이였다.
3개월째 잘 굴러가던 서비스가
이렇게 다운이되니깐 매우 당황했었다.
이슈가 있었던 부분을 살펴보고 트러블슈팅한 경험을 공유하고자 한다.
목차
1. 에러 원인찾기 : 도커 event,syslog
2. 이유가 뭘까 : 이미지 처리
3. 해결하기 : sharp install
3.1. 근데왜 squoosh 가 문제일까?
에러 원인찾기 : 도커 event ,syslog
두둥 서비스는 근검절약(돈이없따 ㅠ)을 위해 ec2 micro 에 swap memory 설정으로 꽉꽉 채워서 돌아가는 서비스다.
메모리가 아예 넘치게되면 ec2 ssh 접속조차 안되는데 이번경우는 달랐다.
sudo docker ps
를 했을 때 프론트 이미지만 내려간 상황이였고,
아쉽게도
sudo docker logs -f <image-id> --tail <tail line>
명령어로도 디버깅할만한 로그가 남아있지 않은 상황이였다.
이때부터 메모리 이슈일것같은 느낌이 강하게 왔고,
sudo docker events --slice '2023-05-20'
(https://docs.docker.com/engine/reference/commandline/events/ 도커 이벤트 관련 )
위명령어로 도커에서 발행된 이벤트 로그를 살펴보았고.
oom, exitCode=129 라는 내용으로 왔다.
exitCode 의 경우 128번 까지는 도커관련한 코드고
이후 128 + n 형식으로
n은 리눅스관련 코드이다.
cat /var/log/syslog
명령어로 syslog를 봐도 oom-killer 가 동작해서 다운되어있었다.
이유가 뭘까 : 이미지처리
왜 메모리 oom 이 났을 까.. 생각해보면
넥스트가 ssr이고, node 런타임을 기반으로 하고 있어 생긴 문제라고 생각했다.
그중에서 가장 크게 메모리를 잡아먹는게 무엇일까 하면
이미지가 그중에 가장크게 잡아먹을것 같았다. ( 프론트에서 별다른 메모리잡아먹을 작업을 하지 않기 때문 )
공식문서가서 프로덕션 모드로 배포하는 부분을 살펴보았다.
to prevent excessive memory usage... 두둥에서는 공연 상세화면에서 이미지 사이즈의 최적화를 위해서
next/image 를 쓰고 있었고.,.
이것이 원인임을 알아냈다...
(프론트 배포때 이거 안하고 뭐했어..) 😒😒
해결하기 : sharp install
개발환경에서는 가벼운 squoosh 를 사용하고,
프로덕션환경에서는 sharp 를 사용하는데
문제는 sharp를 install 하지 않은 채로 프로덕션으로 올려
실제 배포 어플리케이션에서 squoosh를 사용하기 때문이다.
간단하게 yarn add sharp 로 처리했다.
근데 왜 squoosh가 문제일까?
squoosh 는 웹어셈블리 기반으로 작성되었는데, 가장 큰문제는 할당된 메모리를 축소할 수 있는 방안이 없다고 한다..
사용자 브라우저에서 돌아가는 이미지 압축이라면, 메모리가 축소되든 말던 브라우저만 꺼지면 그렇게 큰 문제 가 없다.
문젠 node js 런타임이 서버에서 돌아간다는것이고,
node 위에서 웹 어셈블리를 통해 돌아가는 ( https://nodejs.dev/en/learn/nodejs-with-webassembly/ )
squoosh 의경우..점점 메모리만 늘어나는 꼴이라고 한다.
물론 sharp 의경우에도 메모리관련해서 문제가있지만 동시성을 낮추면서 문제를 해결했다고 한다...
( 사실 두둥 세팅이면 그럼 이미지가 하나에 한번씩 sharp 되는 꼴이다 )
성능을 제대로 확보할라면 메모리 할당자를 jemalloc 같은걸로 바꾸라고 한다.
방법은 도커이미지를 아래와 같이 하면된다.
RUN apt-get update && apt-get install --force-yes -yy \
libjemalloc1 \
&& rm -rf /var/lib/apt/lists/*
# Change memory allocator to avoid leaks
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so.1
https://github.com/lovell/sharp/issues/955#issuecomment-475532037
결국 사실 공식문서 제대로 안읽고, sharp 안깔고 배포해서 생긴 문제였지만..
이미지를 sharp하는걸 서버에서... 처리하는게 이상한 그림이긴하다.
메모리 많이쓰는 작업이고, 백엔드도 서버에서 처리안하고 람다에서 sharp 사용해서 리사이징 하는 등..
그런 부분 고려하면 next/image 자체를 안쓰는것도 좋은 방안이라고 생각한다.
아무튼 기존에 이미지 리사이징에 sharp를 사용한 경험이 있어서 한번 다시 돌아볼 수 있는
그런 경험이었다.