Nodejs应用生产环境远程调试

Nodejs应用生产环境远程调试

难度:容易

前言

本文源于对Node应用生产环境的一次调试经历,当时遇到一些问题,遂作记录。如果对Node应用程序调试不熟悉的同学可以先行阅读以下官方文档:

本地调试

先上一段demo程序:

// app.js
let http = require('http');

let server = http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world');
});

server.listen(3000, () => {
    console.log('listenning on 3000');
});

在本地调试node程序,相信各位同学在学习node的第一天就已经掌握了,我们可以通过VS code等IDE直接debug,这里我们就不做演示了,这里我们通过以下命令开启我们的调试:

node --inspect-brk app.js

接着我们可以看到终端输出:

Debugger listening on ws://127.0.0.1:9229/17bbf88c-9630-4f80-b190-0284664fb34b
For help, see: https://nodejs.org/en/docs/inspector

此时我们可以通过Chrome DevTools开启调试

image-20201026210355373

为什么要选择Chrome DevTools进行调试而没有用VS code js debugger,这是因为虽然VS code可以通过Attach to remote program也能建立调试环境,但我们无法直接看到远程源码,它需要本地有对应的源代码才可实现调试,而Chrome DevTools则不需要,建立调试连接后,可以直接加载远程代码,这点对于我们远程调试生产/测试环境的Node应用,非常方便。当然我这里用的vs code原生自带的javascript调试插件,路过的同学有用过更好用的调试插件也可以推荐一二。

测试环境调试(远程)

开启测试环境调试与本地环境仅有少许不同,开启调试时需要指定IP+Port,具体方法如下:

node --inspect-brk=0.0.0.0:9229 app.js

一般指定本机地址,端口可以根据测试环境的防火墙限制而使用可以用的端口,输入以上命令后,终端上显示如下:

Debugger listening on ws://0.0.0.0:9229/d56cb197-3284-47d1-82ea-aa4b1597bc48
For help, see: https://nodejs.org/en/docs/inspector
Debugger attached.

打开本地DevTools -> Add connection,输入测试服务器网络IP和端口,即可连接成功并开始调试,注意这里网络IP是测试环境所在局域网的IP地址,调试过程与本地类似。

生产环境调试(远程)

生产环境远程调试与测试环境有很大的不同,主要的原因:网络隔离+防火墙限制。就本人所在的公司,办公环境网络和生产环境网络是完全隔离的,这导致我们在本地环境无法通过IP访问到生产机器。另外,生产服务器有着较为严格的防火墙策略,仅仅开放特定端口(比如80,443,8080等),同时对于端口的数据流向也做了严格的管控。鉴于此,似乎远程调试生产环境已经变得不可能,只剩下Core dump和Thread dump这两个法子对生产故障进行死后验尸。不过我并没有放弃,翻遍内部文档库,找到一种叫做跳板机的东西,它可以使我们通过特定授权账号对生产环境进行远程访问,类似建立起一种授信的连接。另外,更幸运地是跳板机上装有chrome,这使得我们有能力直接通过chrome对生产环境的node程序进行远程调试(备注:生产环境开启调试的过程与测试相同,这里不再赘述)。

满足之余,我在想如果没有跳板机,我们该怎么办调试生产环境,重新翻开Nodejs调试文档寻找还有没有其他的办法,在debugger一章,全篇的大部分篇幅都在向我们介绍如何用命令行进行调试,本地尝试了一下,发现真的挺有用,命令也很简单,这里列举几个:

# 首先通过以下方式开启调试
$ node inspect app.js
< Debugger listening on ws://127.0.0.1:9229/ca0e5e2d-6109-4a0a-bcbb-d93f81eade2a
< For help, see: https://nodejs.org/en/docs/inspector
< Debugger attached.
Break on start in file:///Users/wgy/Documents/training/node-training/app.js:1
> 1 (function (exports, require, module, __filename, __dirname) { const http = require('http');
  2 
  3 const server = http.createServer((req, res) => {
debug> 
# 以下是常用的命令,与devtools界面上类似
# cont, c: Continue execution
# next, n: Step next
# step, s: Step in
# out, o: Step out
# pause: Pause running code (like pause button in Developer Tools)
# setBreakpoint(), sb(): Set breakpoint on current line

更多命令可以参考官方文档,需要注意的是设置断点(sb命令),在多文件调试的场景下需要我们提前设置好断点,特别是对node应用启动过程的调试。另外,如果我们的项目中使用了ES6 module,在运行时使用babel register+polyfill,这时行号会发生变化,和本地源代码差别很大,设置断点前,最好进入repl,用vim看下运行时源代码行号。

到这里,我的node应用服务器调试经历基本讲完了,如果有什么问题,欢迎留言探讨。(完)

风清洋

风清洋

保持原动力,迎接每一天

评论