Node.js

Node.js 虽然有和 JavaSrcript 一样的写法,但并不是解释性语言,它将 JavaScript 代码编译成机器代码,是编译型语言。

优点:

  1. 异步I/O模型:Node.js 的异步I/O模型能够使服务器处理更多的并发请求,并在处理数据密集型任务时表现更加出色。

  2. 高性能:由于 Node.js 的底层使用了 C++ 开发,并且采用了 V8 引擎,因此它具有卓越的性能表现。

  3. 轻量级:Node.js 的代码库相对较小,因此可以快速启动和运行,并占用更少的内存资源。

  4. 跨平台:Node.js 可以在 Windows、Linux、macOS 等多个操作系统上运行,并且具有良好的兼容性。

  5. 社区支持:Node.js 拥有庞大的开发社区,可以获取大量的第三方模块和工具,并且可以共享最佳实践和开发经验。

缺点:

  1. 单线程:Node.js 的单线程模型可能导致某些长时间运行的任务阻塞事件循环,从而影响应用程序的性能。

  2. 不适合 CPU 密集型任务:由于 Node.js 的单线程模型和事件驱动机制,它不适合处理需要大量 CPU 计算的任务。

  3. 回调函数嵌套:由于 Node.js 采用回调函数的方式来处理异步操作,因此嵌套过多的回调函数可能会导致代码难以维护和理解。

  4. 异常处理:Node.js 对异常的处理机制相对较弱,因此需要开发人员自行进行异常处理。

  5. 开发成本:由于 Node.js 的生态系统相对较新,因此在开发过程中可能需要花费更多的时间和精力来寻找和解决问题。

1. 高并发策略

一般来说,高并发的解决方案就是提供多线程模型,服务器为每个客户端请求分配一个线程,使用同步 I/O,系统通过线程切换来弥补同步 I/O 调用的时间开销。比如 Apache 就是这种策略,由于 I/O 一般都是耗时操作,因此这种策略很难实现高性能,但非常简单,可以实现复杂的交互逻辑。

而事实上,大多数网站的服务器端都不会做太多的计算,它们接收到请求以后,把请求交给其它服务来处理(比如读取数据库),然后等着结果返回,最后再把结果发给客户端。因此,Node.js 针对这一事实采用了单线程模型来处理,它不会为每个接入请求分配一个线程,而是用一个主线程处理所有的请求,然后对 I/O 操作进行异步处理,避开了创建、销毁线程以及在线程间切换所需的开销和复杂性。

2. 事件循环

Node.js 在主线程里维护了一个事件队列,当接到请求后,就将该请求作为一个事件放入这个队列中,然后继续接收其他请求。当主线程空闲时(没有请求接入时),就开始循环事件队列,检查队列中是否有要处理的事件,这时要分两种情况:如果是非 I/O 任务,就亲自处理,并通过回调函数返回到上层调用;如果是 I/O 任务,就从 线程池 中拿出一个线程来处理这个事件,并指定回调函数,然后继续循环队列中的其他事件。

当线程中的 I/O 任务完成以后,就执行指定的回调函数,并把这个完成的事件放到事件队列的尾部,等待事件循环,当主线程再次循环到该事件时,就直接处理并返回给上层调用。 这个过程就叫 事件循环 (Event Loop)

由于计算任务和分发任务都有主线程完成,因此执行CPU密集型任务时,主线程可能耗时较高,会阻塞后续任务。

这个设计交 Reactor 模型,Redis6.0 以后的IO模型也是这个

Last updated