# Enhancing Node Performance
### Blocking in Event Loop
以下為在 server 底下模擬一個耗時的 task 的範例。
```javascript
// index.js
const express = require('express')
const app = express()
function doWork(duration) {
const start = Date.now()
while (Date.now() - start < duration) {}
}
app.get('/', (req, res) => {
doWork(5000)
res.send('Hi there')
})
app.listen(3000)
```
### Benchmarking Server Performance
使用 **Apache Benchmark** 對 API 進行壓力測試<br/>
**-c** concurrency 表示**併發請求數**<br/>
**-n** requests 表示**請求總數**
```bash
ab -c 50 -n 500 localhost:3000/fast
```
### Clustering
以下為手動設置 Cluster 的範例。
```javascript
// index.js
// 一個 child 有一個 thread 可使用。
process.env.UV_THREADPOOL_SIZE = 1
const cluster = require('cluster')
// index.js 是在 master 模式下被執行的嗎?
if (cluster.isMaster) {
// 觸發 index.js **再次**被執行,但是在 child 模式下被執行。
cluster.fork()
} else {
// child 模式,這邊負責當 server ,除此之外沒處理別的事情。
const express = require('express')
const crypto = require('crypto')
const app = express()
app.get('/', (req, res) => {
crypto.pbkdf2('a', 'b', 100000, 512, 'sha512', () => {
res.send('Hi there')
})
})
app.listen(3000)
}
```
注意,並不是無腦地增加 child instance 就可以優化效能,<br/>
硬體是有極限的,本質上你必須考量電腦 CPU 最多能同時處理多少任務。<br/>
ex: 就算 1 個 child 開到 6 個 thread ,在雙核心的電腦下同時只能處理最多 2 個 thread 的任務就毫無意義,還不如開 2 個 thread 的效能來得快。
### PM2
```
yarn global add pm2
```
以下為用 PM2 設置 Cluster 的範例,<br/>
把前面一節有關 Cluster 的程式碼清掉。
```javascript
// index.js
const express = require('express')
const crypto = require('crypto')
const app = express()
app.get('/', (req, res) => {
crypto.pbkdf2('a', 'b', 100000, 512, 'sha512', () => {
res.send('Hi there')
})
})
app.listen(3000)
```
```bash
# 設置 -i 0 表示創建等同於邏輯核 (Locgical CPU Cores) 數量的 Cluster
pm2 start index.js -i 0
# 刪除所有 index Cluster
pm2 delete index
# 檢視所有 Cluster
pm2 list
# 檢視所有 index Cluster 的詳情
pm2 show index
# 檢視所有 Cluster 的 Log
pm2 monit
```
### Worker Threads
```bash
yarn add webworker-thread
```
```javascript
const express = require('express')
const crypto = require('crypto')
const app = express()
const Worker = require('webworker-threads').Worker
app.get('/', (req, res) => {
/*
* 注意!
* 1. 這個 worker 的 callback 不要牽涉到外面 scope 的變數,
* 你應該把這個 worker 視為分離於主線程的另一個程序看待。
* 2. 不要使用 arrow function,否則無法使用 this.onMessage
* 接主線程的 postMessage 。
* */
const worker = new Worker(function () {
this.onmessage = function () {
let counter = 0
while (counter < 1e9) {
counter++
}
postMessage(counter)
}
})
worker.onmessage = function (message) {
console.log(message.data)
res.send('' + message.data)
}
worker.postMessage()
})
app.listen(3000)
```
###### tags: `Node JS: Advanced Concepts` `NodeJS` `JavaScript`