요즘IT
위시켓
최근 검색어
전체 삭제
최근 검색어가 없습니다.

*FEConf2023에서 발표한 <SSR 환경(Node.js) 메모리 누수 디버깅 가이드>를 정리한 글입니다. 발표 내용을 2회로 나누어 발행합니다. 1회에서는 메모리 누수에 대해 알아보고, 메모리 누수를 모니터링 도구를 통해 확인해보겠습니다. 2회에서는 메모리 누수 현상을 직접 디버깅해보고 해결하는 방법을 알아봅니다. 본문에 삽입된 이미지의 출처는 모두 이 콘텐츠와 같은 제목의 발표 자료로, 따로 출처를 표기하지 않았습니다. 발표 자료는 FEConf2023 홈페이지에서 다운로드할 수 있습니다.

회원가입을 하면 원하는 문장을
저장할 수 있어요!

다음

회원가입을 하면
성장에 도움이 되는 콘텐츠를
스크랩할 수 있어요!

확인

개발

SSR 환경(Node.js) 메모리 누수 디버깅 가이드 (1)

년차,
어떤 스킬
,
어떤 직무
독자들이 봤을까요?
어떤 독자들이 봤는지 궁금하다면?
로그인

*FEConf2023에서 발표한 <SSR 환경(Node.js) 메모리 누수 디버깅 가이드>를 정리한 글입니다. 발표 내용을 2회로 나누어 발행합니다. 1회에서는 메모리 누수에 대해 알아보고, 메모리 누수를 모니터링 도구를 통해 확인해보겠습니다. 2회에서는 메모리 누수 현상을 직접 디버깅해보고 해결하는 방법을 알아봅니다. 본문에 삽입된 이미지의 출처는 모두 이 콘텐츠와 같은 제목의 발표 자료로, 따로 출처를 표기하지 않았습니다. 발표 자료는 FEConf2023 홈페이지에서 다운로드할 수 있습니다.

 

2024년 FEConf 세션 발표자 모집 중

2024년 FEConf 라이트닝 토크 발표자 모집 중

 

FEConf2023에서 발표된 ‘SSR 환경(Node.js) 메모리 누수 디버깅 가이드’/박지혜 토스 플레이스 프론트엔드 엔지니어

 

안녕하세요. 저는 토스 플레이스의 박지혜라고 합니다. 이번 글에서는 Node.js로 실행한 SSR 환경에서 메모리 누수가 있을 때 디버깅하는 방법에 대해서 소개하겠습니다.

 

여러분은 “SSR 환경(Node.js) 메모리 누수 디버깅 가이드"라는 제목에서 어떤 키워드가 가장 중요하다고 생각하시나요? 저는 ‘Node.js’와 ‘메모리 누수’라는 키워드가 제일 중요하다고 생각합니다. 이 중에서도 메모리 누수에 대해 제 경험을 바탕으로 소개하겠습니다.

 

어느 날 동료 데브옵스 엔지니어가 저에게 “특정 서비스가 OOM(out of memory)이 발생하는데 확인해 주세요.” 라고 얘기를 했습니다. 이 말을 듣고 저는 간단하게 메모리 누수에 대해 고민하고 해당 부분을 수정하려고 했습니다. 먼저 코드를 열어보니 큰 문제가 없어 보였는데 메모리 누수가 계속 발생했습니다. 그때 저는 조금 더 공부를 해서 디버깅을 통해 이 문제를 해결해야겠다고 마음먹었습니다.

 

이번 글을 통해 두 가지 내용을 전달하고 싶습니다.

 

1. 메모리 누수를 디버깅할 수 있는 자신감

2. 브라우저의 Memory 탭을 통해 다양한 환경에서 메모리 누수의 범인을 찾는 법

 

이번 글을 통해 그때 당시의 저와 비슷한 문제를 겪고 있는 분들에게 도움이 되었으면 좋겠습니다.

 

 

메모리 누수가 무엇이고, 무엇이 문제인가?

메모리 누수

메모리 누수란 실제로 필요하지 않는 메모리를 계속 차지하고 있는 현상을 뜻합니다. 아래와 같이 엘리베이터에 비유하여 메모리 누수에 대해 알아보겠습니다.

 

