Node.js
是从纯前端走向更高阶层的前端,以及全栈工程师的唯一快速途径Node.js
就是运行在服务端的 JavaScript
Node.js
是一个基于Chrome JavaScript
运行时建立的一个平台Node.js
是一个事件驱动I/O
服务端JavaScript
环境,基于Google
的V8
引擎,V8
引擎执行Javascript
的速度非常快,性能非常好PHP
、Python
或Ruby
等动态编程语言,然后你想创建自己的服务,那么Node.js
是一个非常好的选择Node.js
是运行在服务端的 JavaScript
,如果你熟悉Javascript
,那么你将会很容易的学会Node.js
Node.js
也是一个非常好的选择Node.JS
适合运用在高并发、I/O
密集、少量业务逻辑的场景Node.js
的模块组成如下:Node.js
的运行机制JavaScript
脚本Node API
libuv
库负责Node API
的执行。它将不同的任务分配给不同的线程,形成一个EventLoop
(事件循环),以异步的方式将任务的执行结果返回给V8引擎。V8
引擎再将结果返回给用户。(Event Loop)
Nodejs
执行之后会初始化一个事件循环,执行代码程序(这些程序可能会造成异步调用、定时器或者process.nextTick()
),然后开始执行事件循环。各个阶段执行的任务如下:
timers 阶段
: 这个阶段执行setTimeout
和setInterval
预定的callback
;I/O callbacks
阶段: 执行除了close
事件的callbacks
、被timers
设定的callbacks
、setImmediate()
设定的callbacks
这些之外的callbacks
;idle, prepare
阶段: 仅node内部使用;poll
阶段: 获取新的I/O事件, 适当的条件下node
将阻塞在这里;check
阶段: 执行setImmediate()
设定的callbacks
;close callbacks
阶段: 执行socket.on('close', ...)
这些 callback
process.nextTick()
不属于上面的任何一个phase
,它在每个phase
结束的时候都会运行。也可以认为,nextTick
在下一个异步方法的事件回调函数调用前执行。
TIPS:
Node.js
中的事件循环机制不会掉头,只会由上往下,循环执行。
在
Node.js
中,绝大部分API
都是异步的,有一个很形象的故事描述了JAVA和Node.js
的区别,JAVA
是一个餐厅100
个服务员对应100
客户,Node.js
是一个服务员玩命干,也对应100
个客户,上菜的速度很大一部分取决于厨师的做菜速度
I/O
操作完之后呢?Node.js
的I/O
处理完之后会有一个回调事件,这个事件会放在一个事件处理队列里头,在进程启动时node会创建一个类似于While(true)
的循环,它的每一次轮询都会去查看是否有事件需要处理,是否有事件关联的回调函数需要处理,如果有就处理,然后加入下一个轮询,如果没有就退出进程,这就是所谓的“事件驱动”。这也从Node
的角度解释了什么是”事件驱动”。node.js
中,事件主要来源于网络请求,文件I/O
等,根据事件的不同对观察者进行了分类,有文件I/O观察者,网络I/O观察者。事件驱动是一个典型的生产者/消费者模型,请求到达观察者那里,事件循环从观察者进行消费,主线程就可以马不停蹄的只关注业务不用再去进行I/O
等待。
Node
公开宣称的目标是 “旨在提供一种简单的构建可伸缩网络程序的方法”。我们来看一个简单的例子,在 Java和 PHP 这类语言中,每个连接都会生成一个新线程,每个新线程可能需要2MB的配套内存。在一个拥有8GBRAM的系统上,理论上最大的并发连接数量是4,000
个用户。随着您的客户群的增长,如果希望您的Web应用程序支持更多用户,那么,您必须添加更多服务器。所以在传统的后台开发中,整个Web应用程序架构(包括流量、处理器速度和内存速度)中的瓶颈是:服务器能够处理的并发连接的最大数量。这个不同的架构承载的并发数量是不一致的。Node
声称它不允许使用锁,它不会直接阻塞 I/O
调用。Node
在每个连接发射一个在 Node 引擎的进程中运行的事件,而不是为每个连接生成一个新的 OS 线程(并为其分配一些配套内存)。nodejs
的机制是单线程,这个线程里面,有一个事件循环机制,处理所有的请求。在事件处理过程中,它会智能地将一些涉及到IO、网络通信等耗时比较长的操作,交由worker-threads
去执行,执行完了再回调,这就是所谓的异步IO非阻塞吧。但是,那些非IO操作,只用CPU计算的操作,它就自己扛了,比如算什么斐波那契数列之类。它是单线程,这些自己扛的任务要一个接着一个地完成,前面那个没完成,后面的只能干等。因此,对CPU要求比较高的CPU密集型任务多的话,就有可能会造成号称高性能,适合高并发的node.js服务器反应缓慢。Node.js
高并发使用Nginx+pm2
,pm2
中可以开启多线程负载均衡,模式分两种:
pm2
简介:PM2
是node
进程管理工具,可以利用它来简化很多node
应用管理的繁琐任务,如性能监控、自动重启、负载均衡等,而且使用非常简单。
下面就对PM2进行入门性的介绍,基本涵盖了PM2的常用的功能和配置。
fork
模式,单实例多进程,常用于多语言混编,比如php、python
等,不支持端口复用,需要自己做应用的端口分配和负载均衡的子进程业务代码。缺点就是单服务器实例容易由于异常会导致服务器实例崩溃。
cluster
模式,多实例多进程,但是只支持node
,端口可以复用,不需要额外的端口配置,0代码实现负载均衡。优点就是由于多实例机制,可以保证服务器的容错性,就算出现异常也不会使多个服务器实例同时崩溃。
pm2
部署,默认开启负载均衡:npm i pm2 -g
$ pm2 start app.js # 启动app.js应用程序
$ pm2 start app.js -i 4 # cluster mode 模式启动4个app.js的应用实例 # 4个应用程序会自动进行负载均衡
pm2 start app.js -i max 根据你的cpu数量最大化启动多线程进行负载均衡
如果要停止所有应用,可以pm2 stop all
查看进程状态 pm2 list
pm2真心很好很强大,可以在线热更新代码,更多的指令需要上官网看
pm2
和Nginx
配合 upstream my_nodejs_upstream {
server 127.0.0.1:3001;
}
server {
listen 80;
server_name my_nodejs_server;
root /home/www/project_root; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_max_temp_file_size 0; proxy_pass http://my_nodejs_upstream/;
proxy_redirect off; proxy_read_timeout 240s;
}
特别说明,我们不建议使用
Node.js
作为底层服务器,更多时候作为中间件和接入层使用,例如Electron
开发跨平台应用
Nginx
开启多线程,负载均衡Nginx
,找到config
文件夹下面的nginx.conf
,修改下面配置文件upstream test{
server 11.22.333.11:6666 weight=1;
server 11.22.333.22:8888 down;
server 11.22.333.33:8888 backup;
server 11.22.333.44:5555 weight=2;
}
//down 表示单前的server临时不參与负载.
//weight 默觉得1.weight越大,负载的权重就越大
//backup: 其他全部的非backup机器down或者忙的时候,请求backup机器。所以这台机器压力会最轻
nginx
命令汇总 :nginx 服务器重启命令,关闭
nginx -s reload :修改配置后重新加载生效
nginx -s reopen :重新打开日志文件
nginx -t -c /path/to/nginx.conf 测试nginx配置文件是否正确
关闭nginx:
nginx -s stop :快速停止nginx
quit :完整有序的停止nginx
其他的停止nginx 方式:
ps -ef | grep nginx
kill -QUIT 主进程号 :从容停止Nginx
kill -TERM 主进程号 :快速停止Nginx
pkill -9 nginx :强制停止Nginx
启动nginx:
nginx -c /path/to/nginx.conf
平滑重启nginx:
kill -HUP 主进程号
Nginx
多线程负载均衡和部署pm2
负载均衡后的架构图:Node.js
作为底层服务器,直接操作数据库的方式:Node.js
作为中间件,访问底层服务器的方式:Apache、Nginx 与 Node.js
之争高并发下的性能测试对比:
Apache、Nginx 与 Node.js
之争 i7-2600k
,四核八线程的机器Gentoo Linux
是用于测试的操作系统ApacheBench,2.3 <$Revision: 1748469 $>
我们可以从结果中得到什么?
全面考虑
PHP 与 Node.js 的对决
Node.js
的生态圈汇总:Node.js
遵循commonJS
规范,要说它的生态圈,第一个肯定是webpack
,用不好Node.js
的人肯定用不好webpack
,所以说Node.js
的一个突破初级前端工程师的好学习方向express koa koa2 egg
一系列的Node.js
框架,在Restful
架构下使用,完成常规的一些http,ajax
请求响应GraphQL
,GraphQL
是一种 API 所使用的查询语言,不止Node.js
有,其他语言也有,不止可以查询,还可以多数据库CRUD
操作,解决了一部分RestFul
架构带来的问题mongodb
,非关系型数据库,轻量级别数据库,目前Node.js
配合使用的比较多的数据库,在Node.js
中我们一般使用 mongoose
这个库来配合使用sqlite
,SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。它是一个零配置的数据库,这意味着与其他数据库一样,您不需要在系统中配置。就像其他数据库,SQLite 引擎不是一个独立的进程,可以按应用程序需求进行静态或动态连接。SQLite 直接访问其存储文件。Electron
,跨平台桌面开发,可以使用Node.js
的API,V8的环境也被打包在内。C++
插件,Node.js
的V8环境就是C++写的,自然也是可以使用C++插件Redis
,数据缓存层,Redis支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。SSR
, 以React
为例,在中间层对代码进行注水,在客户端对代码脱水,实现部分首屏SSR
,优化首屏渲染时间。websocket
通讯等puppeteer
爬虫Node.js
在目前前端的开发中,是一项不可或缺的技能,它也是让我们走向真正全栈工程师的路不那么陡峭Node.js
适用场景,非密集型计算型Node.js
最核心的部分不止是RestFul
架构的那一套接受请求,返回数据。还有文件IO
,流,Buffer
,redis层
这一类的操作Node.js
配合Nginx
进行负载均衡,不仅能提升性能,更能替后端真正减轻很多负担,完成许多特定的需求。Node.js
在做接入层,比如Electron
中,可以调用很多Node API
,完成渲染进程不能做的事情,例如文件io
,buffer
操作等今天由于时间有限,很多东西都没有细化下去写,可能还是有不少漏掉的,以后都会慢慢补上,走过路过,点点赞,咱们永远都是A