성능 모니터링이 필요한 이유는 무엇인가요? 이 글은 여러분에게 Node.js성능 모니터링을 안내할 것입니다. 여러분에게 도움이 되기를 바랍니다.
Node서버측 Javascript용 런타임으로서 Javascript의 애플리케이션 시나리오를 크게 풍부하게 합니다.
그러나 Node.js 런타임 자체는 블랙박스입니다. 우리는 런타임 상태를 인식할 수 없으며 온라인 문제를 재현하기도 어렵습니다.
따라서 성능 모니터링은 Node.js 애플리케이션의 "정상 작동"의 초석입니다. 다양한 런타임 표시기를 언제든지 모니터링할 수 있을 뿐만 아니라 비정상적인 시나리오 문제를 해결하는 데도 도움이 될 수 있습니다.
성능 모니터링은 두 부분으로 나눌 수 있습니다:
성능 지표 수집 및 표시
성능 데이터 캡처 및 분석
위 그림에서 현재 주류인 3가지 노드의 장단점을 확인할 수 있습니다. .js 성능 모니터링 솔루션, 다음은 이 세 가지 솔루션의 구성에 대한 간략한 소개입니다.
Prometheus
AliNode
alinode는 공식 nodejs와 호환되는 확장 프로그램입니다. 런타임 시 몇 가지 추가 기능이 제공됩니다:
agenthub 는 성과 지표를 수집하고 보고하는 데 사용되는 상주 프로세스입니다.
를 통합합니다. 전체 프로세스는 모니터링에서 폐쇄 루프를 형성합니다. 디스플레이, 스냅샷, 분석 등 접근이 편리하고 간편하지만 런타임 확장에는 여전히 리스크가 존재합니다
通过process.cpuUsage()
可以获取当前进程的CPU耗时数据,返回值的单位是微秒
通过process.memoryUsage()
process.cpuUsage()
를 통해 얻을 수 있습니다. 반환 값의 단위는 Microsecondsuser: 실행 중 프로세스 자체가 소비한 CPU 시간
system: 프로세스가 소비한 CPU 시간입니다. 프로세스가 실행될 때의 시스템🎜🎜process.memoryUsage()
를 통해 현재 프로세스의 메모리 할당 데이터를 얻을 수 있습니다. 반환 값은 바이트입니다. 🎜🎜🎜rss: 상주 메모리, 노드 프로세스에서 할당한 총 메모리 크기🎜🎜heapTotal: v8🎜🎜에서 적용한 힙 메모리 크기 heapUsed: v8에서 사용하는 힙 메모리 크기 🎜🎜external: v8 🎜🎜arrayBuffers에서 관리하는 C++에서 차지하는 메모리 크기: ArrayBuffer 🎜🎜🎜🎜🎜에 할당된 메모리 크기위 그림에서 볼 수 있듯이 rss
에는 코드 세그먼트(Code Segment
), 스택 메모리(Stack
), 힙 메모리( 힙
)rss
包含代码段(Code Segment
)、栈内存(Stack
)、堆内存(Heap
)
通过v8.getHeapStatistics()
和v8.getHeapSpaceStatistics()
可以获取v8堆内存和堆空间的分析数据,下图展示了v8的堆内存组成分布:
堆内存空间先划分为空间(space),空间又划分为页(page),内存按照1MB对齐进行分页。
New Space:新生代空间,用来存放一些生命周期比较短的对象数据,平分为两个空间(空间类型为semi space
):from space
,to space
Old Space:老生代空间,用来存放New Space
晋升的对象
Code Space:存放v8 JIT编译后的可执行代码
Map Space:存放Object指向的隐藏类的指针对象,隐藏类指针是v8根据运行时记录下的对象布局结构,用于快速访问对象成员
Large Object Space:用于存放大于1MB而无法分配到页的对象
v8的垃圾回收算法分为两类:
Mark-Sweep-Compact
算法,用于老生代的对象回收Scavenge
算法,用于新生代的对象回收前提:New space
分为from
和to
两个对象空间
触发时机:当New space
空间满了
步骤:
在from space
中,进行宽度优先遍历
发现存活(可达)对象
Old space
to space
中当复制结束时,to space
中只有存活的对象,from space
就被清空了
交换from space
和to space
,开始下一轮Scavenge
适用于回收频繁,内存不大的对象,典型的空间换时间的策略,缺点是浪费了多一倍的空间
三个步骤:标记、清除、整理
触发时机:当Old space
空间满了
步骤:
Marking(三色标记法)
marking queue
(显式栈)中,并将这些对象标记为灰色marking queue
pop
出来,并标记为黑色push
到marking queue
V8 힙 메모리 및 힙 공간은 v8.getHeapStatistics()
및 v8.getHeapSpaceStatistics() 분석 데이터, 다음 그림은 v8의 힙 메모리 구성 분포를 보여줍니다.
semi space
) : from space, <code>to space
New Space 코드를 저장하는 데 사용됨 >Promoted object🎜🎜🎜🎜Code Space: v8 JIT🎜🎜🎜🎜로 컴파일된 실행 코드를 저장합니다. Map Space: Object가 가리키는 히든 클래스의 포인터 객체를 저장합니다. 히든 클래스 포인터는 v8에서 다음에 따라 기록한 객체입니다. 개체 구성원에 대한 빠른 액세스를 위한 런타임 레이아웃 구조🎜🎜🎜🎜대형 개체 공간: 페이지에 할당할 수 없는 1MB보다 큰 개체를 저장하는 데 사용됩니다🎜🎜🎜<h3 data-id="heading-8"><strong>GC </strong></h3>🎜v8의 가비지 수집 알고리즘은 두 가지 범주로 나뉩니다. 🎜🎜🎜Major GC: 구세대 객체 재활용을 위해 <code>Mark-Sweep-Compact
알고리즘을 사용합니다. 🎜🎜Minor GC: 새로운 세대의 객체 재활용을 위해 Scavenge
알고리즘을 사용합니다🎜🎜새 공간는 <code>from
및 to
라는 두 개의 개체 공간으로 나뉩니다.🎜🎜트리거 시간: 새 공간
공간이 가득 찼을 때🎜🎜단계: 🎜🎜🎜🎜 from space
에서 너비 우선 순회🎜🎜🎜🎜를 수행하고 살아남은(연결 가능한) 개체 🎜🎜🎜가 한 번 살아남았고(Scavange를 경험함) 오래된 공간
🎜🎜다른 것들은 공간으로
🎜🎜🎜🎜🎜 복사가 끝나면 공간으로
에 살아남은 개체들만 남게 되고, > from space
가 삭제되었습니다🎜🎜🎜🎜 from space
와 to space
를 교환하고 다음 Scavenge
🎜🎜 라운드를 시작하세요. 🎜 🎜재활용이 잦고 메모리가 작은 개체에 적합합니다. 단점은 두 배의 공간이 낭비된다는 것입니다.🎜기존 공간
이 가득 찼을 때🎜🎜단계: 🎜🎜🎜🎜 마킹( 3색 마킹 방식)🎜🎜🎜흰색: 재활용이 가능한 개체를 나타냅니다.🎜🎜검정색: 재활용이 불가능한 개체를 나타내며, 그에 의해 생성된 참조는 스캔되었습니다.🎜🎜회색: 재활용이 불가능한 개체를 나타내고, 참조가 생성된 참조는 다음과 같습니다. 아직 스캔되지 않았습니다. 스캔 후🎜🎜V8 루트 개체가 직접 참조하는 개체를 표시 대기열
(명시적 스택)에 넣고 이러한 개체를 회색으로 표시합니다🎜🎜깊이 우선 탐색으로 시작합니다. 이러한 개체에서 개체에 액세스할 때마다 개체를 표시 대기열
pop
에서 꺼내어 검은색으로 표시합니다. 🎜🎜 그런 다음 개체 참조 아래의 모든 흰색 개체를 다음으로 표시합니다. 회색, 표시 대기열
에 푸시
등을 수행하여 스택의 모든 개체가 팝될 때까지 이전 세대에는 검은색(비-) 개체만 남습니다. recyclable) 및 흰색(재활용 가능). Planted🎜🎜PS: 제한된 공간에서 개체가 너무 커서 스택에 밀어넣을 수 없는 경우 v8에서는 개체를 회색으로 유지하고 건너뛰어 스택 후 전체 스택을 오버플로로 표시합니다. 지워지면 마크가 다시 탐색되므로 힙을 추가로 스캔해야 합니다🎜🎜🎜🎜🎜Sweep🎜🎜🎜흰색 개체를 지우면🎜🎜 메모리 공간이 불연속됩니다🎜🎜🎜🎜🎜Compact🎜Old 공간
의 한쪽 끝으로 이동하여 지워진 공간은 연속적이고 완전할 것입니다Old space
的一端,这样清除出来的空间就是连续完整的在最开始v8进行垃圾回收时,需要停止程序的运行,扫描完整个堆,回收完内存,才会重新运行程序。这种行为就叫全停顿(Stop-The-World
)
虽然新生代活动对象较小,回收频繁,全停顿,影响不大,但是老生代存活对象多且大,标记、清理、整理等造成的停顿就会比较严重。
这个理念其实有点像React框架中的Fiber架构,只有在浏览器的空闲时间才会去遍历Fiber Tree执行对应的任务,否则延迟执行,尽可能少地影响主线程的任务,避免应用卡顿,提升应用性能。
由于v8对于新老生代的空间默认限制了大小
New space
默认限制:64位系统为32M,32位系统为16MOld space
默认限制:64位系统为1400M,32位系统为700M因此node
提供了两个参数用于调整新老生代的空间上限
--max-semi-space-size
:设置New Space
空间的最大值--max-old-space-size
:设置Old Space
空间的最大值node
也提供了三种查看GC日志的方式:
--trace_gc
:一行日志简要描述每次GC时的时间、类型、堆大小变化和产生原因--trace_gc_verbose
:展示每次GC后每个V8堆空间的详细状况--trace_gc_nvp
:每次GC的详细键值对信息,包含GC类型,暂停时间,内存变化等由于GC日志比较原始,还需要二次处理,可以使用AliNode团队开发的v8-gc-log-parser
对于运行程序的堆内存进行快照采样,可以用来分析内存的消耗以及变化
生成.heapsnapshot
文件有以下几种方式:
使用heapdump
使用v8的heap-profile
使用nodejs内置的v8模块提供的api
v8.getHeapSnapshot()
v8.writeHeapSnapshot(fileName)
生成的.heapsnapshot
새로운 세대에서 승격된 개체를 할당할 공간이 부족한 경우에만 mark-compact를 사용하세요.
🎜Stop-The-World
)라고 합니다🎜🎜신세대의 활성 객체는 작고 자주 재활용되지만, 완전 정지는 거의 영향을 미치지 않지만 이전 세대의 살아남은 객체는 표시, 청소, 정리 등으로 인한 일시 중지는 더 심각할 것입니다. 🎜새 공간
기본 제한: 64비트 시스템의 경우 32M, 32비트 시스템의 경우 16M 🎜🎜기존 공간
기본 제한: 64비트 시스템의 경우 1400M, 32비트 시스템의 경우 1400M -bit system 700M🎜🎜그래서 node
는 신세대와 구세대의 공간 상한을 조정하기 위한 두 개의 매개변수를 제공합니다🎜🎜🎜--max-semi-space-size : <code>새 공간
의 최대값 설정 space🎜🎜--max-old-space-size
: 기존 공간
의 최대값 설정 code> space🎜node
는 GC를 보는 세 가지 방법도 제공합니다. 로그: 🎜 🎜🎜--trace_gc
: 로그 줄은 각 GC의 시간, 유형, 힙 크기 변경 및 원인을 간략하게 설명합니다. 🎜🎜--trace_gc_verbose
: 각 GC의 결과 각 V8 힙 공간의 자세한 상태 🎜🎜--trace_gc_nvp
: GC 유형, 일시 중지 시간, 메모리 변경 등을 포함한 각 GC의 자세한 키-값 쌍 정보 🎜🎜GC 로그로 인해 상대적으로 원시적이며 2차 처리가 필요합니다. v8-gc-log-parser🎜.heapsnapshot
파일을 생성하는 방법에는 여러 가지가 있습니다. 🎜🎜 🎜🎜힙 덤프🎜🎜🎜🎜🎜🎜🎜v8 사용힙 프로필🎜🎜🎜🎜🎜🎜🎜v8에서 제공하는 API를 사용하세요 nodejs🎜🎜🎜🎜v8.getHeapSnapshot()
🎜🎜🎜🎜🎜🎜🎜v8.writeHeapSnapshot(파일 이름)
🎜🎜🎜🎜🎜🎜🎜 v8-profiler-next🎜🎜🎜🎜.heapsnapshot
파일은 Chrome 개발자 도구 도구 모음의 메모리에 업로드할 수 있으며, 결과는 다음과 같습니다. 아래와 같이 표시됩니다: 🎜🎜🎜🎜기본 보기는 요약
보기입니다. 여기서 가장 오른쪽 두 열인 Shallow Size
및 Retained Size
Summary
视图,在这里我们要关注最右边两栏:Shallow Size
和 Retained Size
Shallow Size
:表示该对象本身在v8堆内存分配的大小Retained Size
:表示该对象所有引用对象的Shallow Size
之和当发现Retained Size
特别大时,该对象内部可能存在内存泄漏,可以进一步展开去定位问题
还有Comparison
视图是用于比较分析两个不同时段的堆快照,通过Delta
列可以筛选出内存变化最大的对象
对于运行程序的CPU进行快照采样,可以用来分析CPU的耗时及占比
生成.cpuprofile
文件有以下几种方式:
这是采集5分钟的CPU Profile样例
生成的.cpuprofile
文件,可以在Chrome devtools工具栏的Javascript Profiler
(不在默认tab,需要在工具栏右侧的更多中打开显示),选择上传文件后,展示结果如下图:
默认的视图是Heavy
视图,在这里我们看到有两栏:Self Time
和Total Time
Self Time
:代表此函数本身(不包含其他调用)的执行耗时Total Time
:代表此函数(包含其他调用函数)的总执行耗时当发现Total Time
和Self Time
偏差较大时,该函数可能存在耗时比较多的CPU密集型计算,也可以展开进一步定位排查
当应用意外崩溃终止时,系统会自动记录下进程crash掉那一刻的内存分配信息,Program Counter以及堆栈指针等关键信息来生成core文件
生成.core
文件的三种方法:
ulimit -c unlimited
打开内核限制node --abort-on-uncaught-exception
node启动添加此参数,可以在应用出现未捕获的异常时也能生成一份core文件gcore <pid></pid>
手动生成core文件获取.core
文件后,可以通过mdb、gdb、lldb等工具实现解析诊断实际进程crash的原因
llnode `which node` -c /path/to/core/dump
从监控可以观察到堆内存在持续上升,因此需要堆快照进行排查
根据heapsnapshot
可以分析排查到有一个newThing
的对象一直保持着比较大的内存
从代码中可以看到虽然unused
方法没有调用,但是newThing
对象是引用自theThing
,导致其一直存在于replaceThing
Shallow Size
: v8 힙 메모리에 할당된 객체 자체의 크기를 나타냅니다.보유된 크기
: Shallow를 나타냅니다. 개체 Size
sumRetained Size
가 특히 큰 것으로 확인되면 개체 내부에서 메모리 누수가 발생할 수 있습니다. 그리고 문제를 찾기 위해 더 확장할 수도 있습니다델타
열을 사용하여 필터링할 수 있습니다. 가장 큰 메모리 변화가 있는 객체를 찾아보세요
Cpuprofile
🎜🎜은 프로그램을 실행하는 🎜CPU🎜의 스냅샷 샘플링을 찍습니다. 이는 CPU 시간과 비율🎜.cpuprofile
파일, Chrome devtools 도구 모음의 Javascript Profiler
로 이동할 수 있습니다(기본 탭이 아님, 툴바 오른쪽의 더보기에서 디스플레이를 엽니다. 파일 업로드를 선택한 후 표시 결과는 다음과 같습니다. 🎜🎜 🎜🎜기본 뷰 Heavy
뷰입니다. 여기서는 두 가지 뷰가 있음을 알 수 있습니다. 열: 자체 시간
및 총 시간
🎜자체 시간
: 이 함수 자체의 실행 시간을 나타냅니다(다른 호출 제외). )총 시간
: 이 함수의 총 실행 시간을 나타냅니다(다른 호출 함수 포함) 자체 시간
이 크면 함수에 많은 시간이 소요되는 CPU 집약적인 계산이 있을 수 있습니다. 추가 문제 해결을 수행할 수도 있습니다🎜.core
파일을 생성하는 세 가지 방법:🎜ulimit -c unlimited커널 제한 켜기
node --abort-on-uncaught-Exception
노드를 시작할 때 이 매개변수를 추가하세요. 애플리케이션에서 사용할 수 있습니다. 코어 파일은 다음과 같은 작업을 수행할 수 있습니다. 포착되지 않은 예외가 발생하는 경우에도 생성됩니다.gcore <pid></pid>
코어 파일을 수동으로 생성.core
파일을 얻은 후 mdb, gdb, lldb 및 기타 도구를 사용하여 실제 프로세스 충돌 원인을 분석하고 진단할 수 있습니다🎜llnode `which node` -c /path/to/core/dump
heapsnapshot
에 따르면 newThing
의 개체가 항상 비교적 큰 메모리를 유지하고 있음을 분석하고 확인할 수 있습니다🎜unused
메소드가 호출되지는 않았지만 theThing
에서 newThing
객체를 참조하여 replaceThing
에 항상 존재하도록 함수의 실행 컨텍스트에서는 해제되지 않습니다. 이는 클로저로 인해 발생하는 일반적인 메모리 누수 사례입니다🎜🎜🎜요약🎜🎜🎜일반적인 메모리 누수에는 다음과 같은 상황이 포함됩니다. :🎜따라서 위의 상황에서는 메모리에 있는 객체가 자동으로 재활용되는지 여부를 신중하게 고려해야 합니다. 그렇다면 수동 재활용이 필요합니다. , 수동으로 객체를 null
로 설정, 타이머 제거, 이벤트 리스너 바인딩 해제 등이 있습니다.
지금까지 이 글에서는 전체 Node.js 성능 모니터링 시스템에 대해 자세히 소개했습니다.
먼저 성능 모니터링으로 해결되는 문제와 그 구성 요소를 소개하고, 주류 솔루션의 장단점을 비교합니다.
다음으로 두 가지 주요 성능 지표와 스냅샷 도구를 자세히 소개합니다.
마지막으로 관찰, 분석, 문제 해결을 통해 간단한 메모리 누수 사례를 재현하고 일반적인 메모리 누수 상황과 해결 방법을 요약합니다.
이 기사가 모든 사람이 Node.js 성능 모니터링 시스템 전체를 이해하는 데 도움이 되기를 바랍니다.
노드 관련 지식을 더 보려면 nodejs 튜토리얼을 방문하세요!
위 내용은 성능 모니터링이 필요한 이유는 무엇입니까? Node.js 성능 모니터링에 대해 이야기해 보겠습니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!