문제
New Relic Node.js 에이전트를 설치했고 Node.js 애플리케이션의 메모리 사용량이 증가했습니다.
해결책
이 메모리 증가에 대한 몇 가지 가능한 원인과 각각에 대한 잠재적인 솔루션이 있습니다.
Node.js는 클러스터 모듈을 제공합니다. 이를 통해 호스트에서 사용 가능한 모든 프로세서 코어를 사용해 요청을 병렬로 처리할 수 있습니다. 그러나 각 클러스터 작업자는 SSL 트랜잭션을 위한 자체 슬랩 버퍼를 할당하고 Node.js 에이전트 데이터의 자체 사본을 유지합니다. 이로 인해 메모리 오버헤드가 사용된 클러스터 작업자 수 만큼 늘어납니다. 호스트가 동시에 여러 Node.js 애플리케이션을 실행하는 경우에도 마찬가지입니다.
Solution:
일부 클라우드 서비스 제공업체는 주어진 시간에 실제로 사용할 수 있는 것보다 더 많은 수의 프로세서 코어를 명시하는 환경을 사용합니다. 클러스터 작업자 수를 줄이거나 클러스터 지원 없이 실행하면 성능에 영향을 주지 않고 메모리 사용량을 줄일 수 있습니다.
로그인 메시지는 기본적으로 디스크에 로그인됩니다. 메시지 데이터가 처리되는 방식으로 인해 메시지 객체는 가비지 수집을 위해 Old-pointer-space 으로 이동할 수 있습니다. 이는 객체에 대한 모든 참조가 사라진 후에도 객체가 한동안 메모리에 남아 있음을 의미합니다. 이로 인해 특정 시간에 프로세스가 소비하는 메모리 양이 더 많아집니다. 가비지 수집에도 추가 처리 시간이 사용됩니다.
Solution:
Node.js 버전에 따라 에이전트는 기본적으로 trace
또는 info
로그 수준으로 설정될 수 있습니다. 메모리 사용량과 가비지 수집에 소요되는 시간을 현저히 줄이려면 로깅 상세 수준을 info
또는 warn
수준으로 줄입니다.
많은 데이터베이스 드라이버는 cursor
이라는 추상화를 사용합니다. 커서는 쿼리 결과를 반복하는 기능을 제공합니다. 예를 들어, mongodb 드라이버는 find
쿼리를 실행할 때 커서를 제공합니다.
커서는 Node.js 런타임의 객체와 MongoDB 서버의 엔터티로 존재합니다. 애플리케이션이 cursor
의 사용을 마치면, 서버와 클라이언트 애플리케이션 모두에서 리소스를 확보하기 위해 이를 닫아야 합니다.
Node.js에서는 서버에서 cursor
를 닫지 않고도 커서를 가비지 수집하여 애플리케이션의 리소스를 해제할 수 있습니다. 이는 애플리케이션에서 눈에 띄지 않을 수 있습니다. 그러나 뉴렐릭 Node.js 에이전트는 열린 커서를 추적하여 결과를 반복하는 데 소요된 시간을 측정합니다. 애플리케이션이 사용하는 모든 커서를 닫지 않으면 에이전트는 계속해서 오래된 커서와 누수 메모리를 추적합니다.
Solution:
애플리케이션이 쿼리 결과 처리를 완료한 후 cursor.close()
를 호출하여 애플리케이션에서 생성된 모든 cursor
가 닫혔는지 확인합니다.
Node.js 에이전트는 앱이 처리하는 각 트랜잭션에 대한 데이터를 기록합니다. 데이터는 일반적으로 트랜잭션 이름별로 그룹화됩니다. 에이전트가 사용하는 메모리는 1분 길이의 수확 주기에 기록된 서로 다른 트랜잭션의 수에 따라 증가합니다.
또한 각 트랜잭션 동안 더 많은 양의 데이터가 보관되지만 트랜잭션이 완료되면 결국 폐기됩니다. 에이전트가 사용하는 메모리는 애플리케이션이 처리하는 동시 트랜잭션 수에 따라 증가합니다.
Solution:
에이전트 데이터 저장소가 메모리 사용량 증가의 원인으로 식별되는 경우 호스트에 메모리를 추가하거나 더 큰 클라우드 인스턴스로 전환하여 가장 잘 해결할 수 있습니다.