node项目架构与优化

为什么要用node

1、前后端耦合太紧密,中间加一层node,还要给前端装一些乱七八糟的东西  java啥的服务环境。还有后台返回接口的时候不管前端需不需要那些接口一起返回,其实只用到1~2 条数据。本来ajax就非常消耗时的事,就用其中一条,用node做一层中间层处理把没用的接口剔除掉。

2、比如:一个10天项目,后台开发6天,前台2天,测试2天。后台开发时,没有接口,前端得等着后台的接口,如果后台某种情况推迟了一天,前端就1天开发,测试要2天,肯定前端开发不完。使用node我们可以并行开发,提高开发效率。

3、proxy 代理层    java->node    前端->node  这种情况叫BFF,后台是没有跨域的。做了一层中间代理,可以自己控制路由,前端请求发给node,就不会出现跨域的问题。node socket io 实时通讯。

4、node容错,性能难做。

node异步IO原理浅析及优化方案

  • 异步IO的是与非

    前端通过异步IO可以消除UI阻塞。
    假设请求资源A的时间为M,请求资源B的时间为N,那么同步的请求耗时就为M+N,如果采用异步的方式占用时间为MAX(M,N)。
    随着业务的复杂,会引入分布式系统,时间会线性的增加M+N+...和MAX(M,N,...),这会放大同步和异步之间的差异。
    I/O是昂贵的,分布式I/O是更昂贵的。

    一些底层知识

    1、

      CPU是钟周期:1/CPU主频->1s/3.1GHz

      一级CPU是钟周期:3.5GHz   1/3.5*3  io时间

    2、

    p是并行系统钟的处理器数量;

    f=ws/w为串行部分的比例;

     我们分布到其他机器里,每个机器都用同样的代码。网络要请求这文件,就比较慢 整个时间就比较长。

     并不是所有的所有并行的好,也并不少所有串行就好,分情况。系统会自动根据情况来判断使用并行还是串行。

    3、操作系统对计算机进行来抽象,将所有输入输出设备抽象为文件。内核在进行文件I/O操作时,通过文件描述符进行管理。应用程序如果需要进行I/O需要打开文件描述符,在进行文件和数据的读写。异步IO不带数据直接返回,要获取数据还需要通过文件描述符再次读取。

   

 

    

    NodeJS使用与IO密集型不适用于CPU密集型

    比如银行,每次计算价格,java是多线程可以处理多个任务,而Nodejs是单线程用异步不停的写,写发上也非常复杂。可以有框架处理单线程问题,但是性能上还是不如java。

  • Node对异步IO实现

  完美的异步IO应该是应用程序发起阻塞调用,无需通过便利或者事件幻想等方式轮询。

前端的event loop跟node event loop不一样,前端比node event loop还要复杂一些。node程序进来不停的转,就等于我们把米放到电饭煲里,定好时间,我们去忙别的,等他做好之后,会提示,已经做好了。

  • 几个特殊对API

    1、setTimeout和setInterval线程池不参与

    2、process.nextTick()实现类似setTimeout(function(){},0);每次调用放入队列中,在下一轮循环中取出。

    3、setImmediate();比provess.nextTick()优先级低

    4、Node如何实现一个Sleep?

    

async function test(){
  console.log('hello');
  await seelp(1000);
  console.log('word');         
}
function seelp(time){
  return new Promise(resolve=>setTimeout(resolve,time))
}
test()

 

  • 函数式编程在Node中对应用

    1、高阶函数:可以将函数作为输入或者返回值,形成一种后续传递风格的结果接受方式,而非单一的返回值形成。后续传递风格的程序将函数业务重点从返回值传递到回调函数中。

app.use(function(){
   //todo 
})
var emitter = new event.eventEmitter;
emitter.on(function(){
    //todo
})

    2、偏函数:指定部分参数产生一个新的定制函数的形式就是偏函数。node中异步编程非常常见,我们通过哨兵变量会很容易造成业务的混乱。underscore,after变量。

  • 常用的Node控制异步API的技术手段

    1、step、wind(提供等待的异步库)、bigpipe、Q.js

    2、Async、Await

    3、Promise/Defferred是一种先执行异步调用,延迟传递的处理方式。Promise是高级接口,事件是低级接口。低级接口可以构建更多复杂的场景,高级接口一旦定义,不太容易变化,不再有低级接口的灵活性,但对于解决问题非常有效。

    4、由于Node基于V8的原因,目前还不支持协程。协程不是进程或线程,其执行过程更类似于子例程,或者说不带返回值的函数调用。

    一个程序可以包含多个协程,可以对比一个进程包含多个线程。来比较协程和线程。我们知道多个线程相对独立,有自己的上下文,切换受系统控制;而协程也相对独立,有自己的上下文,但是其切换由自己控制,由当前协程切换到其他协程有当前协程来控制。

