浅谈用nodejs处理高并发

3,274 阅读3分钟

背景

  • 解决的问题:解决web端高并发问题,例如i/o密集操作
  • 什么是I/O密集:指的是文件操作、网络操作(频繁埋点->网络操作)、数据库等等
  • 什么是CPU密集:指的是逻辑处理运算、压缩、解压、加密、解密等等
  • 为什么:NodeJS处理并发的能力强,但处理计算和逻辑的能力反而很弱

Node.js

  • Node.js是建立在Google V8 JavaScript引擎之上的网络服务器框架,允许开发者能够用客户端使用的语言JavaScript在服务器端编码。
  • JS的执行机制:JS设计是单线程的,通过事件环Event Loop实现异步开发。
  • Node.js正因为node的Event Loop原理,使NodeJS处理并发的能力强。

Node工作流程:

  1. V8引擎解析JavaScript脚本,若解析后的代码,调用了Node API,Node就会将代码交给libuv库处理,这个libuv库是c语言写的,也就是node的事件环的核心。
  2. libuv库负责Node API的执行,它将不同的任务分配给不同的工作线程(work threads),通过多线程同步阻塞执行,模拟异步处理机制,成功后将回调函数放入Event Queue。
  3. 等到work threads队列中有执行完成的事件,就会通过execute callback回调给Event queue队列,把它放入队列中。
  4. 最后通过事件驱动(发布订阅)的方式,取出EVENT QUEUE队列的事件,再通过V8引擎将结果返回给应用
  • 传统的server 每个请求生成一个线程,nodejs是一个单线程的,使用libuv库保持数万并发
  • libuv:c语言编写的基础库实现主循环
  • NodeJS它的所有I/O、网络通信等比较耗时的任务,都可以交给worker threads执行再回调,所以很快
  • 非阻塞事件驱动 实现异步开发,通过事件驱动的I/O来操作完成平台数据密集型实时应用

Node事件环

  • node中的event loop是在libuv里面的,libuv里面有个事件环机制,它会在启动node时,初始化事件环。详见 juejin.cn/post/684490…

与传统webServer对比

  • 传统多线程
  • node事件处理
  • 脱离带宽内存与计算量来讨论并发是没有意义的。
  • 在内存受限的情况下,node.js就有优势了。
    • 传统server,假设一个进程需要1M内存,为了能同时开1000进程,你需要额外的1G内存来给它。
    • 而对于node.js,它可能只需要20M来完成这个事,代价就是每个客户端都可能需要多等那么一小会儿。
  • node.js的优势严格来说不是并发而是“非阻塞”

总结

我们所看到的node.js单线程只是一个js主线程,本质上的异步操作还是由线程池完成的,node将所有的阻塞操作都交给了内部的线程池去实现,本身只负责不断的往返调度,并没有进行真正的I/O操作,从而实现异步非阻塞I/O,这便是node单线程和事件驱动的精髓之处。

控制并发

  • 用eventproxy、async.mapLimit、async.queue等控制并发
  • 以eventproxy为例:分批处理任务
var EventProxy = require('eventproxy');

const most = 5;//并发数5
var urllist = [....];//待抓取url列表,100个

function foo(start){
    var ep = new EventProxy();
    ep.after('ok',most,function(){
        foo(start+most);//一个批次任务完成,递归进行下一批任务
    });
    var q=0;
    for(var i=start;i<urllist.length;i++){
        if(q>=most){
            break;//最多添加most个任务
        }
        http.get(urllist[i],function(res){
            //....
            res.on('end',function(){
                ep.emit('ok');//一个任务完成,触发一次ok事件
            });
        });
        q++;
    }
}
foo(0);

async.mapLimit和async.queue实现方式见 blog.csdn.net/qq_42306443…

其他措施

  • 举例天猫:node服务器的两个角色,解决高并发问题
    • 一个处理所有的来自客户端的https请求
    • 另一个就是为传统的服务器分发http请求
  • 增加机器分布(内存/带宽/计算力等),均衡压力
  • 其他技术方案:php+Openresty java-Netty等