• Stars
    star
    143
  • Rank 248,878 (Top 6 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 4 years ago
  • Updated 16 days ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A CLI tool to help with diagnosing Node.js processes basing on inspector.

diat

npm npm npm test

[English Doc]

diat 是基于 inspector 模块(提供: cpuprofile, heapsnapshot, debug 等能力)用于协助 Node.js 进程进行问题诊断的 CLI 工具。可以将diat当成是具有更丰富特性的 node-inspect

索引

动机

在解决 Node.js 服务端应用中发生的问题的过程中,我们发现Node.js/V8 原生的 inspector 模块是解决各类问题最有效的工具(不考虑大量使用 addon 或排查其他底层 c/cpp 代码的情况),比如:用 cpuprofile 解决 cpu 使用率异常的问题;用 heapsnapshot 排查内存泄漏的问题等等;用Debugger 协议直接打 logpoint 甚至热更新代码来协助排查业务问题。

并且不少 Node.js 开发者都具有 web 开发的经验,也就是说开发者学习利用 Chrome Devtools 进行问题排查可能是成本的最低途径之一。

但在实践过程中仍然有一些问题困扰着我们,比如:

  • 有些线上问题偶发且难以追踪、复现,开启 inspector 重启应用后问题消失
  • 有些环境我们可以开启 inspector,但外网无法访问
  • 非业务性质的线上问题诊断本身是一个重要但低频的场景,相比之下要求各个业务线事先统一接入一套诊断工具的成本较高

因此我们期望 diat 针对线上问题诊断的场景,能作为一个开箱即用的工具,围绕 Node.js/V8 inspector 的能力缩短 V8 inspector 的使用成本。

node-inspect相比于其他工具有什么优点

相比于其他诊断工具,node-inspect 支持 node-inspect -p $PID 来对一个进程直接进行调试,这种模式的优点在于:

  • 开箱即用,无需应用事先接入。因为在使用时通常不需要重启进程,所以对于偶发或难以复现的问题排查会有所帮助。
  • 部分功能在进程的主线程阻塞时也可以工作,如V8 cpu profile。因为直接基于 inspector 协议,并且 Node.js 的 inspector server 是运行在独立的线程上。
  • 需要消耗额外资源的命令在工具退出后会关闭,从而尽可能少给进程带来额外的资源消耗。因此也更适合用在生产环境上。

而对于windows或是其他不能用 node-inspect -p $PID 的场合,则需要配合 --inspect 使用。

diat相比于node-inspect做了什么改动

diat 的代码本身就包含了一份改动过的 node-inspect 代码,通过 diat inspect -r 即可使用 node-inspect。相比于node-inspect,diat添加了更多功能和优化。一些与inspector server通信相关的优化包括:

  • 支持开启 worker_threads 的 inspector server 并进行调试。
  • 支持代理 inspector server 的服务到外部网络中,从而允许其他调试工具接入。
  • 退出后关闭 inspector server 释放9229端口,避免在有多个 Node.js 进程(或者说 V8 实例)的场景下 9229 端口被一个进程占用。

而基于node-inspect新增的特性则包括:

  • 除了生成 cpuprofile 和 heapsnapshot,还支持生成 heapprofile 和 heaptimeline 文件。
  • 支持 attachConsole 来输出主线程中 console 输出的内容。
  • 支持 setLogpoint() 来设置不会中断线程运行的 logpoint。logpoint 也是一种 breakpoint,所以可以通过 clearBreakpoint() 来清除。
  • 支持 getScripts() 返回scripts的数据(而不是打印出来),从而可以在通过js表达式筛选自己需要的脚本,用于进程的文件很多的情况。
  • 支持 source(scriptId) 返回一个js脚本完整的内容。

如果有适合放到 node-inspect 中的特性,我们会尝试提交PR到上游。

推荐的排查途径

  1. 如果环境允许外部网络访问,推荐直接开启 inspector server 并用 debugger 工具接入
  2. 否则再利用利用CLI提供的各类命令解决问题

安装

npm i diat -g && diat --help

Node.js版本支持

All Node.js LTS releases.

使用场景介绍

你可以用下面的命令开启一个 Node.js 进程用于测试:

node -e "console.log(process.pid); setInterval(() => {}, 1000)"

inspect

inspect命令用来打开一个进程的 inspector 用于直接调试。通常如果你能打开 inspector 并访问到,大部分问题都可以通过 inspector 协议上的功能解决。

diat inspect -p <PID>

成功后会返回如下信息:

inspector service is listening on: 0.0.0.0:56324
or open the uri below on your Chrome to debug: devtools://devtools/bundled/js_app.html?experiments=true&v8only=true&ws=10.90.39.11:56324/408b7bca-1000-4c1f-a91e-de44d460e5ae
press ctrl/meta+c to exit

当看到这样的信息后,你可以用调试工具接入56324端口,注意0.0.0.0需要换成可访问到的公网 ip。你也可以直接用 Chrome 打开后面的devtools://url 用 Chrome devtools 连接进程的 inspector。

inspect命令是通过发送 SIGUSR1 信号让 Node.js 内置的代码开启 inspector 端口,详情见文档。但出于安全考虑 Node.js 是让 inspector 监听127.0.0.1ip 地址,也就是外网无法访问。diat 在这基础之上做了个 tcp 代理让外网可以访问到进程 inspector,也就是存在被恶意访问 inspector 的风险。因此需要仔细斟酌你的使用场景是否适用

排查结束用ctrl/meta+c退出 diat 进程后,diat 会关闭业务进程中的 inspector。如果 diat 进程异常退出没能关闭进程的 inspector 的话,因为 inspector 默认监听的是127.0.0.1端口,一般风险也不大。

关闭inspector

你可以通过下列命令手动关闭一个端口上的inspector server,从而释放对应的端口:

diat inspectstop -a 127.0.0.1:9229

inspectworker

目前社区缺少对 worker_threads 开启的线程进行调试的支持(ndb支持)。inspectworker命令可以用来打开线程的 inspector 进行调试:

diat inspectworker -p <PID>

进程可以通过 worker_threads 打开多个线程,所以接入成功后首先要选择我们想要 inspect 的线程:

? Choose a worker to inspect (Use arrow keys)
❯ Worker 2(id: 1) [file:///diat/packages/diat/
__tests__/test_process/thread_worker.js]
  Worker 1(id: 2) [file:///diat/packages/diat/
__tests__/test_process/thread_worker.js]

选择相应的线程后,diat 会打开对应线程的 inspector,后续使用方式同inspect命令,可以参照inspect中的描述。

因为目前 Node.js 对 worker_threads 中的 inspector 的支持有所缺失(或者说未来 worker_threads 的调试方式不一定是以 inspector 为主),所以目前 diat 打开线程中的 inspector 后无法关闭。

repl

前面介绍了用 inspectinspectworker 打开 inspector 的方式,但在一些环境中我们并不能用外部 debugger 接入,比如:网络隔离的情况。这种情况下我们可以利用 -r 配置在命令行上进行调试,如:

diat inspect -p <PID> -r

成功后输入 help 查看 node-inspect 支持的命令。关于 node-inspect 的详细信息可以查看文档:

metric

metric命令用于查看进程占用的资源:

diat metric -p <PID>

开启后会展示 cpu、memory 和 uv 相关的一些基础数据:

[cpu] load(user): 0.00032 load(system): 0.000068
[memory] rss: 29.78MB heapTotal: 4.18MB heapUsed: 2.33MB external: 873.74KB
[uv] handle: 3, request: 0, latency: 5ms

数据每隔 2s 进行一次更新。

cpuprofile

cpuprofile命令用于让进程进行 cpu prfile,从而生成.cpuprofile 文件记录一段时间内 js 中的函数执行情况。cpu profile 可以帮助我们排查 cpu 使用率过高的问题,或是用于协助进行性能分析:

diat cpuprofile -p <PID>

当.cpuprofile 文件生成成功后,diat 会返回文件所在的位置:

profiling...
cpuprofile generated at: /diat_90504_1584018222518.cpuprofile

你可以在 Chrome Devtools 中的 Profiler 面板中打开.cpuprofile 文件进行分析。关于 cpu profile 的使用说明可以参考 Chrome Devtools 的官方文档

cpuprofile 支持配置如下参数:

  • --duration 表示采样的时间,默认为 5000ms。
  • --interval 表示采样间隔,默认为 1000us。采样间隔越小,则 cpuprofile 越准确,但需要进程额外消耗的资源越多。

cpuprofile 默认的文件格式是:./diat_$PID_$TS.cpuprofile,可通过--file改变指定生成文件的名称。

heapsnapshot

heapsnapshot命令用于生成.heapsnapshot 文件(堆快照)。heap snapshot 可以让我们了解进程中的内存占用细节,可以用来帮助我们排查内存泄漏问题:

diat heapsnapshot -p <PID>

你可以在 Chrome Devtools 中的 Memory 面板中打开.heapsnapshot 文件进行分析。关于 heap snapshot 的使用说明可以参考 Chrome Devtools 的官方文档

注意: 生成 heap snapshot 可能导致内存占用比较高的进程退出。因为没有指定参数的话,Node.js 进程在 64bit 机器上的 max-old-space-size 是 1.4GB 左右(Node.js 12 上的某个版本开始不再做这个默认的限制),而 heap snapshot 在生成的过程中会额外占用不少内存。此时继续增大内存占用会导致 V8 abort 或系统 OOM killer 关闭业务进程。对于这个问题暂时可能没有什么好的办法处理。

heapsnapshot 文件的默认格式是:./diat_$PID_$TS.heapsnapshot,可通过--file改变指定生成文件的名称。

其他V8内存相关的profile

除了 heapsnapshot,还可以直接通过diat生成 heapprofile 文件:

diat heapprofile -p <PID> -d 5000

和 heaptimeline 文件:

diat heaptimeline -p <PID> -d 5000

其中 heap profile 不会阻塞线程、对进程影响较小,而 heap timeline 则可以获取到生成对象所对应的代码。更多细节可查看官方文档

用perf生成火焰图

关于 perf + --perf-basic-prof 的用法也可以参考 diagnostics-flamegraph

cpu profile 对于排查 js 中与 cpu 相关的问题很有帮助。但是因为 cpu profile 是 V8 记录的 js 中的函数执行情况,所以对于 Node.js 底层代码中或 addon 代码中的函数调用情况,我们没办法通过 cpu profile 进行排查。如果发生这类问题我们需要 c/cpp 的 profile 进行排查。diat 对 Linux perf 方案提供额外的支持(可以参考node.js Flame Graphs on Linux)。

如果运行环境中已经安装了 perf 工具,则可以通过 perf 命令生成火焰图:

diat perf -p <PID>

最终会生成火焰图的svg文件(默认文件名称为: diat_perf.svg):

分步实现

diat perf 是对多个命令的封装,下面将分步介绍单个命令的使用方式。

首先通过perfbasicprof让 Node.js 进程生成.map 文件,.map 文件让 perf 能识别 js 的函数:

diat perfbasicprof -p <PID> -e true

接着让 perf 对进程进行 profile:

perf record -F 1000 -p <PID> -g -m 512B -- sleep 5

成功后我们会在当前文件下找到 perf.data 文件,文件中描述了这段时间内进程中的函数调用。用 perf 再次处理以获取可以直接读取的内容:

perf script > out.nodestacks01

操作结束后让 Node.js 停止生成.map 文件,减少资源消耗:

diat perfbasicprof -p <PID> -e false

如果我们想生成 Flame graph,可以perf2svg用做进一步处理生成 svg:

diat perf2svg -f out.nodestacks01

已知限制

1. 无法在 Windows 上直接传入 PID

因为 Windows 不支持给进程发送信号打开 inspector,所以也就没办法用-p选项传入 pid。可以考虑在启动 Node.js 时增加--inspect打开 inspector 并在 diat 的命令中用-a/--inspector_addr配置替代-p配置传入 inspector 的地址,比如:

node --inspect=9229 index.js

然后用 diat“打开”inspector(实际上做的事情只是在公共 ip 代理 inspector 服务):

diat inspect -a=127.0.0.1:9229

2. 9229 端口被占用后,无法通过 SIGUSR1 信号在默认的 9229 端口上打开 inspector

同样可以考虑在启动 Node.js 时增加--inspect=PORT指定一个可用的端口打开 inspector,并在 diat 的命令中用-a/--inspector_addr配置替代-p配置传入 inspector 的地址。

3. Node.js 8 版本中 inspector 的限制

Node.js 8 版本(目前已经退出 LTS)中的 inspector 有一些限制(这些问题不存在于 Node.js >= 10 的版本中),比如:

  1. 同一时间只能有一个inspector.Session接入

因为这个限制的存在,也就意味着如果已经打开并接入了进程的 inspector 端口,比如:用 Chrome Devtools 接入。那后续接入 inspector 的尝试都会失败,diat 也就没办法生效。而有些工具,比如pm2中的某些配置,比如:--max-memory-restart,也会打开进程的 inspector 并接入,所以这种情况下新的接入也会失败。

  1. 新版本的 node-inspect 使用了 Node.js 8 所不支持的api,如: require('url').fileURLToPath,会导致部分命令在 Node.js 8 中失败。

工作原理

基本工作原理

  1. 用 SIGUSR1 信号在 9229 端口上打开 inspector: https://nodejs.org/api/process.html#process_signal_events
  2. 利用 v8-inspector(node) 协议进行通信,可以执行对应的 inspector 功能,包括执行一段指定的代码: https://chromedevtools.github.io/devtools-protocol/v8/HeapProfiler/

inspectworker 的工作原理

除了 v8-inspector(node) 的协议外,Node.js 内部还有定义一些协议用于 trace 和 worker_threads 等功能,定义见:https://github.com/nodejs/node/blob/master/src/inspector/node_protocol.pdl

这些协议中包括和线程中的 inspector 进行通信的部分。diat 通过该协议让线程打开 inspector,从而允许外部接入。

在Electron上使用

你可以对 Electron 的 Node.js 进程使用 diat。因为工作原理对 Node.js 进程是通用的,所以理论上 diat 对于这类应用都是生效的。

Contributing

项目使用 lerna 进行管理,git clone 项目后进行安装:

cd diat && npm install

packages 文件夹下的 linux-perf、node-inspect 和 stackvis-simplified 是对社区里面的项目进行了些改造的代码。diat 自身的代码主要在:

  • packages/diat:命令行工具的主要代码
  • packages/live-inspector:处理与 inspector 通信

提交代码前需要确保测试通过,并在 commit message 中描述对应的改动。测试可通过npm run test执行。

已知问题:目前因为 jest 在检测 worker_threads 开启的线程上似乎有些问题,可能导致测试无法自动退出。

License

MIT

More Repositories

1

IconPark

🍎Transform an SVG icon into multiple themes, and generate React icons,Vue icons,svg icons
TypeScript
8,016
star
2

xgplayer

A HTML5 video player with a parser that saves traffic
JavaScript
7,851
star
3

sonic

A blazingly fast JSON serializing & deserializing library
Assembly
6,369
star
4

monoio

Rust async runtime based on io-uring.
Rust
3,621
star
5

byteps

A high performance and generic framework for distributed DNN training
Python
3,547
star
6

lightseq

LightSeq: A High Performance Library for Sequence Processing and Generation
C++
3,103
star
7

ByteX

ByteX is a bytecode plugin platform based on Android Gradle Transform API and ASM. 字节码插件开发平台
Java
2,865
star
8

AlphaPlayer

AlphaPlayer is a video animation engine.
Java
2,124
star
9

Elkeid

Elkeid is an open source solution that can meet the security requirements of various workloads such as hosts, containers and K8s, and serverless. It is derived from ByteDance's internal best practices.
Go
2,101
star
10

scene

Android Single Activity Applications framework without Fragment.
Java
2,024
star
11

flutter_ume

UME is an in-app debug kits platform for Flutter. Produced by Flutter Infra team of ByteDance
Dart
2,001
star
12

terarkdb

A RocksDB compatible KV storage engine with better performance
C++
1,989
star
13

bhook

🔥 ByteHook is an Android PLT hook library which supports armeabi-v7a, arm64-v8a, x86 and x86_64.
C
1,923
star
14

btrace

🔥🔥 btrace(AKA RheaTrace) is a high performance Android trace tool which is based on Perfetto, it support to define custom events automatically during building apk and using bhook to provider more native events like Render/Binder/IO etc.
Kotlin
1,826
star
15

gopkg

Universal Utilities for Go
Go
1,586
star
16

bitsail

BitSail is a distributed high-performance data integration engine which supports batch, streaming and incremental scenarios. BitSail is widely used to synchronize hundreds of trillions of data every day.
Java
1,584
star
17

go-tagexpr

An interesting go struct tag expression syntax for field validation, etc.
Go
1,470
star
18

android-inline-hook

🔥 ShadowHook is an Android inline hook library which supports thumb, arm32 and arm64.
C
1,445
star
19

GiantMIDI-Piano

Python
1,431
star
20

appshark

Appshark is a static taint analysis platform to scan vulnerabilities in an Android app.
Kotlin
1,363
star
21

piano_transcription

Python
1,247
star
22

AabResGuard

The tool of obfuscated aab resources.(Android app bundle资源混淆工具)
Java
1,247
star
23

CodeLocator

Kotlin
1,163
star
24

BoostMultiDex

BoostMultiDex is a solution for quickly loading multiple dex files on low Android version devices (4.X and below, SDK <21).
Java
1,106
star
25

music_source_separation

Python
1,039
star
26

Fastbot_Android

Fastbot(2.0) is a model-based testing tool for modeling GUI transitions to discover app stability problems
C++
971
star
27

memory-leak-detector

C
919
star
28

fedlearner

A multi-party collaborative machine learning framework
Python
877
star
29

SALMONN

SALMONN: Speech Audio Language Music Open Neural Network
Python
786
star
30

sonic-cpp

A fast JSON serializing & deserializing library, accelerated by SIMD.
C++
781
star
31

godlp

sensitive information protection toolkit
Go
770
star
32

monolith

ByteDance's Recommendation System
Python
765
star
33

tailor

C
669
star
34

RealRichText

A Tricky Solution for Implementing Inline-Image-In-Text Feature in Flutter.
Dart
657
star
35

guide

A new feature guide component by react 🧭
TypeScript
645
star
36

ibot

iBOT 🤖: Image BERT Pre-Training with Online Tokenizer (ICLR 2022)
Jupyter Notebook
608
star
37

MVDream

Multi-view Diffusion for 3D Generation
Python
588
star
38

magic-microservices

Make Web Components easier and powerful!😘
TypeScript
556
star
39

Fastbot_iOS

About Fastbot(2.0) is a model-based testing tool for modeling GUI transitions to discover app stability problems
Objective-C
537
star
40

res-adapter

Official implementation of "ResAdapter: Domain Consistent Resolution Adapter for Diffusion Models".
Python
508
star
41

mockey

a simple and easy-to-use golang mock library
Go
494
star
42

effective_transformer

Running BERT without Padding
C++
439
star
43

Next-ViT

Python
426
star
44

flow-builder

A highly customizable streaming flow builder.
TypeScript
421
star
45

unpub

Self-hosted private Dart Pub server for Enterprise
Dart
411
star
46

ByteTransformer

optimized BERT transformer inference on NVIDIA GPU. https://arxiv.org/abs/2210.03052
C++
407
star
47

MVDream-threestudio

3D generation code for MVDream
Python
397
star
48

matxscript

A high-performance, extensible Python AOT compiler.
C++
390
star
49

syllepsis

Syllepsis is an out-of-the-box rich text editor.
TypeScript
343
star
50

bytemd

ByteMD v1 repository
TypeScript
336
star
51

OMGD

Online Multi-Granularity Distillation for GAN Compression (ICCV2021)
Python
323
star
52

uss

Python
306
star
53

byteir

A model compilation solution for various hardware
MLIR
305
star
54

neurst

Neural end-to-end Speech Translation Toolkit
Python
293
star
55

danmu.js

HTML5 danmu (danmaku) plugin for any DOM element
JavaScript
276
star
56

CloudShuffleService

Cloud Shuffle Service(CSS) is a general purpose remote shuffle solution for compute engines, including Spark/Flink/MapReduce.
Java
235
star
57

g3

Enterprise-oriented Generic Proxy Solutions
Rust
227
star
58

lynx-llm

paper: https://arxiv.org/abs/2307.02469 page: https://lynx-llm.github.io/
Python
225
star
59

xgplayer-vue

Vue component for xgplayer, a HTML5 video player with a parser that saves traffic
JavaScript
219
star
60

vArmor

vArmor is a cloud native container sandbox based on AppArmor/BPF/Seccomp. It also includes multiple built-in protection rules that are ready to use out of the box.
Go
214
star
61

particle-sfm

ParticleSfM: Exploiting Dense Point Trajectories for Localizing Moving Cameras in the Wild. ECCV 2022.
C++
213
star
62

trace-irqoff

Interrupts-off or softirqs-off latency tracer
C
195
star
63

ParaGen

ParaGen is a PyTorch deep learning framework for parallel sequence generation.
Python
180
star
64

AWERTL

An non-invasive iOS framework for quickly adapting Right-To-Left style UI
Objective-C
172
star
65

Bytedance-UnionAD

Ruby
164
star
66

react-model

The next generation state management library for React
TypeScript
162
star
67

keyhouse

Keyhouse is a skeleton of general-purpose Key Management System written in Rust.
Rust
162
star
68

LargeBatchCTR

Large batch training of CTR models based on DeepCTR with CowClip.
Python
153
star
69

primus

Java
148
star
70

ic_flow_platform

IFP (ic flow platform) is an integrated circuit design flow platform, mainly used for IC process specification management and data flow contral.
Python
137
star
71

Hammer

An efficient toolkit for training deep models.
Python
136
star
72

DanmakuRenderEngine

DanmakuRenderEngine is a lightweight and scalable Android danmaku library. 轻量级高扩展安卓弹幕渲染引擎
Kotlin
127
star
73

ns-x

An easy-to-use, flexible network simulator library in Go.
Go
116
star
74

pv3d

Python
113
star
75

fc-clip

This repo contains the code for our paper Convolutions Die Hard: Open-Vocabulary Segmentation with Single Frozen Convolutional CLIP
Python
109
star
76

RLFN

Winner of runtime track in NTIRE 2022 challenge on Efficient Super-Resolution
Python
106
star
77

trace-noschedule

Trace noschedule thread
C
99
star
78

DCFrame

DCFrame is a powerful UI collection framework, which can easily create complex UI.
Swift
96
star
79

TWIST

Official codes: Self-Supervised Learning by Estimating Twin Class Distribution
Python
95
star
80

tar-wasm

A faster experimental wasm-based tar implementation for browsers.
Rust
94
star
81

magic-portal

⚡ A blazing fast micro-component and micro-frontend solution uses web-components under the hood.
TypeScript
90
star
82

xgplayer-react

React component for xgplayer, a HTML5 video player with a parser that saves traffic
JavaScript
84
star
83

fe-foundation

UI Foundation for React Hooks and Vue Composition Api
TypeScript
81
star
84

nnproxy

Scalable NameNode RPC Proxy for HDFS Federation
Java
79
star
85

dbatman

Go
74
star
86

Elkeid-HUB

Elkeid HUB is a rule/event processing engine maintained by the Elkeid Team that supports streaming/offline (not yet supported by the community edition) data processing. The original intention is to solve complex data/event processing and external system linkage requirements through standardized rules.
Python
74
star
87

FreeSeg

Python
69
star
88

pull_to_refresh

Flutter pull_to_refresh widget
Dart
67
star
89

ByteMLPerf

AI Accelerator Benchmark focuses on evaluating AI Accelerators from a practical production perspective, including the ease of use and versatility of software and hardware.
Python
63
star
90

Jeddak-DPSQL

DPSQL (Privacy Protection SQL Query Service) - This project is a microservice Middleware located between the database engine ( Hive , Clickhouse , etc.) and the application system. It provides transparent SQL query result desensitization capabilities.
Python
62
star
91

trace-runqlat

C
61
star
92

kernel

ByteDance kernel for use on cloud.
C
57
star
93

terark-zip

A data structure and algorithm library built for TerarkDB
C++
56
star
94

scroll_kit

Dart
54
star
95

ovs-dpdk

This is a fork of Open vSwitch, we focus DPDK based Open vSwitch
C
50
star
96

node-unix-socket

Unix dgram, seqpacket, etc binding for Node.js.
Rust
48
star
97

RangersAppLog

Bytedance AppLog SDK
Objective-C
47
star
98

kvm-utils

C
47
star
99

arishem

A high performance and lightweight rule engine written by Golang.
Go
46
star
100

markov-molecular-sampling

Python
46
star