全部产品
云市场

诊断报告

更新时间:2018-10-09 15:01:21

功能描述

Node.js 性能平台的诊断功能,大都从某一个特定角度,例如针对内存问题的堆快照,针对CPU问题的Profiling,通过一定时间的信息采集来协助定位问题。

诊断报告则从一个全局的视角抓住进程的瞬时状态,采集了堆栈,系统资源,平台信息等以协助故障定位。尤其是其中的JavaScriptStack可以协助精确定位长正则和死循环故障。

各个分支开始支持的版本:

  • 2.x: v2.5.2
  • 3.x: v3.11.8
  • 4.x: v4.3.0

注意此功能需要您的 agenthub/egg-alinode 依赖的 commandx 版本 >= v1.5.3,否则会失败。

操作指南

在实例页抓取性能数据,或者数据趋势页,点击诊断报告后,以json格式输出当前应用运行时状态,协助定位故障。

a

b

下面列举一些对定位问题协助较大的输出项,具体可以实际操作生成诊断报告后查看。

  • JavaScriptStack: JS 栈,当前js代码运行栈
  • NativeStack: 当前c++运行栈
  • JsHeapGcInfo: 堆上各个空间信息
  • resource: 进程资源信息和eventloop资源信息
  • libuvHandleSummary: libuvHandle信息
  • system: 系统环境变量,资源限制,动态链接库等
  • FileName: 诊断报告全路径
  • NodeJsVersion: 对应的Node.js版本
  • alinodeVersion: Node.js 性能平台运行时版本
  • execPath: 运行时二进制文件路径

在线分析

文件 页面等待诊断报告生成后,点击 转储 按钮后,可以将您的应用生成的对应诊断报告文件转储至云端,此时点击 分析 按钮可以实现在线的分析:

diag_ananysis

新打开的在线分析页面会给出当前诊断报告对应的 JavaScript 栈Native 栈堆内分布Libuv 句柄系统详情 等信息,具体我们看一看下面的应用示例。

应用示例

  • 复制 demo.js 代码 到服务器/本地保存为demo.js后运行(这里假设 agenthub 已经运行)。
  1. $node demos.js
  2. http listen at 8080 pid: 26542
  • 在浏览器打开 http://[您的服务器地址]:8080

  • 选择测试 Trigger Long Running Regular Expression 或者 Trigger Dead Loop JS function 进入长正则或者死循环中。

  • 然后根据上面的pid去Node.js性能平台上点击 诊断报告 ,然后到 文件 页面转储后继续点击 分析 进行在线分析定位。

首先可以看到最有用的 JavaScript 栈 信息:

js-stack

这里进程显然是阻塞在 regexpCase() 函数调用中,查看对应的 18 行 23 列可以看到是里面的 replace 操作由于触发了异常的正则回溯导致的进程全局阻塞。

剩余的一些信息的展示可以帮助您更精准地定位到问题,如下图所示

  • Native 栈信息

native-stack

  • 堆内分布

heap

  • Libuv 句柄信息

libuv

  • 系统详情信息(包含了进程当前的 ENV、系统软硬资源限制和共享库等信息)

system

其他说明

  • 诊断报告参考了node-report的功能
  • 可以通过环境变量DIAGNOSTIC_EVENTS = fatalerrorexception或者fatalerror+exception来使能遇到FatalError或者Exception时自动生成诊断报告。

demo.js 代码

  1. 'use strict';
  2. const http = require('http');
  3. const regexpCase = function() {
  4. let str = '<br/> ' +
  5. ' 早餐后自由活动,于指定时间集合自行办理退房手续。';
  6. str += '<br/> <br/>' +
  7. ' <br/> ' +
  8. ' <br/>';
  9. str += ' <br/>' +
  10. ' ' +
  11. ' ' +
  12. ' <br/>';
  13. str += ' <br/> <br/>';
  14. str += ' ' +
  15. ' ' +
  16. ' 根据船班时间,自行前往暹粒机场,返回中国。<br/>';
  17. str += '如需送机服务,需增加280/每单。<br/>';
  18. let r = String(str).replace(/(^(\s*?<br[\s\/]*?>\*?)+|(\s*?<br[\s\/]*?>\s*?)+?$)/igm, '');
  19. };
  20. const findSomething = function(from) {
  21. // find something from 'from'
  22. return [];
  23. };
  24. const deadLoopCase = function() {
  25. let selected = [];
  26. let curArr = ['item1', 'item2', 'item3'];
  27. let arr = [];
  28. while(selected.length < curArr.length) {
  29. const dp = findSomething(curArr)[0];
  30. //if (typeof dp === 'undefined') {
  31. // break;
  32. //}
  33. if (selected.indexOf(dp) === -1) {
  34. selected.push(dp);
  35. } else {
  36. arr = arr.filter(val => {
  37. return val != dp
  38. })
  39. }
  40. }
  41. };
  42. http.createServer( (req, res) => {
  43. console.log(req.url);
  44. switch(req.url) {
  45. case '/regexp': {
  46. regexpCase();
  47. res.end('regexp case');
  48. } break;
  49. case '/deadloop': {
  50. deadLoopCase();
  51. res.end('deadloop case');
  52. } break;
  53. case '/exit': {
  54. process.exit(0);
  55. } break;
  56. default: {
  57. res.writeHead(200, "OK",{'Content-Type': 'text/html'});
  58. res.write('<html><head><title>Node.js</title></head><body style="font-family:arial;">');
  59. res.write('<h2> Regular Expression and Dead Loop Detection Example</h2>');
  60. res.write('<p>Click on button below to trigger long time running regexp test.');
  61. res.write('<form enctype="application/x-www-form-urlencoded" action="/regexp" method="post">');
  62. res.write('<button>Trigger Long Running Regular Expression</button></form>');
  63. res.write('<p>Click on button below to enter JavaScript dead loop test');
  64. res.write('<form enctype="application/x-www-form-urlencoded" action="/deadloop" method="post">');
  65. res.write('<button>Trigger Dead Loop JS function</button></form>');
  66. res.write('<p>The test can be terminated only before the above cases triggered.');
  67. res.write('<form enctype="application/x-www-form-urlencoded" action="/exit" method="post">');
  68. res.write('<button>Exit Test</button></form>');
  69. res.write('</form></body></html');
  70. res.end();
  71. } break;
  72. }
  73. }).listen(8080);
  74. console.log('\nhttp listen at 8080 pid: ', process.pid);