node项目的线上部署与守护
发布于 9 年前 作者 weivea 6052 次浏览 最后一次编辑是 8 年前 来自 分享

关于node项目的线上部署与守护

预警:本文是作者根据自己的实践自己捣鼓的,十分粗糙,切勿盲从。若要用于线上项目,请多测试是否有坑。欢迎批评沟通与指正;

首先,我们从简单的模型分析

1、上线流程:

覆盖线上代码—》重启哈哈,没错,就是两步

2、多进程的实现:

都知道node是单线程的嘛,为了充分利用CPU性能,我们需要开启多个进程,以使用CPU的多核心

3、进程守护:

既然应用跑起来了,自然不能让它挂了呀,所以需要一个守护进程嘛,

下面,我们来一步一步解决问题

这里先给出代码目录结构:

- rootDir
	- node_modules
	- dir1
	- dir2
	- app.sh//程序启动和停止脚本
	- cluster.js//用于生成多进程
	- error.log
	- guard.sh//守护进程脚本
	- index.js//node程序入口
	- nohup.out
	- package.json

1、我们先看看怎么实现多进程就是不按套路出牌 :)

先看看我们的node入文件index.js

//其它业务逻辑
app.use(....)//一些中间件

if(module.parent){//如果是被require的,则露出app
    console.log(module);
    module.exports = function(){
        app.listen('4500');
        console.log('listening on port :4500');
    }
}else{//否则,直接启动
    app.listen('4500');
    console.log('listening on port :4500');
}

node中有一个叫Cluster的事例,就是专门来实现多线程的,有兴趣的朋友可以看一看。

官方描述:A single instance of Node.js runs in a single thread. To take advantage of multi-core systems the user will sometimes want to launch a cluster of Node.js processes to handle the load.

我们就用它实现了我们的多线程集群:cluster.js

const cluster = require('cluster');
const app = require('./index.js');
const numCPUs = require('os').cpus().length;//cpu核心数

if (cluster.isMaster) {//不是主进程,则fork workers
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }
    cluster.on('exit', (worker, code, signal) => {//有子进程退出了则重新fork
        console.log((new Date()).toLocaleString()+`:worker ${worker.process.pid} died,restart..` );
        cluster.fork();
    });
} else {
    app();//启动app
}

执行node cluster.js,查看进程,ps -ef | grep cluster.js我们可以看到有4个子进程,OK!成功

  501 18306 14421   0  4:23PM ttys001    0:00.00 grep --color=auto --exclude-dir=.bzr --exclude-dir=CVS --exclude-dir=.git --exclude-dir=.hg --exclude-dir=.svn cluster.js
  501 18292  9652   0  4:22PM ttys005    0:00.30 node cluster.js
  501 18293 18292   0  4:22PM ttys005    0:00.42 /usr/local/Cellar/node/4.2.1/bin/node /Users/weijianli/Work/tplServer_node/cluster.js
  501 18294 18292   0  4:22PM ttys005    0:00.42 /usr/local/Cellar/node/4.2.1/bin/node /Users/weijianli/Work/tplServer_node/cluster.js
  501 18295 18292   0  4:22PM ttys005    0:00.43 /usr/local/Cellar/node/4.2.1/bin/node /Users/weijianli/Work/tplServer_node/cluster.js
  501 18296 18292   0  4:22PM ttys005    0:00.42 /usr/local/Cellar/node/4.2.1/bin/node /Users/weijianli/Work/tplServer_node/cluster.js

lsof -i:4500我们看到,node占用了4500这个端口号

COMMAND   PID      USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
node    18292    weivea   21u  IPv6 0x76cf94da255eb7e3      0t0  TCP *:ipsec-msft (LISTEN)

2、接下来再看看怎么实现守护进程

guard.sh

#!/bin/sh
WEB_DIR=`pwd;`
WEB_APP='cluster.js'

#location of node you want to use
NODE_EXE=/usr/local/bin/node

#就是这么霸气,循环执行,挂了就起,看了看,其实并不恐怖,只要node应用没挂,该shell就不会往下执行
while true; do
    {
        $NODE_EXE $WEB_DIR/$WEB_APP #执行node应用
        DATE_S=`date;`
        echo "$DATE_S:Stopped unexpected, restarting \r\n\r\n" >> $WEB_DIR/error.log
    } 2>> $WEB_DIR/error.log
    sleep 2s
done

3、还需要一个简单的启动和关闭方式

app.sh终于轮到它了;

用法:
开启应用:./app.sh start
关闭应用:./app.sh stop

说说逻辑:
首先,开启应用:首先检测是否存在应用进程和应用守护进程。
如果都存在,则kill调应用进程,此时守护进程会自动再次开启应用进程;
如果有一个不存在:则先kill掉存在的应用或守护进程,再启动守护进程,守护进程会启动应用进程。在启动守护进程的时候 用来nohup命令,所以,应用中的console.log()打印的信息会输出到./nohup.out中,对于懒人来说是不是有给你设了一道防火墙,

#!/bin/sh

WEB_DIR=`pwd;`

WEB_APP='cluster.js'

GUARD='guard.sh'

guardPID=`ps -ef | grep $WEB_DIR/$GUARD | grep -v grep | head -n 1 | awk '{print $2}'`

pid=`ps -ef | grep $WEB_DIR/$WEB_APP | grep -v grep | head -n 1 | awk '{print $2}'`

if [ $1 ] && [ $1 == 'start' ]

then
if [ $guardPID ] && [ $pid ]
then
    DATE_S=`date;`
    echo "restart:$DATE_S"
    echo "restart:$DATE_S" >> $WEB_DIR/error.log
    kill $pid
else
    DATE_S=`date;`
    echo "start:$DATE_S"
    echo "start:$DATE_S" >> $WEB_DIR/error.log
    if [ $guardPID ]
    then
    kill $guardPID
    fi
    if [ $pid ]
    then
    kill $pid
    fi
    nohup $WEB_DIR/$GUARD&
fi

elif [ $1 ] && [ $1 == 'stop' ]
then
    DATE_S=`date;`
    echo "stop:$DATE_S"
    echo "stop:$DATE_S" >> $WEB_DIR/error.log
    if [ $guardPID ]
    then
    kill $guardPID
    fi
    if [ $pid ]
    then
    kill $pid
    fi
else

echo " use: $0 start    or    $0 stop"

fi

覆盖代码 sh app.sh start开启应用,或重启应用

sh app.sh stop 关闭应用

最后,shell文件仅仅在mac下运行过,linux下不知道跑起来是啥样~

对了。关于node项目的管理,有个叫pm2的东西,功能很全,也比较重型吧,当然,还有alinode

2 回复

赞一个,pm2能自动守护进程,就算挂了也能自动重启

@jiangliqin 是的呢,文章最后也提了

回到顶部