深入浅出Node

0. 总结

这本书,从实战方面诠释了NODE的原理

笔者第一次读完时,很多是跳过的,因为没有相关的实践操作,留个影响,相信以后会有想起来应用的时候

4星(322页)

1. Node简介

1.2 Node的命名和起源

Ryan Dahl是一名资深的c/c++程序员

他认为:设计高性能Web服务器的几个要点:

  1. 事件驱动
  2. 非阻塞IO

他的在选JS之前,其他语言的考虑

  1. c门槛太高
  2. haskell: 作者自己玩不6
  3. lua: 自身已经有很多阻塞的库
  4. Ruby: 性能不好

1.3 Node给javascript带来的意义

Node = Chrome - HTML - Webkit

1.4 Node的特点

1.4.1 异步I/O

1.4.2 事件与回调函数

事件的编程方式具有轻量级、轻耦合、只关注事物点等优势,但是在多个异步任务的场景下,事件和事件之间各自独立,如何协作是一个问题

1.4.3 单线程

优点:

  1. 不用像多线程那样处处在意状态同步问题
  2. 不存在死锁
  3. 不存在线程上下文交换带来的性能开销

缺点

  1. 无法利用多核CPU
  2. 错误会引起整个应用退出
  3. 大量计算占用CPU导致无法继续调用异步I/O

在浏览器中主线程可以负责UI,而把大量的计算放在webworker

而Node,主线程负责响应,而可以child_process进行大量计算

这样

缺点1变成了: 可以利用多核进行大量计算 缺点3变成了: 可以利用多核进行计算

但是缺点2呢?.

1.5 Node的应用场景

1.5.1 I/O密集型

2. 模块机制

2.2 Node的模块实现

2.2.1 优先从缓存加载

其实无论是webpack还是浓的,都是从优先缓存读取的

所以require里的文件只会被第一次引用的时候执行,然后缓存起来

2.2.2 路径分析和文件定位

默认不带文件后缀时,会按.js,.json,.node 的顺序查找,所以一般只会隐藏.js,而.json,.node不会隐藏后缀

2.2.3 模块编译

  1. .js: 通过fs模块同步读取后编译执行
  2. .node: c/c++编写的拓展文件,通过dlopen()方法加载最后编译生成的文件
  3. .json: 通过fs同步读取,然后JSON.parse()解析返回结果
  4. 其余拓展名文件,会被当做js文件载入

3. 异步I/0

3.2 异步I/0实现现状

3.2.1 异步I/O与非阻塞I/O

阻塞I/O:

阻塞I/O调用过程

与阻塞I/O对应的是非阻塞I/O

两者的主要区别是

  1. 阻塞I/O完成整个获取数据的过程
  2. 非阻塞I/O则不带数据直接返回,要获取数据,还需要通过文件描述符再次读取,需要通过轮询多次访问

3.5 事件驱动与高性能服务器

几种经典的服务器模型

  1. 同步式
  2. 每进程/每请求
  3. 每线程/每请求

每线程/每请求的方式目前被apache所使用

node通过事件驱动方式处理请求,无需为每个请求创建额外的对应进程,可以省掉创建线程和销毁线程的开销,同时操作系统在带哦度任务时因为线程较少,上下文切换代价很低.这是Node高性能的一个原因

4. 异步编程

4.2 异步编程的优势与难点

4.2.2 难点

  1. 异常处理: 原则上只需执行调用者传入的回调函数,正确传递回异常提供调用者的判断
  2. 函数嵌套过剩
  3. 阻塞代码
  4. 多线程编码
  5. 异步转同步

4.3 异步编程解决方案

  1. 事件发布/订阅
  2. Promise/Deferred模式
  3. 流程控制库

4.3.2 Promise/Deferred模式

Promises/A的抽象定义

  1. Promises操作只会处于三种状态中的一种: 未完成,完成,失败
  2. Promises的状态只会出现从未完成向完成或失败转化,不能逆反,完成和失败也不能互相转化
  3. Promises的状态一旦转化,将不能改变

(笔者疑问: 当我们获取到json数据时,是在完成态,然后发现json数据格式不对,不能从完成转到失败?)

Api定义上,一个Promise对象只要具备then方法即可

  1. 接受完成态、错误态的回调方法,在操作完成或出现错误时,将会调用对应方法
  2. 可选地支持progress事件回调作为第三个方法
  3. then()方法只接受function对象,其余对象将会被忽略
  4. then()方法继续返回promise对象,以实现链式调用

then(fulfilledHandler, errorHandler, progressHandler)

Promise是高级接口,事件是低级接口,低级接口可以构成更多更复杂的场景,高级接口一旦定义,不太容易改变,但对于解决典型问题非常有效

4.3.3 流程控制库

  1. 尾触发和next
  2. async
  3. step

5. 内存控制

5.1 V8的垃圾回收机制与内存限制

5.1.3 V8的对象分配

查看内存分配

> process.memoryUsage()
{ rss: 21692416, heapTotal: 9587488, heapUsed: 4757408 }

可以在启动node时,更改内存限制

node --max-old-space-size=1700 test.js //单位为MB 设置老生代内存空间
node --max-new-space-size=1024 test.js //单位为kb 设置新生带内存空间

一旦设置启动后,不能更改

为什么V8要限制内存? 因为1.5GB的垃圾回收,V8做一次小的垃圾回收需要50毫秒以上,做一次非增量的垃圾回收深圳要1s以上

5.1.4 V8的垃圾回收机制

V8的垃圾回收策略主要基于分代式垃圾回收机制

回收算法     Mark-Sweep Mark-Compact Scavenge
速度        中等        最慢          最快
空间开销     (有碎片)   (有碎片)    双倍空间(无碎片)
是否移动对象  否          否           是

5.1.5 查看垃圾回收日志

启动时添加--trace_gc参数,会在打印台输出垃圾回收信息

加上--prof可以得到V8执行时性能分析数据,其中包含垃圾回收执行时占用时间

可以通过linux-tick-processor(在node源码的tool里) 用于统计日志信息

6. 理解Buffer

6.1 Buffer结构

Buffer是一个像Array的对象,主要用于操作字节

6.1.1 模块结构

Buffer是一个典型的Javascript与C++结合的模块

性能由C++实现,并非性能相关的javascript实现

node_buffer(c++)->Buffer/SlowBuffer(javascript核心模块)

6.2 Buffer的转换

6.2.2 Buffer转字符串

buf.toString([encoding], [start], [end])

7. 网络编程

8. 构建web应用

8.1 基础功能

Cookie的性能影响

  1. 为静态组件使用不同的域名

9. 玩转进程

10. 测试

这里讲了测试的基础概念,讲述了单元测试,自动集成和性能测试的一些基本方法

11 产品化

11.5 监控报警

11.5.1 监控

  1. 日志监控
  2. 响应时间
  3. 进程监控
  4. 进程监控
  5. 磁盘监控
  6. 内存监控
  7. CPU占用监控
  8. CPU load监控
  9. I/O监控
  10. 网络监控
  11. 应用状态监控
© 404mzk all right reserved,powered by Gitbookhttp://read.404mzk.com 该文件修订时间: 2017-03-09 00:03:25

results matching ""

    No results matching ""