NodeJS原理及大规模部署

老袁の相声总结4

Posted by pfan8 on November 17, 2020

Node作为中间层

Node现在大部分都是做中间层

Web Node Java

​ ==> ==>

可以做到以下几点,逐步进阶:

  1. 做路由,例如vue+node,也没有跨域问题
  2. 要SEO,可以做MPA,用Node+swig模板,甚至可以做DB
  3. 做SPA和MPA混用,为了SEO和首屏直出
  4. 使用nodejs做同构,如nuxt和next

换个角度说:

  • node作为Proxy
    • API调用路由
    • 跨域
    • 提高自由度,上线时间,不被后端block
  • node作为同构层
    • vue、react
    • 后期甚至可以作为Docker独立服务
    • 中间层提高内存限制,以及QPS

P.S 如果不用Node做中间层,可以将Vue和React打包成SSR bundle,给浏览器去渲染

异步与IO

NodeJs适合IO密集型而不适用CPU密集型

  • NodeJS为什么是单线程,因为js能操作DOM,那么多个线程同时操作DOM就不知道应该采取哪一个线程的操作
  • 完美的异步IO应该是应用程序发起非阻塞调用,无需通过遍历或者事件轮询
  • windows下异步回调机制是iocp,Linux下是epool和kqueue等更多的,不同发行版不同
  • Amdahl、Gustafson定律

EventLoop

Node的异步线程通常都会丢进EventLoop中然后给对应的机制进行处理(iocp,Linux的自定义线程池)

但是有几个特殊的API不会丢到EventLoop

  • SetTimeout和Setinterval线程池不参与
  • process.nextTick()实现类似setTimeout(function(){}, o);每次调用放入队列中,在下一轮循环中取出
  • SetImmediate();比process.nextTick()优先级低
  • Node如何实现一个sleep(利用Promise和setTimeout)

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

按照历史时间顺序,1中早期的技术现在基本都被替代了

  1. Step、wind、Bigpipe、Q.js
  2. Async、Await
  3. Promise/Defferred是一种先执行异步调用,延迟传递的处理方式。Promise是高级接口,事件是低级接口。低级接口可以构建更多复杂的场景,高级接口是一旦定义,不太容易变化,不再有低级接口的灵活性,但对于解决问题非常有效
  4. 由于Node基于V8的原因,目前还不支持协程。协程不是进程或线程,其执行过程更类似于子例程,或者说不带返回值的函数调用

线程 vs 协程:

  • 线程切换上下文由系统控制
  • 协程切换上下文由自己控制

V8垃圾回收机制

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

目前V8采用了两个垃圾回收器,主垃圾回收器-Major GC(主要负责老生代的垃圾回收)和副垃圾回收器-Minor GC(Scavenger主要负责新生代的垃圾回收)。V8之所以使用两个垃圾回收器,主要是受到了代际假说的影响

关于Scavenger和Parallel垃圾回收等回收机制,这篇blog 说得很详细,先po在这,有时间的话再搬迁整理

需要补充一些的事MajorGC,在老生代的垃圾回收中,使用Mark-Sweep标记要清除的对象以及Mark-Compact压缩要保留的对象;另外用三色标记法标记对象,不,如下图

Node大规模站点部署

关于部署,接触过Java SSH或者IIS的多层架构,MVC等架构的应该能快速理解。这里也先贴上两张图,有时间的话再进行整理

补充几点

  • Nagios实现服务器监控
  • Varnish/Stupid 是Node作为中间层的cache,对Java等后端层的cache
  • 同时为了减少中间层的开销,对后端的连接采用keep alivey以及heartbeat心跳检测