首頁  >  文章  >  web前端  >  如何使用node中cluster集群

如何使用node中cluster集群

php中世界最好的语言
php中世界最好的语言原創
2018-06-04 09:38:091708瀏覽

這次帶給大家如何使用node中cluster集群,使用node中cluster集群的注意事項有哪些,下面就是實戰案例,一起來看一下。

結論

雖然平常透過設定為CPU進程數的工作進程,但是可以超過這個數,並且並不是主進程先創建

if (cluster.isMaster) {
 // 循环 fork 任务 CPU i5-7300HQ 四核四进程
 for (let i = 0; i < 6; i++) {
  cluster.fork()
 }
 console.log(chalk.green(`主进程运行在${process.pid}`))
} else {
 app.listen(1314) // export app 一个 Koa 服务器的实例
 console.log(chalk.green(`子进程运行在${process.pid}`))
}
#子进程运行在17768
#子进程运行在5784
#子进程运行在11232
#子进程运行在7904
#主进程运行在12960
#子进程运行在4300
#子进程运行在16056

在主進程中cluster 表示主進程(用於監聽、發送事件), process 是本身的進程,worker 表示子進程,透過cluster.workers 取得

在子進程中process 表示子程序(用於監聽、發送事件),也可以透過cluster.worker 表示目前子程序

cluster.worker.process 等價於process(在子程序中)

#主程序子程序相互通訊

  1. #cluster 用來監聽process(child) 子程序觸發的各種事件

  2. worker 在主流程中獲取,用於和自身通訊。當子程序觸發事件時,會傳回目前的worker 以及相關的資訊到主程序對應的事件中

  3. #process(parent) 主程序本身的程序實例,在通訊過程中基本上沒有用到

  4. process(child) 子程序本身的實例,只能在子程序取得用於監聽自身的事件

可見主進程與子進程透過這樣一個三角關係互相通信,其中cluster 和worker 是在主進程中取得的,process(child) 是子進程。 cluster 透過操作 worker 通知子進程,子進程本身和 cluster 進行通訊。為什麼要這樣設計呢?因為子進程會有多個,只有透過worker 才能選擇和哪個進程通訊

子進程的調度策略cluster.schedulingPolicy

調度策略,包括循環計數的cluster.SCHED_RR,以及由作業系統決定的cluster.SCHED_NONE。這是一個全域設置,當第一個工作進程被衍生或調動cluster.setupMaster()時,都將第一時間生效。除Windows以外的所有作業系統中,SCHED_RR都是預設值。只要libuv可以有效地分發IOCP handle,而不會導致嚴重的效能衝擊的話,Windows系統也會更改為SCHED_RR。 cluster.schedulingPolicy 可以透過設定NODE_CLUSTER_SCHED_POLICY環境變數來實現。這個環境變數的有效值包括"rr" 和 "none"。

RR 即 Round-Robin 輪詢調度,即每個子程序的獲取的事件的機會是均等的,這是除 windows以外預設的。而 windows 下的調度策略很詭異,見下圖。目前並沒有相關API 可以設定調度策略的演算法,node 只為我們提供了兩個值

進程調度演算法.png

測試資料為1000次並發請求,重複測試20次,在windows下的表現。可見 windows 的調度演算法表現的雜亂無章。如果是 RR 演算法四條程序的調度應該處於同一橫線上。暫時沒在本地搭建 linux 環境,有條件的同學可以協助測試一波。
cluster的調度演算法目前至於系統有關

多進程間的鑑權問題

注意:Node.js 不支援路由邏輯。因此在設計應用時,不應該過度依賴記憶體資料物件(如sessions和login等)。由於各工作進程是獨立的進程,它們可以根據需要隨時關閉或重新生成,而不影響其他進程的正常運作。只要有存活的工作進程,伺服器就可以繼續處理連線。如果沒有存活的工作進程,現有連線會遺失,新的連線也會被拒絕。 Node.js不會自動管理工作進程的數量,而應該由具體的應用根據實際需求來管理進程池。

文档中已明确说明了,每一个工作进程都是独立的,并且互相之间除了能够进行通信外,没有办法共享内存。所以在设计鉴权的时候,有两种方法

  1. 通过共有的主进程存储鉴权信息,每次前端提交帐号密码,授权完成后,将 token 发送给主进程,下次前台查询时先在主进程获取授权信息

  2. 通过统一的外部 redis 存取

两种方法看来还是第二种好的不要太多,因此多进程的环境下,应该使用外部数据库统一存储 token 信息

进一步的子进程间通信思考

虽然 node 中并没有直接提供的进程间通讯功能,但是我们可以通过主进程相互协调进程间的通讯功能,需要定义标准的通信格式,例如

interface cmd {
 type: string
 from: number
 to: number
 msg: any
}

这样通过统一的格式,主进程就可以识别来自各个进程间的通信,起到进程通信中枢的功能

egg.js 中 agent 的实现

        +--------+     +-------+
        | Master |<-------->| Agent |
        +--------+     +-------+
        ^  ^  ^
        /  |   \
       /   |    \
      /    |     \
     v     v     v
+----------+  +----------+  +----------+
| Worker 1 |  | Worker 2 |  | Worker 3 |
+----------+  +----------+  +----------+

我们看到 egg 在多进程模型之间实现了一个 agent 进程,这个进程主要负责对整个系统的定期维护

说到这里,Node.js 多进程方案貌似已经成型,这也是我们早期线上使用的方案。但后来我们发现有些工作其实不需要每个 Worker 都去做,如果都做,一来是浪费资源,更重要的是可能会导致多进程间资源访问冲突。举个例子:生产环境的日志文件我们一般会按照日期进行归档,在单进程模型下这再简单不过了:

每天凌晨 0 点,将当前日志文件按照日期进行重命名

销毁以前的文件句柄,并创建新的日志文件继续写入

试想如果现在是 4 个进程来做同样的事情,是不是就乱套了。所以,对于这一类后台运行的逻辑,我们希望将它们放到一个单独的进程上去执行,这个进程就叫 Agent Worker,简称 Agent。Agent 好比是 Master 给其他 Worker 请的一个『秘书』,它不对外提供服务,只给 App Worker 打工,专门处理一些公共事务。

这样我们可以指定一个进程作为 agent 进程,用于实现自己定义的事务。在 egg 中,主线程启动后 首先 fork agent进程,当 agent 进程启动完成后再启动具体的 worker 进程。参照上面的代码,相信这部分逻辑现在也不难实现了。这样 agent 就会获得 id 为1的进程

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

如何使用vue中实现点击空白处隐藏div实现

怎样使用JS+setInterval实现计时器

以上是如何使用node中cluster集群的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn