弱弱地问一下,cluster 和 child_process 的使用场景
发布于 7 年前 作者 riskers 6035 次浏览 来自 问答

我对服务端开发的认知还处在 curd 的阶段,所以这些进程之类的并没有使用过。最近又开始进入 Node 的世界,所以产生了一些疑问:

  1. 大家说说在什么项目里,或者自己在什么场景下用到过进程,cluster 和 child process 的使用场景有那些,并且说说为什么
  2. 以及在大家熟悉的其他的后端语言中,是否都存在调用进程的场景

本人 3 年前端经验,就像上面说的,对服务端开发的认知还处在 curd 的阶段,所以希望大家不吝赐教。谢谢

cluster 和 child process 的概念也都看了,就是压榨机器,提升性能。不过这些是不是加机器也能做到,如果是一个集群的情况下呢?

11 回复
  1. web 应用层的开发,几乎用不到多进程的。
  2. 除去功能设计上的需要,这个后面说,多进程主要作用是“运用系统资源,特别是 CPU 多核资源”。node 单个进程是无法在多个 CPU 核调度运算。这种情况下,最简单的方式就是多个进程。但是话又说回来,多个进程这种事,也完全不需要在代码中自己去做 fork ,在上层应用层面多启几个实例就好了( node start.js --port=8000, node start.js --port=8001 这种)。
  3. 非 web 应用层开发领域,多进程一方面是功能设计上的需要,比如要并行计算(考虑你完全要自己做一个体系,不像 web 应用有一些上下层工具给你用)。另一方面,就是进程 daemon 化本身的实现。在操作系统中,只说 Linux 吧,其它系统我也不清楚细节,任何程序启动之后,都是在当前的“前台”的,你想把这个程序放到当前的“后台”,那么启动过程需要 fork 2次(比较常用的作法),这个部分涉及多进程,所以如果你需要做一些监控类的工具,或者并不是那么通用化的 server 端程序,可能也需要自己处理这些细节(至于为什么要 fork 2次,随便一搜都能找到了,比如 http://blog.chinaunix.net/uid-27105712-id-3356916.html

@atian25 谢谢大神回复

现在用到 puppeteer 来做测试平台,场景如下: 我要每分钟查一次表 report_list 中 status=1 的字段来得到数据,根据得到的一串数据(比如10条),执行一次计算(跑一遍puppeteer,然后截图,并且上传到 CDN,这个过程要1分钟左右,10条就是10分钟),然后把得到的 CDN地址存入另一张表,同时把report_list中这条记录status置为0.

我的思路卡在:在 schedule 中每分钟查库,然后执行命令,但是这个命令(可能会10分钟),这样就会每分钟开启一个10分钟的任务,这样对么?不知道这种情况应该怎么设计,是要运用到 cluster 么

@yszou 请看看我上面补充的描述,这种场景下我该怎么设计

  • cluster 底层就是 child_process
  • master 进程做中控,启动 1 个 agent 和 n 个 worker
  • agent 来做任务调度,跟数据库交互来获取任务,并分配给某个空闲的 worker 来做
  • worker 就是 cluster 出来的。

@riskers

是我做的话,我不会自己去做 fork 的。

我只写一个程序,这个程序做的事,首先,这个程序自带 timer ( nodejs 已经有了),然后,每 10 秒查一次库吧,不需要 1 分钟,因为查询成本不高,这个自己控制(因为自带 timer ,所以只要把异常处理好,这个程序可以一直运行的。有异常挂掉也没什么,外面还有专门的进程管理工具兜底)。每查一次库,只取一条 report 记录,并把它的 status 先改成 2 ,表示“正在处理之类”,这个 update 操作注意加锁,别让其它程序也查到同样的记录了(关系数据库基本功能)。同时可以在记录中加个属性,表示“开始处理的时间”,还可以加个属性,表示“处理程序的进程ID”。

然后,这个程序开始做需要做的事,比如需要 1 分钟才能完成。正常结束之后,再 update 把 status 改成 0 。

接着,找一个专门的进程管理工具,nodejs 的 PM2 (没用过,看介绍应该做进程管理用的), Python 的 supervisor 等,根据机器的配置, CPU 核数,在不同机器上启动 N 个这个程序就好了。剩下的事进程管理工具会解决,记得做成随机器启动。

再完善一点,可以再作一个专门的额外监控程序,每 1 分钟检查一下 report 记录的状态,通过“开始处理时间”判断一下,如果这个时间超过了 2 分钟,明显不正常了,那么通过 supervisor (我不知道 PM2 有没有) 的 RPC 接口,把对应的进程干掉,重启,对应 status 改成 1 。(这个额外的程序也可以加到进程管理工具的启动当中,即使没台机器都重复跑了一个这样的东西,也没有关系)

简简单单的,这个小的程序你部署到几十台机器都没有问题。(当然,如何部署分发,是另一个话题了)

你们说的已经很全了。我再补充个实践例子,比如webpack打包的时候,文件越多越慢,其实也可以利用这个机制来实现多进程打包的。ykit就是这样做的。

@yszou 谢谢,因为是基于 eggjs 搞得,所以你说的这些操作我理解是不是能放在 agent.js 里去做。https://eggjs.org/zh-cn/core/cluster-and-ipc.html

@riskers

怎么写看你自己了吧。 跟 web 没关系,跟 eggjs 也没有直接关系的。你写一个 worker.js 放到项目的任何一个地方就可以了,反正运行只是 node worker.js 就好了啊。

@riskers 三楼的就等于需要跑10个子进程,直接child_process.exec不好吗。。

楼主的问题怎么解决的,多线程的问题先不说,

如果每分钟开始一个新任务,任务周期都是10分钟,产生速率比消耗速率大,这样任务数量会越来越多吧,资源会被撑爆了对吗?

回到顶部