From a7ce76addaac7f48472121d9176028587dec6fbc Mon Sep 17 00:00:00 2001 From: Lellansin Date: Tue, 14 Mar 2017 17:09:02 +0800 Subject: [PATCH] Add error.md & add TODO --- README.md | 25 +-- assets/node-js-survey-debug.png | Bin 0 -> 43825 bytes sections/error.md | 279 ++++++++++++++++++++++++++++++++ sections/io.md | 8 + sections/network.md | 13 +- 5 files changed, 309 insertions(+), 16 deletions(-) create mode 100644 assets/node-js-survey-debug.png create mode 100644 sections/error.md diff --git a/README.md b/README.md index 7093f9e..83c5e2c 100644 --- a/README.md +++ b/README.md @@ -149,23 +149,26 @@ Hi, 欢迎来到 ElemeFE, 如标题所示本教程的目的是教你如何通过 [阅读更多](sections/os.md) -## 错误处理/调试/优化 +## [错误处理/调试/优化](sections/error.md) -* `[Doc]` Errors (异常) -* `[Doc]` Domain (域) -* `[Doc]` Debugger (调试器) -* `[Doc]` C/C++ 插件 -* `[Doc]` V8 -* `[Point]` 内存快照 -* `[Point]` CPU剖析 +* [`[Doc]` Errors (异常)](sections/error.md#errors) +* [`[Doc]` Domain (域)](sections/error.md#domain) +* [`[Doc]` Debugger (调试器)](sections/error.md#debugger) +* [`[Doc]` C/C++ 插件](sections/error.md#c-c++-addon) +* [`[Doc]` V8](sections/error.md#v8) +* [`[Point]` 内存快照](sections/error.md#内存快照) +* [`[Point]` CPU剖析](sections/error.md#cpu-剖析) ### 常见问题 -* 怎么处理未预料的出错?用 try/catch ,domains 还是其它什么? -* domain 的原理是? 为什么要弃用 domain? +* 怎么处理未预料的出错? 用 try/catch ,domains 还是其它什么? [[more]](sections/error.md#q-handle-error) +* 什么是 `uncaughtException` 事件? 一般在什么情况下使用该事件? [[more]](sections/error.md#uncaughtException) +* domain 的原理是? 为什么要弃用 domain? [[more]](sections/error.md#domain) * 为什么要在 cb 的第一参数传 error? 为什么有的 cb 第一个参数不是 error, 例如 http.createServer? +* 为什么有些异常没法根据报错信息定位到代码调用? 如何准确的定位一个异常? [[more]](sections/error.md#错误栈丢失) +* 内存泄漏通常由哪些原因导致? 如何分析以及定位内存泄漏? [[more]](sections/error.md#内存快照) -`更多整理中` +[阅读更多](sections/error.md) ## 测试 diff --git a/assets/node-js-survey-debug.png b/assets/node-js-survey-debug.png new file mode 100644 index 0000000000000000000000000000000000000000..cc16367b42ad809bd2a9abba7ed649c6f5cd190d GIT binary patch literal 43825 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 i`xw=H=Ku29GEUefxX>%WBZL3FGtxJ^Q= 实际上, `try/catch` 唯一常用的是在 `JSON.parse` 和类似验证用户输入的地方 + +然而实际上现在在 Node.js 中你已经可以轻松的使用 try/catch 去捕获异步的异常了. 并且在 Node.js v7.6 之后使用了升级引擎的新版 v8, 旧版中 try/catch 代码不能优化的问题也解决了. 所以我们现在再来看 + +> 怎么处理未预料的出错? 用 try/catch , domains 还是其它什么? + +在 Node.js 中错误处理主要有一下几种方法: + +* callback(err, data) 回调约定 +* throw / try / catch +* EventEmitter 的 error 事件 + +callback(err, data) 这种形式的错误处理起来繁琐, 并不具备强制性, 目前已经处于仅需要了解, 不推荐使用的情况. 而 domain 模块则是半只脚踏进棺材了. + +1) 感谢 [co](https://github.com/visionmedia/co) 的先河, 现在的你已经简单的使用 try/catch 保护关键的位置, 以 koa 为例, 可以通过中间件的形式来进行错误处理, 详见 [Koa error hangding](https://github.com/koajs/koa/wiki/Error-Handling). 之后的 async/await 均属于这种模式. + +2) 通过 EventEmitter 的错误监听形式为各大关键的对象加上错误监听的回调. 例如监听 http server, tcp server 等对象的 `error` 事件以及 process 对象提供的 `uncaughtException` 和 `unhandledRejection` 等等. + +3) 使用 Promise 来封装异步, 并通过 Promise 的错误处理来 handle 错误. + +4) 如果上述办法不能起到良好的作用, 那么你需要学习如何优雅的 [Let It Crash](http://wiki.c2.com/?LetItCrash) + +> 为什么要在 cb 的第一参数传 error? 为什么有的 cb 第一个参数不是 error, 例如 http.createServer? + +TODO + + +### 错误栈丢失 + +```javascript +function test() { + throw new Error('test error'); +} + +function main() { + test(); +} + +main(); +``` + +可以收获报错: + +```javascript +/data/node-interview/error.js:2 + throw new Error('test error'); + ^ + +Error: test error + at test (/data/node-interview/error.js:2:9) + at main (/data/node-interview/error.js:6:3) + at Object. (/data/node-interview/error.js:9:1) + at Module._compile (module.js:570:32) + at Object.Module._extensions..js (module.js:579:10) + at Module.load (module.js:487:32) + at tryModuleLoad (module.js:446:12) + at Function.Module._load (module.js:438:3) + at Module.runMain (module.js:604:10) + at run (bootstrap_node.js:394:7) +``` + +可以发现报错的行数, test 函数, main 函数的调用关系都在 stack 中清晰的体现. + +当你使用 setImmediate 等定时器来设置异步的时候: + +```javascript +function test() { + throw new Error('test error'); +} + +function main() { + setImmediate(() => test()); +} + +main(); + +``` + +我们发现 + +```javascript +/data/node-interview/error.js:2 + throw new Error('test error'); + ^ + +Error: test error + at test (/data/node-interview/error.js:2:9) + at Immediate.setImmediate (/data/node-interview/error.js:6:22) + at runCallback (timers.js:637:20) + at tryOnImmediate (timers.js:610:5) + at processImmediate [as _immediateCallback] (timers.js:582:5) +``` + +错误栈中仅输出到 test 函数内调用的地方位置, 再往上 main 的调用信息就丢失了. 也就是说如果你的函数调用深度比较深的情况下, 你使用异步调用某个函数出错了的情况下追溯这个异步的调用是一个很困难的事情, 因为其之上的栈都已经丢失了. 如果你用过 [async](https://github.com/caolan/async) 之类的模块, 你还可能发现, 报错的 stack 会非常的长而且曲折, 光看 stack 很难去定位问题. + +这项目不大/作者清楚的情况下不是问题, 但是当项目大起来, 开发人员多起来之后, 这样追溯错误会变得异常痛苦. 关于这个问题, 在上文中提到 [错误处理的最佳实践](https://cnodejs.org/topic/55714dfac4e7fbea6e9a2e5d) 中, 关于 `编写新函数的具体建议` 那一带的内容有描述到. 通过使用 [verror](https://www.npmjs.com/package/verror) 这样的方式, 让 Error 一层层封装, 并在每一层将错误的信息一层层的包上, 最后拿到的 Error 直接可以从 message 中获取用于定位问题的关键信息. + +以昨天的数据为准(2017-3-13)各位只要对比一下看看 npm 上上个月 [verror](https://www.npmjs.com/package/verror) 的下载量 `1100w` 比 [express](https://www.npmjs.com/package/express) 的 `1070w` 还高. 应该就能感受到这种写法有多流行了. + +### 防御性编程 + +错误并不可怕, 可怕的是你不去准备应对错误————[防御性编程的介绍和技巧](http://blog.jobbole.com/101651/) + +### let it crash + +[Let It Crash](http://wiki.c2.com/?LetItCrash) + +### uncaughtException + +当异常没有被捕获一路冒泡到 Event Loop 时就会触发该事件 process 对象上的 `uncaughtException` 事件. 默认情况下, Node.js 对于此类异常会直接将其堆栈跟踪信息输出给 `stderr` 并结束进程, 而为 `uncaughtException` 事件添加监听可以覆盖该默认行为, 不会直接结束进程. + +```javascript +process.on('uncaughtException', (err) => { + console.log(`Caught exception: ${err}`); +}); + +setTimeout(() => { + console.log('This will still run.'); +}, 500); + +// Intentionally cause an exception, but don't catch it. +nonexistentFunc(); +console.log('This will not run.'); +``` + +#### 合理使用 uncaughtException + +`uncaughtException` 的初衷是可以让你拿到错误之后可以做一些回收处理之后再 process.exit. 官方的同志们还曾经讨论过要移除该事件 (详见 [issues](https://github.com/nodejs/node-v0.x-archive/issues/2582)) + +所以你需要明白 `uncaughtException` 其实已经是非常规手段了, 应尽量避免使用它来处理错误. 因为通过该事件捕获到错误后, 并不代表 `你可以愉快的继续运行 (On Error Resume Next)`. 程序内部存在未处理的异常, 这意味着应用程序处于一种未知的状态. 如果不能适当的恢复其状态, 那么很有可能会触发不可预见的问题. (使用 domain 会很夸张的加剧这个现象, 并产生新人不能理解的各类幽灵问题) + +如果在 `.on` 指定的监听回调中报错不会被捕获, Node.js 的进程会直接终端并返回一个非零的退出码, 最后输出相应的堆栈信息. 否则, 会出现无限递归. 除此之外, 内存崩溃/底层报错等情况也不会被捕获, **目前猜测**是 v8/C++ 那边撂担子不干了, Node.js 完全插不上话导致的 (TODO 整理到这里才想起来这个念头尚未验证, 如果有空的朋友帮忙验证下). + +所以官方建议的使用 `uncaughtException` 的正确姿势是在结束进程前使用同步的方式清理已使用的资源 (文件描述符、句柄等) 然后 process.exit. + +在 uncaughtException 事件之后执行普通的恢复操作并不安全. 官方建议是另外在专门准备一个 monitor 进程来做健康检查并通过 monitor 来管理恢复情况, 并在必要的时候重启 (所以官方是含蓄的提醒各位用 pm2 之类的工具). + + +### unhandledRejection + +当 Promise 被 reject 且没有绑定监听处理时, 就会触发该事件. 该事件对排查和追踪没有处理 reject 行为的 Promise 很有用. + +该事件的回调函数接收以下参数: + +* `reason` `[](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error)` | `` 该 Promise 被 reject 的对象 (通常为 Error 对象) +* `p` 被 reject 的 Promise 本身 + +例如 + +```javascript +process.on('unhandledRejection', (reason, p) => { + console.log('Unhandled Rejection at: Promise', p, 'reason:', reason); + // application specific logging, throwing an error, or other logic here +}); + +somePromise.then((res) => { + return reportToUser(JSON.pasre(res)); // note the typo (`pasre`) +}); // no `.catch` or `.then` +``` + +一下代码也会触发 `unhandledRejection` 事件: + +```javascript +function SomeResource() { + // Initially set the loaded status to a rejected promise + this.loaded = Promise.reject(new Error('Resource not yet loaded!')); +} + +var resource = new SomeResource(); +// no .catch or .then on resource.loaded for at least a turn +``` + +> In this example case, it is possible to track the rejection as a developer error as would typically be the case for other 'unhandledRejection' events. To address such failures, a non-operational `.catch(() => { })` handler may be attached to resource.loaded, which would prevent the 'unhandledRejection' event from being emitted. Alternatively, the 'rejectionHandled' event may be used. + + +## Domain + +Node.js 早期, try/catch 无法捕获异步的错误, 而错误优先的 callback 仅仅是一种约定并没有强制性并且写起来十分繁琐. 所以为了能够很好的捕获异常, Node.js 从 v0.8 开始引入 domain 这个模块. + +domain 本身是一个 EventEmitter 对象, 其中文意思是 "域" 的意思, 捕获异步异常的基本思路是创建一个域, cb 函数会在定义时会继承上一层的域, 报错通过当前域的 `.emit('error', err)` 方法触发错误事件将错误传递上去, 从而使得异步错误可以被强制捕获. (更多内容详见 [Node.js 异步异常的处理与domain模块解析](https://cnodejs.org/topic/516b64596d38277306407936)) + +但是 domain 的引入也带来了更多新的问题. 比如依赖的模块无法继承你定义的 domain, 导致你写的 domain 无法 cover 依赖模块报错. 而且, 很多人 (特别是新人) 由于不了解 Node.js 的内存/异步流程等问题, 在使用 domain 处理报错的时候, 没有做到完善的处理并盲目的让代码继续走下去, 这很可能导致**项目完全无法维护** (可能出现的问题真是不胜枚举, 各种梦魇...) + +该模块目前的情况: [deprecate domains](https://github.com/nodejs/node/issues/66) + + +## Debugger + +![node-js-survey-debug](../assets/node-js-survey-debug.png) + +类似 gdb 的命令行下 debug 工具 (上图中的 build-in debugger), 同时也支持远程 debug (类似 [node-inspector](https://github.com/node-inspector/node-inspector), 目前处于试验状态). 当然, 目前有不少同学觉得 [vscode](https://code.visualstudio.com/) 对 debug 工具集成的比较好. + +关于这个 build-in debugger 使用推荐看[官方文档](https://nodejs.org/dist/latest-v6.x/docs/api/debugger.html). 如果要深入一点, 你可能对本文感兴趣: [动态修改 NodeJS 程序中的变量值](http://code.oneapm.com/nodejs/2015/06/27/intereference/) + + +## C/C++ Addon + +在 Node.js 中开发 addon 最痛苦的地方莫过于升级 V8 导致的 C/C++ 代码不能兼容的问题, 这个问题在很早就出现了. 为了解决这个问题前人开了一个叫 [nan](https://github.com/nodejs/nan) 的项目. + +要学习 addon 开发, 除了[官方文档](https://nodejs.org/docs/latest/api/addons.html)也推荐阅读这个: https://github.com/nodejs/node-addon-examples + + +## V8 + +这里并不是介绍 V8, 而是介绍 Node.js 中的 V8 这个模块. 该模块用于开放 Node.js 内建的 V8 引擎的事件和接口. 这些接口由 V8 底层决定, 所以无法保证绝对的稳定性. + +|接口|描述| +|---|---| +|v8.getHeapStatistics()|获取 heap 信息| +|v8.getHeapSpaceStatistics()|获取 heap space 信息| +|v8.setFlagsFromString(string)|动态设置 V8 options| + +### v8.setFlagsFromString(string) + +该方法用于添加额外的 V8 命令行标志. 该方法需谨慎使用, 在 VM 启动后修改配置可能会发生不可预测的行为、崩溃和数据丢失; 或者什么反应都没有. + +通过 `node --v8-options` 命令可以查询当前 Node.js 环境中有哪些可用的 V8 options. 此外, 还可以参考非官方维护的一个 [V8 options 列表](https://github.com/thlorenz/v8-flags/blob/master/flags-0.11.md). + +用法: + +```javascript +// Print GC events to stdout for one minute. +const v8 = require('v8'); +v8.setFlagsFromString('--trace_gc'); +setTimeout(function() { v8.setFlagsFromString('--notrace_gc'); }, 60e3); +``` + +## 内存快照 + +内存快照常用与解决内存泄漏的问题. 快照工具推荐使用 [heapdump](https://github.com/bnoordhuis/node-heapdump) 用来保存内存快照, 使用 [devtool](https://github.com/Jam3/devtool) 来查看内存快照. 使用 heapdump 保存内存快照时, 只会有 Node.js 环境中的对象, 不会受到干扰(如果使用 [node-inspector](https://github.com/node-inspector/node-inspector) 的话, 快照中会有前端的变量干扰). + +使用以及内存泄漏的常见原因详见: [如何分析 Node.js 中的内存泄漏](https://zhuanlan.zhihu.com/p/25736931?group_id=825001468703674368). + +## CPU 剖析 + +整理中 + + diff --git a/sections/io.md b/sections/io.md index 49946cf..0c021b7 100644 --- a/sections/io.md +++ b/sections/io.md @@ -242,6 +242,14 @@ function Console(stdout, stderr) { Node.js 封装了标准 POSIX 文件 I/O 操作的集合. 通过 require('fs') 可以加载该模块. 该模块中的所有方法都有异步执行和同步执行两个版本. 你可以通过 fs.open 获得一个文件的文件描述符. +### 编码 + +// TODO + +UTF8, GBK, es6 中对编码的支持, 如何计算一个汉字的长度 + +BOM + ### stdio stdio (standard input output) 标准的输入输出流, 即输入流 (stdin), 输出流 (stdout), 错误流 (stderr) 三者. 在 Node.js 中分别对应 `process.stdin` (Readable), `process.stdout` (Writable) 以及 `process.stderr` (Writable) 三个 stream. diff --git a/sections/network.md b/sections/network.md index e8c05c1..e2a749b 100644 --- a/sections/network.md +++ b/sections/network.md @@ -95,7 +95,7 @@ TIME-WAIT|主动方收到 FIN, 返回收到对方 FIN 的 ACK, 等待对方是 `TIME_WAIT` 是连接的某一方 (可能是服务端也可能是客户端) 主动断开连接时, 四次挥手等待被断开的一方是否收到最后一次挥手 (ACK) 的状态. 如果在等待时间中, 再次收到第三次挥手 (FIN) 表示对方没收到最后一次挥手, 这时要再 ACK 一次. 这个等待的作用是避免出现连接混用的情况 (`prevent potential overlap with new connections` see [TCP Connection Termination](http://www.tcpipguide.com/free/t_TCPConnectionTermination.htm) for more). -出现大量的 `TIME_WAIT` 比较常见的情况是, 并发量大, 服务器在短时间断开了大量连接. 对应 HTTP server 的情况可能是没开启 `keepAlive`. 如果有开 `keepAlive`, 一般是等待客户端自己主动断开, 那么`TIME_WAIT` 就只存在客户端, 而服务端则是 `CLOSE_WAIT` 的状态, 如果服务端出现大量 `CLOSE_WAIT`, 意味着当前服务端建立的链接大面积的被断开, 可能是目标服务集群重启之类. +出现大量的 `TIME_WAIT` 比较常见的情况是, 并发量大, 服务器在短时间断开了大量连接. 对应 HTTP server 的情况可能是没开启 `keepAlive`. 如果有开 `keepAlive`, 一般是等待客户端自己主动断开, 那么`TIME_WAIT` 就只存在客户端, 而服务端则是 `CLOSE_WAIT` 的状态, 如果服务端出现大量 `CLOSE_WAIT`, 意味着当前服务端建立的连接大面积的被断开, 可能是目标服务集群重启之类. ## UDP @@ -218,7 +218,7 @@ Node.js 中的 `http.Agent` 用于池化 HTTP 客户端请求的 socket (pooling hang up 有挂断的意思, socket hang up 也可以理解为 socket 被挂断. 在 Node.js 中当你要 response 一个请求的时候, 发现该这个 socket 已经被 "挂断", 就会就会报 socket hang up 错误. -[Node.js 中源码的情况:](https://github.com/nodejs/node/blob/v6.x/lib/_http_client.js#L286): +[Node.js 中源码的情况:](https://github.com/nodejs/node/blob/v6.x/lib/_http_client.js#L286) ```javascript function socketCloseListener() { @@ -287,18 +287,21 @@ DNS 服务主要基于 UDP, 这里简单介绍 Node.js 实现的接口中的两 由于 .lookup 是同步的, 所以如果由于什么不可控的原因导致 `getaddrinfo` 缓慢或者阻塞是会影响整个 Node 进程的, 参见[文档](https://nodejs.org/dist/latest-v6.x/docs/api/dns.html#dns_dns_lookup). +> hosts 文件是什么? 什么叫 DNS 本地解析? + +TODO ## ZLIB 在网络传输过程中, 如果网速稳定的情况下, 对数据进行压缩, 压缩比率越大, 那么传输的效率就越高等同于速度越快了. zlib 模块提供了 Gzip/Gunzip, Deflate/Inflate 和 DeflateRaw/InflateRaw 等压缩方法的类, 这些类接收相同的参数, 都属于可读写的 Stream 实例. -整理中 +TODO ## RPC RPC (Remote Procedure Call Protocol) 基于 TCP/IP 来实现调用远程服务器的方法, 与 http 同属应用层. 常用于构建集群, 以及微服务 (推荐一本[《Node.js 微服务》](https://www.amazon.cn/%E5%9B%BE%E4%B9%A6/dp/B01MXY8ARP)虽然我还没看完) -常见的 RPC 几大代表: +常见的 RPC 方式: * [Thrift](http://thrift.apache.org/) * HTTP @@ -318,4 +321,4 @@ RPC (Remote Procedure Call Protocol) 基于 TCP/IP 来实现调用远程服务 使用消息队列 (Message Queue) 来进行 RPC 调用 (RPC over mq) 在业内有不少例子, 比较适合业务解耦/广播/限流等场景. -整理中 +TODO