Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
nswbmw committed Apr 10, 2018
1 parent 392c450 commit 25d94d8
Show file tree
Hide file tree
Showing 14 changed files with 48 additions and 37 deletions.
4 changes: 3 additions & 1 deletion 1.1 perf + FlameGraph.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
[火焰图](http://www.brendangregg.com/flamegraphs.html)(Flame Graph)想必大家都听过,它可以将 CPU 的使用情况可视化,使我们直观地了解到程序的性能瓶颈。我们通常要结合操作系统的性能分析工具(profiling tracer)使用火焰图,常见的操作系统的性能分析工具如下:
当程序出现性能瓶颈时,我们通常通过表象(比如请求某个接口时 CPU 使用率飙涨)然后结合代码去推测可能出问题的地方,却不知道问题到底是什么引起的。如果有个一可视化的工具直观地展现程序的性能瓶颈就好了,幸好 [Brendan D. Gregg](http://www.brendangregg.com/) 发明了火焰图。

[火焰图](http://www.brendangregg.com/flamegraphs.html)(Flame Graph)看起来就像一团跳动的火焰,因此得名。火焰图可以将 CPU 的使用情况可视化,使我们直观地了解到程序的性能瓶颈,通常要结合操作系统的性能分析工具(profiling tracer)使用,常见的操作系统的性能分析工具如下:

- Linux:perf, eBPF, SystemTap, and ktap。
- Solaris, illumos, FreeBSD:DTrace。
Expand Down
59 changes: 31 additions & 28 deletions 1.3 Tick Processor.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,63 +110,64 @@ const crypto = require('crypto')

function hash (password, cb) {
const salt = crypto.randomBytes(128).toString('base64')
const hash = crypto.pbkdf2(password, salt, 10000, 64, 'sha512', cb)
return hash
crypto.pbkdf2(password, salt, 10000, 64, 'sha512', cb)
}

let count = 0
console.time('pbkdf2')
for (let i = 0; i < 100; i++) {
hash('random_password', (err, hash) => console.log(hash))
hash('random_password', () => {
count++
if (count === 100) {
console.timeEnd('pbkdf2')
}
})
}
console.timeEnd('pbkdf2')
```

运行结果:

```sh
$ node --prof app
pbkdf2: 4.756ms
...
pbkdf2: 656.332ms
```

可以看出,程序运行了 4.756ms,相比较于之前的 1375.585ms,性能提升了 288 倍!我们继续看下 v8.log 的分析结果,运行:
可以看出,程序运行了 656.332ms,相比较于之前的 1375.585ms,性能提升了 1 倍。我们继续看下 v8.log 的分析结果,运行:

```sh
$ node --prof-process isolate-0x102802400-v8.log
Statistical profiling result from isolate-0x102802400-v8.log, (200 ticks, 9 unaccounted, 0 excluded).
Statistical profiling result from isolate-0x103001a00-v8.log, (198 ticks, 19 unaccounted, 0 excluded).

[Shared libraries]:
ticks total nonlib name
3 1.5% /usr/lib/system/libsystem_malloc.dylib

[JavaScript]:
ticks total nonlib name
1 0.5% 0.5% Stub: CallICStub
1 0.5% 0.5% StoreIC: A store IC from the snapshot
1 0.5% 0.5% Function: ~runInThisContext bootstrap_node.js:495:28
1 0.5% 0.5% Function: ~inspect buffer.js:649:70
1 0.5% 0.5% Function: ~hash /Users/nswbmw/Desktop/test/app.js:11:27
1 0.5% 0.5% Function: ~emitAfterScript async_hooks.js:443:25
1 0.5% 0.5% Function: ~<anonymous> async_hooks.js:1:11
1 0.5% 0.5% Function: ~set native collection.js:149:4
1 0.5% 0.5% Function: ~pbkdf2 crypto.js:691:16
1 0.5% 0.5% Function: ~inherits util.js:962:18
1 0.5% 0.5% Builtin: ArrayIteratorPrototypeNext

[C++]:
ticks total nonlib name
91 45.5% 46.2% T ___kdebug_trace_string
25 12.5% 12.7% t node::(anonymous namespace)::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&)
83 41.9% 41.9% T ___kdebug_trace_string
31 15.7% 15.7% t node::(anonymous namespace)::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&)
14 7.1% 7.1% T ___pthread_sigmask
...

[Summary]:
ticks total nonlib name
7 3.5% 3.6% JavaScript
181 90.5% 91.9% C++
5 2.5% 2.5% JavaScript
174 87.9% 87.9% C++
3 1.5% 1.5% GC
3 1.5% Shared libraries
9 4.5% Unaccounted
0 0.0% Shared libraries
19 9.6% Unaccounted

[C++ entry points]:
ticks cpp total name
39 63.9% 19.5% T v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*)
16 26.2% 8.0% T v8::internal::Runtime_CompileLazy(int, v8::internal::Object**, v8::internal::Isolate*)
41 60.3% 20.7% T v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*)
17 25.0% 8.6% T v8::internal::Runtime_CompileLazy(int, v8::internal::Object**, v8::internal::Isolate*)
...

