在开发过程中,我们一般都是使用 ssh 登录linux,在命令行下直接使用 php-cli 模式运行 swoole,一旦退出ssh 或者使用 ctrl+c,终端会收到 HUP(hangup)信号从而关闭其所有子进程 ,swoole 进程会自动关闭。
那有问题来了,没有靠谱的、可以让脚本在后台长期运行呢,答案是有的 :)
首先,我有个swoole http服务需要后台运行在服务器上,绑定端口9501,查询资料了解到下面几种以守护进程方式运行脚本的方法,可能不太全面,欢迎补充 : )
PHP代码如下:
<?php
/**
* 使用Swoole实现http服务简单示例
* User: WilliamYao
* Date: 2018/4/28 16:18
*/
$http = new swoole_http_server("0.0.0.0", 9501);
$http->set(array(
'reactor_num' => 2, // 主进程内事件处理线程的数量 一般设置为CPU核数的1-4倍
'worker_num' => 4, // 启动的worker进程数。
));
// 计数器
$automic = new swoole_atomic(1);
$http->on('request', function (swoole_http_request $request, swoole_http_response $response) {
global $automic;
$automic->add(1); // 计数+1
$response->header("Content-Type", "text/html; charset=utf-8");
$response->end("<h2>FROM {$request->fd}: Hello Swoole. <br/> COUNT: #{$automic->get()} <br/>TIME: ".microtime(true)."</h2>");
});
$http->start();
一、nohub
最简单的后台运行脚本命令,nohup 能通过忽略 HUP 信号来使我们的进程避免中途被中断
$ nohub /usr/local/php/bin/php /data/www/swoole/echo/server.php > /dev/null 2>&1 &
二、/etc/ini.d/xxx
Debian发行版中,可以使用 start-stop-daemon --start/--stop 创建/停止后台进程
详细可以使用 man start-stop-daemon 查看帮助
主要参数:
--backgroud标识后台运行--pidfile指定pid文件--make-pidfile如果脚本程序本身不产生pid文件,此选项可以生成pid文件--exec执行的脚本程序 后面接--可添加参数--chuid指定运行用户/用户组
#! /bin/sh
### BEGIN INIT INFO
# Provides: swoole-echo
# Required-Start: $all
# Required-Stop: $all
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-NAMEription: starts the swoole-echo server
# Description: starts swoole-echo using start-stop-daemon
### END INIT INFO
PATH=/usr/local/php/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
NAME=swoole-echo
PIDFILE=/var/run/$NAME.pid
DAEMON=/usr/local/php/bin/php
DAEMON_OPTS=/data/www/swoole/echo/server.php
USER=www
GROUP=www
START_OPTS="--start --background --make-pidfile --chuid ${USER}:${GROUP} --pidfile ${PIDFILE} --exec ${DAEMON} ${DAEMON_OPTS}"
STOP_OPTS="--stop --pidfile ${PIDFILE}"
test -x $DAEMON || exit 0
# 若指令传回值不等于0,则立即退出shell。
set -e
start_method(){
echo -n "Starting $NAME"
start-stop-daemon $START_OPTS
echo " done"
}
stop_method(){
echo -n "Stopping $NAME"
if [ ! -r $PIDFILE ] ; then
echo "Warning, no pid file found - $NAME is not running ?"
exit 1
fi
start-stop-daemon $STOP_OPTS
sleep 1
if [ -e $PIDFILE ]
then rm $PIDFILE
fi
echo " done"
}
case "$1" in
start)
start_method
;;
stop)
stop_method
;;
restart)
stop_method
start_method
;;
*)
echo "Usage: $0 {start|stop|restart}" >&2
exit 1
;;
esac
exit 0
加入启动项:
# 添加
$ sudo update-rc.d swoole-echo defaults
# 删除
$ sudo update-rc.d -f swoole-echo remove
Red Hat发行版中,可使用 /etc/rc.d/init.d/functions 脚本中定义的方法
常用方法:
daemon: 启动某个服务。/etc/init.d目录部分脚本的start使用到这个killproc: 杀死某个进程。/etc/init.d目录部分脚本的stop使用到这个pidfileofproc: 寻找某个进程的pidpidofproc: 类似上面的,只是还查找了pidof命令status: 返回一个服务的状态
以上方法帮助用户编写启动脚本,再放到 /etc/ini.d/ 目录下,Debian使用 update-rc.d xxx defaults,RedHat中使用 chkconfig --add xxx 来加载脚本,之后便可使用 service 命令来 start/stop/restart/status 管理服务了。
三、Supervisor
Supervisor 是基于 Python 的进程管理工具,可以帮助我们更简单的启动、重启和停止服务器上的后台进程,是 Linux 服务器管理的效率工具。
Supervisor 有两个主要的组成部分:
supervisord,运行Supervisor时会启动一个进程supervisord,它负责启动所管理的进程,并将所管理的进程作为自己的子进程来启动,而且可以在所管理的进程出现崩溃时自动重启。supervisorctl,是命令行管理工具,可以用来执行stop、start、restart等命令,来对这些子进程进行管理。
只需要修改配置文件(就是这么简单。。)
$ vim supervisord.conf
[program:swoole-echo]
command=/usr/local/php/bin/php /data/www/swoole/echo/server.php;
接下来就可以使用管理进程了
$ supervisorctl stop swoole-echo // 开启进程
$ supervisorctl start swoole-echo // 关闭进程
四、Systemd
systemd 是一个 Linux 系统基础组件的集合,提供了一个系统和服务管理器,运行为 PID 1 并负责启动其它程序。功能包括:支持并行化任务;同时采用 socket 式与 D-Bus 总线式激活服务;按需启动守护进程(daemon);利用 Linux 的 cgroups 监视进程;支持快照和系统恢复;维护挂载点和自动挂载点;各服务间基于依赖关系进行精密控制。systemd 支持 SysV 和 LSB 初始脚本,可以替代 sysvinit。除此之外,功能还包括日志进程、控制基础系统配置,维护登陆用户列表以及系统账户、运行时目录和设置,可以运行容器和虚拟机,可以简单的管理网络配置、网络时间同步、日志转发和名称解析等。
Systemd 并不是一个命令,而是一组命令; 与supervisorctl 类似,有 systemctl 命令可实现 sudo systemctl start xxx命令,方便创建守护进程,启动和停止服务。
如果你的系统是 Ubuntu15.04+/CentOS7+ Systemd 已经默认代替了 init 启动方式,对与第一、第二种后台启动方式,Systemd有更强大的命令参数,更简便的配置文件,不需要额外安装软件包,还支持自动拉起服务,可以说是非常强大了,强烈推荐~
- 建立
swoole-echo.service文件
[Unit]
Description=Echo Http Server
After=network.target
After=syslog.target
[Service]
Type=simple
LimitNOFILE=65535
ExecStart=/usr/local/php/bin/php /data/www/swoole/echo/server.php
ExecReload=/bin/kill -USR1 $MAINPID
Restart=always
[Install]
WantedBy=multi-user.target graphical.target
- 复制到
/etc/systemd/system/,赋予755权限
# 创建软连接,加入守护进程列表
$ sudo systemd enable swoole-echo.service
# 重载守护进程配置
$ sudo systemctl daemon-reload
# 加入自启动
$ sudo systemctl enable swoole-echo.service
# 启动
$ sudo systemctl start swoole-echo.service
# 查看状态
$ sudo systemctl status swoole-echo.service
● swoole-echo.service - Echo Http Server By Swoole
Loaded: loaded (/etc/systemd/system/swoole-echo.service; enabled; vendor preset: enabled)
Active: active (running) since Tue 2018-05-07 15:08:42 CST; 1s ago
Main PID: 22385 (php)
Tasks: 8
Memory: 41.1M
CPU: 36ms
CGroup: /system.slice/swoole-echo.service
├─22385 /usr/local/php/bin/php /data/wwwroot/swoole/echo/server.php
├─22392 /usr/local/php/bin/php /data/wwwroot/swoole/echo/server.php
├─22395 swoole: worker process: 22385
├─22396 swoole: worker process: 22385
├─22397 swoole: worker process: 22385
└─22398 swoole: worker process: 22385
这时,即使使用Systemd 创建的守护进程检测到异常会自动拉起服务!
比如 kill 22385,发现守护进程会自动重新拉起,简直完美!