Pourquoi avez-vous besoin d'un suivi des performances ? Cet article vous présentera la surveillance des performances de Node.js. J'espère qu'il vous sera utile !
NodeEn tant que runtime pour Javascript côté serveur, il enrichit considérablement les scénarios d'application de Javascript.
Mais Node.js Runtime lui-même est une boîte noire Nous ne pouvons pas percevoirl'état du runtime, et il est également difficile de reproduire les problèmes en ligne.
Par conséquent, le Surveillance des performances est la pierre angulaire du « fonctionnement normal » des applications Node.js. Non seulement divers indicateurs d’exécution peuvent être surveillés à tout moment, mais cela peut également aider à résoudre des problèmes de scénarios anormaux.
La surveillance des performances peut être divisée en deux parties :
Collecte et affichage des indicateurs de performance
prom-client
est l'implémentation nodejs de prometheus, utilisée pour collecter des indicateurs de performancextransit est responsable de la collecte et de la transmission des journaux de performances
La plus grande différence par rapport à AliNode est l'utilisation duNode.js Addon
d'implémenter le samplerNode.js Addon
来实现采样器通过process.cpuUsage()
可以获取当前进程的CPU耗时数据,返回值的单位是微秒
通过process.memoryUsage()
process.cpuUsage()
. L'unité de la valeur de retour est les microsecondesvia process.memoryUsage ()
Vous pouvez obtenir les données d'allocation de mémoire du processus en cours. L'unité de la valeur de retour est en octets
Comme vous pouvez le voir sur l'image ci-dessus, rss
comprend des segments de code (Code Segment
), de la mémoire de pile (Stack
) et de la mémoire de tas ( Heap
)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
La mémoire du tas V8 et l'espace du tas peuvent être obtenus via v8.getHeapStatistics()
et v8.getHeapSpaceStatistics() Données d'analyse, la figure suivante montre la distribution de la composition de la mémoire du tas de la v8 :
semi espace
) : depuis l'espace, <code>vers l'espace
Nouvel Espace code >Objet promu🎜🎜🎜🎜Code Space : stocke le code exécutable compilé par v8 JIT🎜🎜🎜🎜Map Space : stocke l'objet pointeur de la classe cachée pointée par Object. Le pointeur de classe cachée est l'objet enregistré par v8 selon. la structure de mise en page du runtime pour un accès rapide aux membres des objets🎜🎜🎜🎜Grand espace d'objet : utilisé pour stocker des objets de plus de 1 Mo qui ne peuvent pas être alloués aux pages🎜🎜🎜<h3 data-id="heading-8"><strong>GC strong></strong></h3>🎜Les algorithmes de garbage collection de v8 sont divisés en deux catégories : 🎜🎜🎜Major GC : utilise l'algorithme <code>Mark-Sweep-Compact
pour le recyclage des objets d'ancienne génération 🎜🎜Minor GC : Utilise l'algorithme Scavenge
pour le recyclage d'objets dans la nouvelle génération🎜🎜Nouvel espace est divisé en deux espaces objets : <code>de
et à
🎜🎜Heure de déclenchement : lorsque l'espace Nouvel espace
est plein🎜🎜Étapes : 🎜🎜🎜🎜Dans depuis l'espace
, effectuez une traversée en largeur d'abord🎜🎜🎜🎜 et constatez que l'objet survivant (accessible) 🎜🎜🎜a survécu une fois (a vécu un Scavange) et a été promu Ancien espace
🎜🎜Les autres sont copiés dans dans l'espace
🎜🎜🎜🎜🎜Lorsque la copie se termine, il ne reste que les objets survivants dans dans l'espace
, de l'espace
est effacé🎜🎜🎜🎜Échangez de l'espace
et vers l'espace
, et commencez le prochain tour de Scavenge
🎜🎜 🎜 🎜Convient aux objets avec un recyclage fréquent et une petite mémoire. Il s'agit d'une stratégie espace-temps typique. L'inconvénient est que deux fois plus d'espace est gaspillé🎜Ancien espace
est plein🎜🎜Étapes : 🎜🎜🎜🎜 Marquage (Méthode de marquage tricolore)🎜🎜🎜Blanc : Représente les objets recyclables🎜🎜Noir : Représente les objets non recyclables, et les références générées par ceux-ci ont été scannées🎜🎜Gris : Représente les objets non recyclables, et les références générées par ils n'ont pas encore été analysés Après l'analyse🎜🎜placez les objets directement référencés par l'objet racine V8 dans une file d'attente de marquage
(pile explicite) et marquez ces objets en gris🎜🎜commencez par une traversée en profondeur d'abord à partir de ces objets, à chaque fois que vous accédez à un objet, placez l'objet hors de la file d'attente de marquage
pop
et marquez-le en noir 🎜🎜 Marquez ensuite tous les objets blancs sous la référence de l'objet comme gris, Push
vers la file d'attente de marquage
, et ainsi de suite jusqu'à ce que tous les objets de la pile soient sautés. Il ne reste que deux objets dans l'ancienne génération : noir (non-). recyclable) et blanc (recyclable). Planté🎜🎜PS : Lorsqu'un objet est trop grand pour être poussé vers la pile avec un espace limité, la v8 gardera l'objet en gris et l'ignorera, marquant la pile entière comme débordée. est effacé, il sera à nouveau parcouru, ce qui nécessitera une analyse supplémentaire du tas🎜🎜🎜🎜🎜Sweep🎜🎜🎜la suppression des objets blancs🎜🎜 rendra l'espace mémoire discontinu🎜🎜🎜🎜🎜Compact🎜.Ancien espace
, de sorte que le l'espace libéré sera continu et completOld 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
Utilisez mark-compact uniquement lorsque l'espace est insuffisant pour allouer les objets promus de la nouvelle génération
🎜Stop-The-World
)🎜🎜Bien que les objets actifs de la nouvelle génération soient petits et fréquemment recyclés, le point final a peu d'impact, mais les objets survivants de l'ancienne génération sont nombreuses et importantes. Les pauses provoquées par le marquage, le nettoyage, l'organisation, etc. seront plus graves. 🎜Nouvel espace
Limite par défaut : 32 Mo pour un système 64 bits, 16 Mo pour un système 32 bits 🎜🎜Ancien espace
Limite par défaut : 1 400 Mo pour un système 64 bits, 1 400 Mo pour un système 32 -bit système 700M🎜🎜Donc node
fournit deux paramètres pour ajuster la limite d'espace supérieure des nouvelles et anciennes générations🎜🎜🎜--max-semi-space-size : Définit la valeur maximale de <code>Nouvel espace
space🎜🎜--max-old-space-size
: Définit la valeur maximale de Ancien espace code> space🎜<h4 data-id="heading-14"><strong>Afficher les journaux GC</strong></h4>🎜<code>node
propose également trois façons d'afficher le GC logs : 🎜 🎜🎜--trace_gc
: Une ligne de journal décrit brièvement l'heure, le type, les changements de taille de tas et les causes de chaque GC 🎜🎜--trace_gc_verbose
: Affiche le résultats de chaque GC État détaillé de chaque espace de segmentation V8 🎜🎜--trace_gc_nvp
: informations détaillées sur la paire clé-valeur de chaque GC, y compris le type de GC, le temps de pause, les modifications de mémoire, etc. 🎜🎜En raison du journal GC, il est relativement primitif et nécessite un traitement secondaire. Vous pouvez utiliser v8-gc-log-parser🎜.heapsnapshot
: 🎜🎜 🎜🎜Utilisez heapdump🎜🎜🎜🎜🎜🎜🎜Utilisation de la v8heap-profile🎜🎜🎜🎜🎜🎜🎜Utilisez l'API fournie par la v8 module intégré à nodejs🎜🎜🎜🎜v8.getHeapSnapshot()
🎜🎜🎜🎜🎜🎜🎜v8.writeHeapSnapshot(fileName)
🎜🎜🎜🎜🎜🎜🎜Utilisez v8-profiler-next🎜🎜🎜🎜.heapsnapshot
généré peut être téléchargé dans la mémoire de la barre d'outils des outils de développement Chrome. Après l'avoir sélectionné, le résultat sera. être affiché comme indiqué ci-dessous : 🎜🎜🎜🎜La vue par défaut est la vue Résumé
Ici, nous devons faire attention aux deux colonnes les plus à droite : Taille peu profonde
et Taille conservée
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
: indique la taille de l'objet lui-même alloué dans la mémoire tas v8Retained Size
: indique la Shallow de tous les objets référencés de l'objet Size
sumRetained Size
est particulièrement grande, il peut y avoir une fuite de mémoire à l'intérieur de l'objet, et vous pouvez développer davantage pour localiser le problèmeDelta
peut être utilisée pour filtrer. les objets avec les plus grands changements de mémoire
.cpuprofile
Fichier, vous pouvez accéder à Javascript Profiler
dans la barre d'outils des outils de développement Chrome (pas dans l'onglet par défaut, vous avez besoin pour ouvrir l'affichage dans Plus sur le côté droit de la barre d'outils). Après avoir sélectionné de télécharger le fichier, le résultat de l'affichage est le suivant : 🎜🎜 🎜🎜Vue par défaut C'est la vue Heavy
. Ici on voit qu'il y en a deux colonnes : Self Time
et Total Time
🎜Self Time
: représente le temps d'exécution de cette fonction elle-même (hors autres appels )Temps total
: représente le temps total d'exécution de cette fonction (y compris les autres fonctions appelantes) Self Time
sont volumineux, la fonction peut nécessiter des calculs gourmands en CPU qui prennent beaucoup de temps. Vous pouvez également effectuer un dépannage plus approfondi🎜.core
:🎜ulimit -c unlimitedActiver les limites du noyau
node --abort-on-uncaught-exception
Ajouter ce paramètre lors du démarrage du nœud, qui peut être utilisé dans l'application. Un fichier core peut également être généré lorsqu'une exception non interceptée se produitgcore <pid></pid>
Générer manuellement le fichier core.core
, vous pouvez utiliser mdb, gdb, lldb et d'autres outils pour analyser et diagnostiquer la cause du crash réel du processus🎜llnode `quel nœud` -c /path/to/core/dump
newThing
a toujours conservé une mémoire relativement grande🎜unused
ne soit pas appelée, l'objet newThing
est référencé depuis theThing
, ce qui provoque il doit toujours exister dans replaceThing
Dans le contexte d'exécution de la fonction, il n'est pas publié. Il s'agit d'un cas typique de fuite de mémoire provoqué par des fermetures🎜🎜🎜Résumé🎜🎜🎜Les fuites de mémoire courantes incluent les situations suivantes. :🎜Donc, dans les situations ci-dessus, vous devez soigneusement déterminer si l'objet en mémoire sera automatiquement recyclé ou non. Si tel est le cas, un recyclage manuel est requis. , comme définir manuellement l'objet sur null
, supprimer la minuterie, dissocier l'écouteur d'événement, etc.
Jusqu'à présent, cet article a donné une introduction détaillée à l'ensemble du système de surveillance des performances de Node.js .
Tout d'abord, il présente les problèmes résolus par le suivi des performances, ses composants et une comparaison des avantages et des inconvénients des solutions traditionnelles.
Ensuite, les deux principaux indicateurs de performances et outils d'instantanés sont présentés en détail.
Enfin, un cas simple de fuite de mémoire est reproduit à partir de l'observation, de l'analyse et du dépannage, et les situations et solutions courantes de fuite de mémoire sont résumées.
J'espère que cet article pourra aider tout le monde à comprendre l'ensemble du système de surveillance des performances de Node.js.
Pour plus de connaissances sur les nœuds, veuillez visiter : tutoriel Nodejs !
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!