[Bottom up (heavy) profile]:
Expand All @@ -175,11 +176,13 @@ Statistical profiling result from isolate-0x102802400-v8.log, (200 ticks, 9 unac
Callers occupying less than 1.0% are not shown.

ticks parent name
91 45.5% T ___kdebug_trace_string
...
25 12.5% t node::(anonymous namespace)::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&)
...
17 8.5% T ___pthread_sigmask
83 41.9% T ___kdebug_trace_string

31 15.7% t node::(anonymous namespace)::ContextifyScript::New(v8::FunctionCallbackInfo<v8::Value> const&)
31 100.0% T v8::internal::Builtin_HandleApiCall(int, v8::internal::Object**, v8::internal::Isolate*)
31 100.0% Function: ~runInThisContext bootstrap_node.js:495:28
31 100.0% Function: ~NativeModule.compile bootstrap_node.js:584:44
31 100.0% Function: ~NativeModule.require bootstrap_node.js:516:34
...
```

Expand Down
2 changes: 1 addition & 1 deletion 2.1 gcore + llnode.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ $ ulimit -c unlimited

以上命令只在当前终端环境下有效,如果想永久生效,就需要修改 /etc/security/limits.conf 文件,如下:

![](./assets/2.1.1.jpg)
![](./assets/2.1.1.png)

## 2.1.2 [gcore](http://man7.org/linux/man-pages/man1/gcore.1.html)

Expand Down
2 changes: 2 additions & 0 deletions 3.1 Promise.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ true
true
```

**注意**:原生 Promise 是没有 queue 属性的,appoint 的实现中添加了这个属性。

可以看出,queue 数组中有两个对象。因为规范中规定:**then 方法可以被同一个 promise 调用多次**。上例中在调用 .then 和 .catch 时 promise 并没有被 resolve,所以将 .then 和 .catch 生成的新 promise(a 和 b) 和正确时的回调(onSuccess 包装成 callFulfilled)和错误时的回调(onError 包装成 callRejected)生成一个 QueueItem 实例并 push 到 queue 数组里,所以两个 console.log 都打印 true。当 promise 状态改变时遍历内部 queue 数组,统一执行成功(callFulfilled)或失败(callRejected)的回调(传入 promise 的 value 值),生成的结果分别设置 a 和 b 的 state 和 value,这就是 Promise 实现的基本原理。
再来看另一个例子:

Expand Down
4 changes: 2 additions & 2 deletions 3.3 Error Stack.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ User

## 3.3.2 Error.captureStackTrace

Error.captureStackTrace 是 Node.js 提供的一个 API,可以传入两个参数:
Error.captureStackTrace 是 V8 提供的一个 API,可以传入两个参数:

