9.1 服务模型的变迁
同步:最早的服务器,其执行模型是同步的,一次只为一个请求服务。
复制进程:每个连接需要一个进程来服务
多线程:数量多时,时间将会被耗用在上下文切换中。无法做到强大的伸缩性。
事件驱动
:采用单线程避免了不必要的内存开销和上下文切换开销。单线程的架构并不少见,其中尤以PHP最为知名—在PHP中没有线程的支持。它的健壮性是由它给每个请求都建立独立的上下文来实现的。但是对于Node来说,所有请求的上下文都是统一的,它的稳定性是急需解决的问题。
9.2 多进程架构
面对单进程单线程对多核使用不足的问题,前人的经验是启动多进程即可。Node提供了child_process模块,
通过fork()复制的进程都是一个独立的进程,这个进程中有着独立而全新的V8实例。它需要至少30毫秒的启动时间和至少10MB的内存。尽管Node提供了fork()供我们复制进程使每个CPU内核都使用上,但是依然要切记fork()进程是昂贵的。好在Node通过事件驱动的方式在单线程上解决了大并发的问题,这里启动多个进程只是为了充分将CPU资源利用起来,而不是为了解决并发问题。
创建子进程
:child_process模块
进程间通信
:onmessage()和postMessage()进行通信。
句柄传递
:多个子进程可以同时监听相同端口,再没有EADDRINUSE异常发生了。
9.3 集群稳定之路
搭建好了集群,充分利用了多核CPU资源,似乎就可以迎接客户端大量的请求了,但还有一些细节需要考虑:
- 性能问题
- 多个工作进程的存活状态管理
- 工作进程的平滑重启
- 配置或者静态数据的动态重新载入
- 其他细节
进程事件:进程间通信
自动重启:自杀信号、限量重启、
负载均衡
:在多进程之间监听相同的端口,使得用户请求能够分散到多个进程上进行处理,这带来好处是可以充分利用CPU资源。
Node默认采用抢占式策略,在一堆工作进程中,对请求进行争抢,谁抢到谁服务,对大家都是公平的,从而实现负载均衡。
v0.11中提供了新的策略叫Round-Robin,轮叫调度,由主进程分发。
状态共享
:第三方数据存储(数据库、磁盘文件、缓存服务)、主动通知(当数据发生更新时,主动通知子进程)
9.4 Cluster模块
以上介绍的是如何通过child_process模块构建强大的单机集群。而Cluster模块更方便实现。