tips
2017-05-18 本文已影响19人
crosstrack
1.node采用子进程的方式来解决单一进程的阻塞
2.node 利用libuv作为平台层来实现和操作系统的剥离
3.node 怎么做事件循环的?i/o密集型应用是什么
4.node怎么通过c++扩展
1.CommonJS规范:希望js能运行在任何地方
2.模块加载顺序:
- 核心模块
- 路径形式的文件模块
- 自定义模块
3.模块编译:
对于不同文件扩展名,载入方法不同
- .js文件:通过fs模块同步读取文件后编译
- .node:c,c++ 编写的扩展文件,通过dlopen
- .json : 通过fs模块同步读取文件后,JSON.parse()
1. 实现异步
Node在不同平台下异步I/O的实现2. 我们提到的node单线程,仅指js执行在单线程中。在node的实现过程中,内部都是通过线程池实现I/O任务
异步I/O流程线程池 ----》 iOS中的GCD
时间循环 ----》 iOS中的runloop
3. setImmediate 优先级低于nextTick(),都用于立即异步执行代码段
1.难点
- 异常处理
- 函数嵌套过深,在回调里再异步,没有做到并行
- 阻塞代码,使用settimeout方法
- 多线程编程
- 异步转同步
2.异步编程解决方案
- 事件发布/订阅模式
- 利用事件队列解决雪崩问题 (类似:dispatch_once)
- 多异步之间的协作方案(dispatch_group)
- promise/deferred模式 (内部封装,把事件隐藏,只把成败状态暴漏,类似signal),
promise负责对外提供then
defer对内,提供对具体事件的对接 - 流程控制库
- async
- step
- eventProxy
- wind
- 异步并发控制
类似nsoperation来控制并发量:
- bagpipe
- async 的parallelLimit
内存管理
1. v8引擎在32位下分配内存最大为0.7g,64为1.4g
可以通过max-old-space-size
命令指定内存大小
2. 内存回收算法:
新生代:存活时间较短的对象
老生代:存活较久的对象
3. process.memoryUsage()查看node的内存占用情况:
> process.memoryUsage()
{ rss: 25706496, //resident set size
heapTotal: 7376896,
heapUsed: 3931200,
external: 8937 }
>
并非由node分配的内存称为堆外内存,比如buffer(256)
分配的内存,通过减少全局变量和闭包捕获的变量来减少老生代对象
4. 内存泄漏
- 缓存
使用模块会缓存模块内变量,而不释放,优先使用进程外缓存,比如Redius,Memcached - 队列消费不及时
出队速度远高于入队速度
web应用
1.
- 获取请求方法
- 路径解析
- 获取查询字符串
- cookie
- session:cookies存储session_id ,query中存储session_id
session通过高速缓存存储优化内存使用,以及加密、签名等安全策略 - etag,cache-control 等缓存处理
2. 上传
屏幕快照 2017-05-17 下午4.19.53.png注意上传过程中内存使用:
- 限制上传过程中的数据大小
- 通过流式解析将数据导入到磁盘中,node只保留小数据
3. 路由解析
3.1 文件路径型
3.2 mvc
- 自然映射
- 手动映射
- RESTFUL
use(path,func) 存储 path-->func
基于正则匹配的路径匹配:
屏幕快照 2017-05-17 下午9.18.49.png
屏幕快照 2017-05-17 下午9.19.06.png
在正则匹配的过程中同时提取出参数
通过对routes增加分类来实现RESTful需求:
中间件:尾触发的方式实现:
var middleware = function(req, res, next) {
// TODO
next()
}
通过use(path, middleware, middleware ...) 存储 path-->stack 实现存储多个func
改造match方法,在找到匹配的路径时不停止,而是全部遍历,保存所有的func,
核心方法:
- use 用来存储(app.get(),app.post 同)
- 构造server方法:匹配路径
- 流水线方法,驱动尾调用运转
- match方法,通过匹配路径获得参数和匹配的中间件
3.3 异常处理
修改handle方法:增加错误处理逻辑
屏幕快照 2017-05-17 下午10.00.17.png错误处理中间件同样可以传递异常。异常中间件有四个参数
var errhandler = function(err, req, res, next) {
// TODO
next()
}
同时在上面四个方法之外增加handle500方法:
handle5003.4 中间件性能
- 高效代码:缓存需要重复计算的结果(传入到req里去)
- 合理使用路由: 提高路由匹配的命中率
3.5 页面渲染
影响终端对响应报文处理是报头的content-*字段
content-disposition 字段 制定下载文件
inline:直接打开, attachment 存为附件
4服务器稳定控制
- 创建子进程,多个子进程监听同一个端口。
- 代理服务器的方式会消耗双倍的文件描述符,不推荐,
- IPC 实现方式:命名管道、匿名管道、信号量、socket、共享内存,node在ipc 的应用层有message事件和send()方法
- send()方法能发送句柄,比如一个套接字,句柄的发送和还原类似于反射,发送句柄(文件描述符,本质上是整数)和message(包含数据类型)
- node除了message事件,还包含
- error
- connection
- disconnect
- close
- exit
- error
- 退出进程的两种方式:
child.kill()
process.kill(pid,[signal])
屏幕快照 2017-06-06 下午3.31.36.png
- 通过exit事件可以实现子进程的自动重启,每个exit都重新生成新的工作子进程,并维护相应的进程字典。在子进程遇到未捕获的异常会触发退出,在该进程所有连接都断开后退出 --》改进,这种退出会使子进程在等待退出的过程中不响应新连接,未避免所有子进程同时假死,在close时向主进程通信,提前生成子进程,同时设置等待超时,强行退出子进程 ---》改进,增加数组,未避免子进程过多重启,记录每次重启的时间戳和退出原因,在过多重启后抛出异常
- 负载均衡,round-robin 轮叫调度
- 进程间状态共享 :第三方数据存储
数据变更如何通知各个进程,两种方式:
- 拉,各个进程轮询数据源有无变化
- 推, 有一单独进程负责拉,再向各个进程推
- cluster模块用来创建node集群,本质就是在fork后在执行了预传的回调
5 测试
- 单元测试:基于断言,测试框架会在断言处理里持续进行所有测试并生成测试报告,第三方:mocha,mock(模拟难以真实遇到的异常),rewire(测试内部方法)
- 工程化与自动化: makefile、 travis-ci
- 性能测试:基准测试(benchmark),压力测试(ab、siege、http_load)
6 产品化
- 目录结构
- 构建工具
makefile,grunt - 编码规范
- 代码审查
- 架构设计
6 .2 部署
利用bash shell 脚本来部署服务
6.3 性能
开源节流,加快计算速度,缓存、优化不必要的计算
- 动静分离
- 多进程架构
- 启用缓存
- 读写分离
6.4 日志
按级别、日期记录运行日志
6.5 监控
监控内容、报警的实现
6.6 异构共存
7. 附录
- precommit