정원이 10명인 엘리베이터가 있고 사람이 4명 타고 있습니다. 이 4명은 내리지 않고 계속 타고 있다고 가정하겠습니다. 그리고 다른 사람이 타기도 하고 내리기도 할 겁니다. 즉, 이 엘리베이터는 사실상 6명만 이용할 수 있는 상황이기 때문에 금방 정원이 초과될 것입니다. 단순하게 표현하면 엘리베이터가 힘들게 되겠죠. 정원도 자주 초과하고 항상 4명이 공간을 차지하고 있기 때문입니다. 즉, 엘리베이터가 효율적으로 운행되지 못하고 있습니다. 이런 상황을 메모리 누수 현상이라고 생각할 수 있습니다.

 

메모리 누수의 문제점

그럼 엘리베이터가 효율적으로 운행되지 않는다면 무엇이 문제일까요? 자바스크립트는 어플리케이션으로 동작하기 위해 기본적으로 메모리가 필요합니다. 따라서 메모리가 부족해지면 성능이 저하됩니다.

 

보통 GC라고 부르는 가비지 컬렉터가 메모리 누수를 막기 위해 많은 활동을 하면 CPU 사용량도 필연적으로 늘어납니다. 또한 CPU를 활발하게 사용하는 작업이 많아지면 이벤트 루프가 블로킹됩니다. 이벤트 루프는 자바스크립트 연산에서 매우 중요한 부분을 차지하기 때문에 이 경우 연산이 느려지고 성능이 저하 되는 것입니다. 이로 인해 실행 중이던 서버가 종료되는 문제를 겪을 수도 있습니다.

 

서버가 비정상적으로 종료되었을 때 다시 실행되도록 해두었을지라도, 이렇게 서버가 죽게 된다면 서버가 종료된 그 순간에는 정상적인 서버의 역할을 하지 못하는 이슈가 발생합니다. 즉, 가용성에 문제가 생깁니다. 간단하게 정리하면 성능이 안 좋아지고, 어플리케이션이 자꾸 죽게 됩니다.

 

해결 방법

앞선 엘리베이터 비유를 통해 해결 방법을 알아보겠습니다. 정원이 10명인 엘리베이터에 많은 사람이 타고 있어서 엘리베이터가 힘든 상황이었기 때문에 정원을 늘릴 수 있도록 더 큰 엘리베이터로 바꿔주거나, 자리를 항상 차지하는 4명의 범인을 내보내면 될 것 같습니다.

 

즉, 힙 메모리를 늘려주거나 메모리 누수의 범인을 디버깅을 통해 찾아 해결할 수 있습니다.

 

 

 

메모리 누수를 확인하는 방법

Node.js 환경에서 메모리 누수를 확인하는 방법은 무엇일까요? 아래와 같이 Node.js를 실행한 터미널에 heap out of memory 라는 문구가 출력되고 이 에러 문구를 통해 확인할 수 있습니다.

 

그러나 개발자들이 항상 터미널을 보고 있을 수는 없습니다. 보통 본인이 실행한 서버에 모니터링 도구를 붙여 이 도구를 통해 서버를 관찰합니다. 서버 모니터링의 경우, 모니터링 도구에 그래프로 표현된 CPU 사용률이나 메모리 상태와 같은 지표들을 확인할 수 있습니다. 그러나 클라이언트 환경의 경우 모니터링 툴을 붙이기는 쉽지 않습니다. 사용하는 유저의 브라우저 종류나 하드웨어 성능에 따라 달라질 수 있기 때문입니다. 하지만 디버깅하는 방법 자체는 두 경우 모두 동일하기 때문에 같은 방법으로 설명하겠습니다.

 

 

모니터링 도구에서 메모리 누수 확인하기

이번 단락에서는 실제 소스 코드를 통해 모니터링 도구에서 메모리 누수를 확인해 보겠습니다. 아래 코드를 기반으로 메모리 누수를 일부러 발생시키고 이를 디버깅하며 해결해 볼 것이기 때문에 잘 기억해 주셨으면 좋겠습니다.