内存管理与优化

   V8垃圾回收机制

    node使用javascript在服务端操作大内存对象受到了一定的限制,64位系统下约为1.4GB,32位系统是0.7GB

    process.memoryUsage->rss、heaptTotal、heapUsed

    V8的垃圾回收策略主要基于分代式垃圾回收机制。在自动垃圾回收的演变过程中,人们发现没有一种垃圾回收算法能够胜任所有场景。V8内存分为新生代和老生代。新生代为存活时间较短对象,老圣代为存活时间较长的对象。

   Scavenge算法

    在分带基础上,新生代的对象主要通过Scavenge算法进行垃圾回收,在具体实现时主要采用cheney算法,cheney算法是一种采用复制的方法实现的垃圾回收算法。它将内存一分为二,每一个空间称为semispace。这两个semispace中一个处于使用,一个处于闲置。处于使用的称之为From,检查From存活对象复制到To。非存活被释放。然后互换位置。再次进行回收,发现被回收过直接晋升,或者发现To空间已经使用来超过25%。他的缺点只能使用堆内存的一半,这是一个典型的空间换时间的办法,但是新生代生命周期较短,恰恰就适合这个算法。

  

  老生代空间生成完成肯定要有东西管理它,就有来mark-sweep和mark-compact

    V8老生代主要采用mark-sweep和mark-compact,在使用Scavenge不合适。一个是对象较多需要赋值量太大而且还是没能解决空间问题。Mark-Sweep是标记清除,标记那些死亡的对象,然后清除。但是清除过后出现内存不连续的情况,所有我们要使用Mark-Compact,他是基于mark-sweep演变而来的,它现将活着的对象移到一边,移动完成后,直接清理边界外的内存。当CPU空间不足的时候会非常高效。V8还引入来延迟处理,增量处理,并计划引入并标记处理。

  

  常见的内存泄漏问题

  1、无限制增长的数组

  2、无限制设置属性和值

  3、任何模块内的私有变量和方法均是永驻内存的a=null

  4、大循环,无GC(垃圾回收机制)机会

  内存泄漏分析

  node-inspector

  console.log("Server PID",process.pid);

  sodu node --inspect app.js

  whie true;do curl "http:localhost:1337/";done

  top -pid 2322

大规模Node站点结构原理分析

  经典的MVC框架

  model-view-Controller

javaweb多层架构

node 集群应用

   预备上线

  1、前端工程化的搭载动态文件的MAP分析压缩打包合并至CDN

  2、单侧、压力测试、性能分析工具发现Bug

  3、编写nginx-conf实现负载均衡和反向代理

  4、PM2启动应用生序小流量灰度上线,修复Bug

  5、上线前的不眠夜、你见过凌晨5点的北京么?

  多线程

  1、master进程均为主进程,Fork可以创造主进程。

  2、通过child_process可以和NET模块组合,可以创建多个线程并监听统一端口。通过句柄传递完成自动启动、发射自杀信号、限量重启、负载均衡。

  3、node默认的机制是采用操作系统的抢占式策略。闲着的进程争抢任务,但是会造成CPU闲置的IO暂时并未闲置。Node后来引入来Round-Robin机制,也叫轮询调度。主进程接受任务,在发。

  4、每个子进程做好自己的事,然后通过进程间通信来将他们链接起来。这符合Unix的设计理念,每个进程只做一件事,并做好。将福啊分解为简单,将简单组合程强大。

  PM2

  pm2是一个自带负载均衡功能的node应用的进程管理器。

  当你要把你的独立代码利用全部的服务器上的所有CPU,并保证进程永远活着,0秒重载。

  1、内建负载均衡(使用node cluster集群模块)

  2、后台运行

  3、0秒停机重仔

  4、具有Ubuntu和CentOS的启动脚本

  5、停止不稳定的进程(避免无限循环)

  6、控制台检测

  7、提供HTTP API

  8、远程控制和实时的接口API(Nodejs 模块,允许和PM2进程管理交互)

    测试过Nodejs v0.11 v0.10 v0.8版本,兼容CoffeeScript,基于linux和MacOs

  

我之前是前端连java感觉还可以,如果我中间加一层node,是不是就变慢了呢,并不是,首先java跟node在同样一个机房他俩请求的时间被严格限制在1ms(毫秒),甚至一些团队100ms已经顶天了,300ms服务肯定有问题。用户肯定无法感知的,node和java走了一次http,会有3次握手,即使是毫秒也是一次浪费,node和java 走的是Linux Virtual Server(Linux虚拟服务器)通信。

 

 

    

 

    

 

posted @ 2018-06-17 21:31  一棵海草  阅读(4710)  评论(0编辑  收藏  举报