nodejs 拾遗(知识点集合,随时补充)

异常处理

js 异常

下面代码不能命中 try catch,原因是 nodejs 中每个事件循环都是一个单独的调用栈,执行到 setTimeout 里面代码时,老的调用栈已经回收,新的调用栈异常不会命中老调用栈中的函数

try {
  interview(function() {
    console.log('haha')
  })
} catch (e) {
  console.log('oh, no', e)
}

function interview(callback) {
  setTimeout(() => {
    if (Math.random() < 0.1) {
      callback('success')
    } else {
      throw new Error('fail')
    }
  })
}

因此,nodejs 中更多的是使用 callback 或者 Promise 来返回调用结果。

如果使用 callback,则需要指定第一个参数为 Error,后续参数为正常调用后返回的结果。这是一个约定。

使用 callback 时需要慎重,因为使用不当会引发两个问题:回调地狱(callback 嵌套),回调并发(等待不少于两个带 callback 的函数执行完成后,再执行后续逻辑)

进程异常

单进程

process.on('uncaughtException',function(err) {
  // do some job
  process.exit(1);
});

function exitWhenStopped() {
    if (!stopping) {
        stopping = true;
        // do clear job
    }
}
process.on('SIGINT', exitWhenStopped);
process.on('SIGTERM', exitWhenStopped);
process.on('SIGHUP', exitWhenStopped);
process.on('SIGUSR2', exitWhenStopped);  // for nodemon restart
process.on('SIGBREAK', exitWhenStopped); // for windows ctrl-break
process.on('message', function(m) {      // for PM2 under window with --shutdown-with-message
    if (m === 'shutdown') { exitWhenStopped() }
});

使用 cluster

除了监听主进程异常外,还可以通过下面代码监听子进程状态

if (cluster.isMaster) {
  // fork child process
  cluster.on('exit', () => {
    // some child process exit, do handle job
    // example:
    setTimeout(() => {
      cluster.fork();
    }, 5000);
  })
}

性能调试

调试工具

  • ab (apache bench) 简单压测工具
  • node --prof + node --prof-process
  • node --inspect-brk + Chrome devtools
  • clinic.js

多进程处理

在 nodejs 中可以使用 cluster 模块,实现类似 nginx 中 master-worker 的模型,提升 nodejs 服务器处理能力。使用 cluster 的好处是,不需要用户分心处理多进程协同,框架自己会进行进程间通信,协调各个进程。

需要注意的是,cluster fork 出的子进程会完整拷贝整个 node 主进程,相当于多个一模一样的分身,这样会导致内存占用升高。进程间通信本身会额外消耗资源,且 node 自身也会使用到多进程。因为,一般经验是把 worker 的数量设置为 CPU 内核数量的一半(1/2),这样可以做到内存占用和处理能力的平衡。

基于 cluster 的进程稳定性优化

进程数量控制

一般设置进程数量为 CPU 内核数量的一半。

内存泄漏处理

有内存泄漏时,进程的内存占用会越来越多,可以通过监测进程使用内存量,超过阈值时重启进程。

setInterval(() => {
  if (process.memoryUsage().rss > 1000000000) {
    // report and alert
    process.exit(1)
  }
}, 5000);

子进程状态监测

function listenChildProcessActiveState(worker) {
  // clean zombie process
let missedPing = 0;
  let inter = setInterval(() => {
    worker.send('ping')
    missedPing++;
    if (missedPing >= 3) {
      clearInterval(inter);
      process.kill(worker.process.pid);
    }
  }, 3000)
  worker.on('message', (msg) => {
    if (msg === 'pong') {
      missedPing--;
    }
  })
}

if (cluster.isMaster) {
  for(let i = 0; i < limit; i++) {
    // fork child process
    let worker = cluster.fork();
    listenChildProcessActiveState(worker);
  }
  
  // 子进程退出监测
  cluster.on('exit', () => {
    // some child process exit, do handle job
    // example:
    setTimeout(() => {
      let worker = cluster.fork();
      listenChildProcessActiveState(worker);
    }, 5000);
  })
} else {
  process.on('message', (msg) => {
    if (msg === 'ping') {
      process.send('pong');
    }
  })
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值