概述nodejs核心机制

nodejsjavascript

  • Non-Blocking I/O Model
  • Event Loop
  • Event-Driven
    • 基本架构
    • 何为阻塞
    • 代码执行时
    • 阻止事件循环的几个维度
    • Worker Pool
    • npm模块的风险

Non-Blocking I/O Model

non-blocking是指node.js进程中不一样步等待执行非javascript操做(例如I/O)完成而继续执行下一块代码的特性。java

注:CPU密集型属于javascript操做。node

I/O一般指与磁盘网络的交互linux

非阻塞I/O模型使得nodejs支持高并发且很是适合于I/O密集型应用c++

Nodejs Event Loop and Worker Pool

共6个阶段git

  • timers setTimeout与setInterval回调函数队列
  • pending callbacks 会在下一次loop中执行的系统级回调队列。如TCP ECONNREFUSED -idle,prepare 内部使用
  • poll 接收新的I/O事件。执行I/O相关回调。在这个阶段node进程可能会阻塞
  • check setImmediate回调会在这个阶段执行
  • close 一些关闭的回调。好比connect.on('close', () => {....})

注:process.nextTick不属于任何一个阶段,它是介于任意两个阶段之间,而且在阶段切换时执行nextTick回调github

Event-Driven

基本架构

  • nodejs事件驱动架构中有两种线程:事件循环线程(Event Loop)以及工做线程池(worker pool)
  • Event Loop负责编排客户端请求然后调度Worker Pool处理CPU密集型任务

注:所以nodejs并非纯粹的单线程语言!正则表达式

何为阻塞

  • 若是Event Loop执行回调或worker执行任务须要很长时间,即为阻塞。当发生阻塞时,主要会有两点须要考虑:
    • 性能:若是某worker线程按期执行heavyweight任务,会影响服务吞吐量(请求/秒)
    • 安全性:假设某些输入会引发程序阻塞,则存在被恶意客户端利用并攻击的风险。即拒绝服务攻击。

代码执行时

  • 在Event Loop中同步执行常规的变量、方法的定义与调用,javascript全部回调以及非阻塞异步I/O如网络I/O
  • Worker Pool是libuv(线程池工做调度的c++库)在Worker Pool中异步执行“昂贵”繁重的任务。node提供非阻塞I/O(操做系统不提供)API,以及CPU密集的I/O API
    • I/O密集型API:
      • DNS: dns.lookup()
      • fs: fs.readFile(),除了那些显示说明同步的方法
    • CPU密集型API:
      • crypto: crypto.pbkdf2()
      • zlib: 除了那些显示说明同步的方法

Event Loop实质

抽象来讲,Event Loop维护挂起事件的队列,Worker Pool维护挂起任务的队列。npm

实际上,Event Loop并非维护一个队列。而是一个文件描述符的集合,这些文件描述符从系统级事件通知机制获取好比epoll(linux),kqueue(OSX),IOCP(Windows)。这些文件描述符对应于某些网络套接字以及node正在监视的文件等等。当某个描述符准备好时,Event Loop会将其转换为合适的事件并执行对应的回调。数组

另外,Worker Pool维护的是一个真正的队列。Worker会pop出队列的task并执行,完成后会触发Event Loop“至少一个事件已完成”的事件。

阻止事件循环的几个维度

  1. 数据处理流程中是否包含计算复杂度高的任务,好比使用CPU密集型Node API好比crypto,fs,zlib,child-process(分区处理与offload to Worker Pool)
  2. ReDoS攻击,检查是否存在易受攻击的正则表达式(使用安全正则表达式库作安全校验
  3. 是否在主线程中使用JSON.parse以及JSON.stringify(潜在风险,所以也建议offload给Worker Pool)

Worker Pool

nodejs默认的Worker Pool专门用于处理I/O任务,维护本身的线程池可使用cluster模块以及child_process模块作自定义线程池。

Node服务器的吞吐量取决于WorkerPool的吞吐量。有效下降逐个任务时间开销以及稳定任务时间开销的变化将最大程度提高服务器的吞吐量。最多见的方法就是复杂重复型任务(好比数组迭代)作分区处理。

注:因为调度Worker Pool会增长额外的通讯开销,由于Worker Pool没法获取主线程的命名空间从而没法直接读取Javascript对象,因此须要序列化/反序列化致使增长通讯成本。

npm模块的风险

npm生态系统中存在数十万个模块为开发者提供了极大的便利,然而社区中npm包参差不齐,由于没法较为准确的估计其使用Event Loop或者Worker Pool的成本而致使一些程序隐患。

相关文章
相关标签/搜索