위 코드는 Node.js로 작성한 간단한 예제 코드입니다. http 요청을 받으면 200이라는 상태 코드와 함께 HTML을 리턴하는 간단한 코드입니다. 이제 이 코드를 활용해 메모리 누수가 있는 코드와 없는 코드를 비교해 보겠습니다.

 

If 조건문을 활용하여 두 가지 코드를 작성했습니다. 표시한 부분 외에는 차이가 없는 코드입니다. 그리고 유저의 요청을 통해 약간의 트래픽을 주는 환경을 아래와 같이 쉘 스크립트로 간단하게 만들었습니다.

 

메모리 누수가 없는 코드에서 호출하는 nonMemoryLeakFunction을 보겠습니다. 함수안에서 listItems 배열을 선언하고, 반복문이 100만 번 반복되면서 배열에 아이템을 넣습니다. 그리고 이 함수가 사용 중인 힙 메모리 용량을 출력하도록 했습니다. 여기서 listItems 배열이 선언된 위치를 주목해 주세요.

 

이 함수를 실행시키면 큰 변화 없이 1초마다 25MB 정도의 메모리 사용량을 나타내고 있습니다. 

 

 

이러한 숫자들을 모니터링 도구를 활용해 확인하면 아래와 같은 그래프로 표현될 것입니다. 큰 변동 없이 비슷한 수치의 메모리 사용량을 보일 것이고, 중간에 배포를 했다면 잠깐 메모리 사용량이 떨어지기도 할 것입니다. 본인의 서비스에 붙여둔 모니터링 툴이 아래와 같은 그래프를 나타내고 있다면 서비스에 별다른 문제가 없다고 생각해도 될 것입니다.

 

이번에는 누수가 있는 코드를 살펴보겠습니다. 앞서 설명드린 listItems 배열의 위치가 함수 밖에 선언되어 있습니다. 즉, 전역변수로 선언되었습니다. 눈치를 채셨겠지만 의도적으로 메모리 누수를 일으키겠다는 의미입니다. 그리고 동일하게 100만 번의 반복문을 실행시키고 함수의 메모리 사용량을 출력하도록 했습니다.

 

이 함수를 실행시키면 33MB에서 시작하여 193MB까지 메모리 사용량이 올라가고 결국은 아래와 같이 힙메모리가 부족하다는 문구와 함께 서버가 죽게 됩니다. 

 

 

마찬가지로 이 경우를 모니터링 툴로 보면 그래프가 어떻게 그려질까요? 우상향을 그리며 올라가다가 서버가 죽으면 그래프가 뚝 떨어지는 모양이 될 것입니다. 서버가 죽을 때 다시 실행되도록 해뒀더라도 결국은 다시 힙 메모리 사용률이 올라가는 패턴을 반복할 것입니다. 저는 이런 그래프를 산 모양의 그래프라고 하는데, 이런 산 모양의 그래프를 발견한다면 메모리 누수가 있다고 생각할 수 있습니다.

다음 글에서는 앞서 확인한 메모리 누수 현상을 직접 디버깅하고 해결하는 방법을 알아보겠습니다.

 

요즘IT의 모든 콘텐츠는 저작권법의 보호를 받는 바, 무단 전재와 복사, 배포 등을 금합니다.

좋아요

댓글

공유

공유

댓글 0
FEConf
485
명 알림 받는 중

작가 홈

FEConf
485
명 알림 받는 중
프론트엔드 컨퍼런스 FEConf 공식 계정입니다.

좋아요

댓글

스크랩

공유

공유

지금 회원가입하고,
요즘IT가 PICK한 뉴스레터를 받아보세요!

회원가입하기
요즘IT의 멤버가 되어주세요! 요즘IT의 멤버가 되어주세요!
요즘IT의 멤버가 되어주세요!
모든 콘텐츠를 편하게 보고 스크랩해요.
모든 콘텐츠를 편하게 보고 스크랩 하기
매주 PICK한 콘텐츠를 뉴스레터로 받아요.
매주 PICK한 콘텐츠를 뉴스레터로 받기
로그인하고 무료로 사용하기