文章插图
接下来会做两个实验:第一个实验是在 Centos 机器上 , 第二个实验是在 Docker 镜像中
实验一:在 Centos 上 , systemd 作为 PID 为 1 的进程下面来做一些测试 , 修改上面的代码 , 将父进程 sleep 的时间改短为 15s , 新建一个 make_zombie.c 文件 , 如下所示 。
#include <stdio.h>#include <stdlib.h>#include <unistd.h>int main() {printf("pid %dn", getpid());int child_pid = fork();if (child_pid == 0) {printf("-----in child process:%dn", getpid());exit(0);} else {sleep(15);exit(0);}}
编译生成可执行文件 make_zombie 。gcc make_zombie.c -o make_zombie
然后新建一个 run.js 代码 , 内部启动一个进程运行 make_zombie , 如下所示 。const { spawn } = require('child_process');const cmd = spawn('./make_zombie');cmd.stdout.on('data', (data) => {console.log(`stdout: ${data}`);});cmd.stderr.on('data', (data) => {console.error(`stderr: ${data}`);});cmd.on('close', (code) => {console.log(`child process exited with code ${code}`);});setTimeout(function () {console.log("...");}, 1000000);
执行 node run.js 运行这段 js 代码 , 使用 ps -ef 查看进程关系如下 。UIDPIDPPIDC STIME TTYTIME CMDya19234 192310 12月20 ?00:00:00 sshd: ya@pts/6ya19235 192340 12月20 pts/600:00:01 -zshya29513 192353 15:28 pts/600:00:00 node run.jsya29519 295130 15:28 pts/600:00:00 ./make_zombieya29520 295190 15:28 pts/600:00:00 [make_zombie] <defunct>复制代码
过 15s 以后 , 再次执行 ps -ef 查询当前运行的进程 , 可以看到 make_zombie 相关进程都不见了 。UIDPIDPPIDC STIME TTYTIME CMDya19234 192310 12月20 ?00:00:00 sshd: ya@pts/6ya19235 192340 12月20 pts/600:00:01 -zshya29513 192353 15:28 pts/600:00:00 node run.js
这是因为 PID 为 29519 的 make_zombie 父进程在 15s 以后退出 , 僵尸子进程被托管到 init 进程 , 这个进程会调用 wait/waitfor 为这个僵尸收尸 。实验二:在 Docker 上 , node 作为 PID 为 1 的进程将 make_zombie 可执行文件和 run.js 打包为 .tar.gz 包 , 随后新建一个 Dockerfile , 内容如下 。
#指定基础镜像FROMregistry.gz.cctv.cn/library/your_node_image:your_tagWORKDIR /#复制包文件到工作目录 , . 代表当前目录 , 也就是工作目录ADD test.tar.gz .#指定启动命令CMD ["node", "run.js"]
执行 docker build 命令构建一个镜像 , 在我的电脑上 Image ID 为 ab71925b5154 , 执行 docker run ab71925b5154 , 启动 docker 镜像 , 使用 docker ps 找到镜像 CONTAINER ID , 这里为 e37f7e3c2e39 。随即使用 docker exec 进入到镜像终端docker exec -it e37f7e3c2e39 /bin/bash
执行 ps 命令查看当前的进程状况 , 如下所示 。UIDPIDPPIDC STIME TTYTIME CMDroot101 07:52 ?00:00:00 node run.jsroot1210 07:52 ?00:00:00 ./make_zombieroot13120 07:52 ?00:00:00 [make_zombie] <defunct>
等一段时间(15s) , 再次执行 ps 查看当前进程 , 如下所示 。UIDPIDPPIDC STIME TTYTIME CMDroot100 07:52 ?00:00:00 node run.jsroot1310 07:52 ?00:00:00 [make_zombie] <defunct>
可以看到 PID 为 13 的僵尸进程已经托管到 PID 为 1 的 node 进程 , 但是没有被回收 。这是 node 不适合做 init 进程的最主要原因:无法回收僵尸进程 。
说到 node , 这里提一下 npm , npm 实际上是使用 npm 进程启动了一个子进程启动了 package.json 中 scripts 里写的启动脚本 , 示例 package.json 脚本如下所示 。
{"name": "test-demo","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo "Error: no test specified" && exit 1","start": "node run.js"},"keywords": [],"author": "","license": "ISC","dependencies": {}}
使用 npm run start 启动 , 得到的进程如下所示 。ya19235 192340 12月20 pts/600:00:01 -zshya32252 192350 16:32 pts/600:00:00 npmya32262 322520 16:32 pts/600:00:00 node run.js
与 node 一样 , npm 也不会处理僵尸子进程回收 。线上问题分析我们线上出问题的情况下使用 npm start 来启动一个 Puppeteer 项目 , 每生成一次图片便会创建 4 个 chrome 相关的进程 , 如下所示 。
推荐阅读
- 防冻液多久换一次?别等到发动机出故障后才知道
- 礼仪微课五分钟 如何上好一堂礼仪课
- 纱窗几年换一次,纱窗的使用寿命是多少年
- 空调管路杀菌怎么操作,空调管路杀菌多久一次
- 福建名菜佛跳墙,原来做法这么简单,汤汁醇厚,吃一次就念念不忘
- 使用docker部署golang服务
- 储水式电热水器怎么清洗,储水式电热水器多久保养一次
- 什么是Docker?与虚拟机有什么区别?
- |第一次当领导,如何说话才显得有威信?
- 推荐5款好用的开源 Docker 工具