```js
Error.captureStackTrace(targetObject[, constructorOpt])
Expand Down Expand Up @@ -197,7 +197,7 @@ Error

**可以看出**:出现了 MyError 相关的调用栈,但我们并不关心 MyError 及其内部是如何实现的。

captureStackTrace 的第 2 个参数可以传入其他函数,不一定是当前函数,例如:
captureStackTrace 的第 2 个参数可以传入调用链上的其他函数,不一定是当前函数,例如:

```js
const myObj = {}
Expand Down
4 changes: 3 additions & 1 deletion 3.4 [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

然而,随着 V8 彻底换上了新的 JIT 编译器—— Turbofan,大多数 “Optimization killers” 都已经成了过去时。所以在本节中我们来看看哪些过去常见的 “Optimization killers” 已经可以被 V8 优化。

## 3.4.1 Turbofan + Ignition
## 3.4.1 Ignition + Turbofan

之前 V8 使用的是名为 Crankshaft 的编译器,这个编译器后来逐渐暴露出一些缺点:

Expand All @@ -30,6 +30,8 @@

Ignition 是 V8 新引入的解释器,用来将代码编译成简洁的字节码,而不是之前的机器码,这大大减少了结果代码,减少了系统的内存使用。由于字节码较小,所以可以编译全部源代码,而不用避免编译未使用的代码。也就是说,脚本只需要解析一次,而不是像之前的编译过程那样解析多次。

Ignition 与 TurboFan 的关系为:Ignition 解释器使用低级的、体系结构无关的 TurboFan 宏汇编指令为每个操作码生成字节码处理程序,TurboFan 将这些指令编译成目标平台的代码,并在这个过程中执行低级的指令选择和机器寄存器分配。

补充一点,之前的 V8 将代码编译成机器码执行,而新的 V8 将代码编译成字节码解释执行,动机是什么呢?可能是:

1. 减少机器码占用的内存空间,即牺牲时间换空间(主要动机)。
Expand Down
4 changes: 3 additions & 1 deletion 3.5 Rust Addons.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,9 @@ zhangsan

## 3.5.5 [NAPI](https://nodejs.org/api/n-api.html)

NAPI 是 node@8 新添加的用于原生模块开发的接口,相较于以前的开发方式,NAPI 提供了稳定的 ABI 接口,消除了 Node.js 版本差异、引擎差异等编译后不兼容的问题。
不少 Node.js 开发者可能都遇到过升级 Node.js 版本导致程序运行不起来的情况,需要重新安装依赖解决,比如:node-sass 模块。因为之前编写 Node.js 扩展严重依赖于 V8 暴露的 API,而不同版本的 Node.js 依赖的 V8 版本可能不同,一旦升级 Node.js 版本,原先运行正常的 Node.js 的扩展就可能失效了。

NAPI 是 node@8 新添加的用于原生模块开发的接口,相较于以前的开发方式,NAPI 提供了稳定的 ABI 接口,消除了 Node.js 版本差异、引擎差异等编译后不兼容的问题,解决了编写 Node.js 插件最头疼的问题。

目前 NAPI 还处于试验阶段,所以相关资料并不多,笔者写了一个 demo 放到了 GitHub 上,这里直接 clone 下来运行:

Expand Down
2 changes: 1 addition & 1 deletion 4.3 Visual Studio Code.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ VS Code 可以添加条件断点,即执行到该行代码满足特定条件后

## 4.3.4 技巧 2——skipFiles

从上面图中可以看到,在 VS Code 左侧有一个 ”调用堆栈“ 面板,显示了当前断点的调用堆栈,但无法直观地看出哪些是我们项目的代码,哪些是 node_moduels 里模块的代码,而且在单步调试时会进入到 node_modules 里。总之,我们不关心 node_modules 里的代码,我们只关心项目本身的代码。这时,skipFiles 就派上用场了。
从上面图中可以看到,在 VS Code 左侧有一个 ”调用堆栈“ 面板,显示了当前断点的调用堆栈,但无法直观地看出哪些是我们项目的代码,哪些是 node_modules 里模块的代码,而且在单步调试时会进入到 node_modules 里。总之,我们不关心 node_modules 里的代码,我们只关心项目本身的代码。这时,skipFiles 就派上用场了。

skipFiles 顾名思义就是忽略我们不关心的文件。修改 launch.json 如下:

Expand Down
2 changes: 1 addition & 1 deletion 6.5 Sentry.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ app.listen(3000)

raven 是 Node.js 版的 Sentry SDK,用来收集和发送错误日志。

**小提示**:将 DSN 替换为第 10 步截图中的 `http://xxx@localhost:9000/2`,DSN 既告诉客户端 Sentry 服务器的地址,也用来当做身份认证的 token。
**小提示**:将 DSN 替换为上图中的 `http://xxx@localhost:9000/2`,DSN 既告诉客户端 Sentry 服务器的地址,也用来当做身份认证的 token。

运行以上测试代码,访问 localhost:3000,错误信息会发送给 Sentry。Sentry 展示如下:

Expand Down
2 changes: 1 addition & 1 deletion 7.1 Telegraf + InfluxDB + Grafana(上).md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

[InfluxDB](https://github.com/influxdata/influxdb) 是一个使用 Go 语言开发的开源的分布式时序、事件和指标数据库,无需外部依赖,其设计目标是实现分布式和水平伸缩扩展。

[Grafana](https://github.com/grafana/grafana) 是一个使用 Go 语言开发的开源的、功能齐全的、漂亮的仪表盘和图表的编辑器,可用来做日志的分析与展示曲线图(如 api 的请求日志),支持多种 backend,如 ElasticSearch、InfluxDB、OpenTSDB 等等。
[Grafana](https://github.com/grafana/grafana) 是一个使用 Angular + Go 语言开发的开源的、功能齐全的、漂亮的仪表盘和图表的编辑器,可用来做日志的分析与展示曲线图(如 api 的请求日志),支持多种 backend,如 ElasticSearch、InfluxDB、OpenTSDB 等等。

**工作流程**:Telegraf 将 StatsD(inputs)和 InfluxDB(outputs)结合起来,即发往 StatsD 的数据,最终通过 Telegraf 写入了 InfluxDB,然后 Grafana 读取 InfluxDB 的数据展示成图表。

Expand Down
Binary file removed assets/2.1.1.jpg
Binary file not shown.
Binary file added assets/2.1.1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/4.2.4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified assets/8.2.1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 25d94d8

Please sign in to comment.