如何将PHP内置服务器用作守护进程。
如何将PHP内置服务器用作守护进程。
我需要将一个php脚本作为守护进程运行(等待指令并执行任务)。cron任务无法满足我的需求,因为指令到达时需要立即采取行动。我知道由于内存管理问题,PHP并不是守护进程的最佳选择,但由于各种原因,我必须在这种情况下使用PHP。我发现了一个名为Daemon的libslack工具(http://libslack.org/daemon),它似乎可以帮助我管理守护进程,但在过去的5年里没有任何更新,所以我想知道您是否了解适合我情况的其他替代方案。非常感谢您提供的任何信息。
如何将PHP内置服务器用作守护进程
使用新的systemd,您可以创建一个服务。
必须在/etc/systemd/system/中创建一个文件或符号链接,例如myphpdaemon.service,并放置以下内容,myphpdaemon将是服务的名称:
[Unit] Description=My PHP Daemon Service #May your script needs MySQL or other services to run, eg. MySQL Memcached Requires=mysqld.service memcached.service After=mysqld.service memcached.service [Service] User=root Type=simple TimeoutSec=0 PIDFile=/var/run/myphpdaemon.pid ExecStart=/usr/bin/php -f /srv/www/myphpdaemon.php arg1 arg2> /dev/null 2>/dev/null #ExecStop=/bin/kill -HUP $MAINPID #It's the default you can change whats happens on stop command #ExecReload=/bin/kill -HUP $MAINPID KillMode=process Restart=on-failure RestartSec=42s StandardOutput=null #If you don't want to make toms of logs you can set it null if you sent a file or some other options it will send all PHP output to this one. StandardError=/var/log/myphpdaemon.log [Install] WantedBy=default.target
您可以使用以下命令启动、获取状态、重新启动和停止服务:
systemctlmyphpdaemon
您可以使用PHP原生服务器使用`php -S 127.0.0.1:
工作示例:
[Unit] Description=PHP APP Sync Service Requires=mysqld.service memcached.service After=mysqld.service memcached.service [Service] User=root Type=simple TimeoutSec=0 PIDFile=/var/run/php_app_sync.pid ExecStart=/bin/sh -c '/usr/bin/php -f /var/www/app/private/server/cron/app_sync.php 2>&1 > /var/log/app_sync.log' KillMode=mixed Restart=on-failure RestartSec=42s [Install] WantedBy=default.target
如果您的PHP例程应该在一个周期内执行一次(例如摘要),则可以使用shell或bash脚本来调用systemd服务文件,而不是直接使用PHP,例如:
#!/usr/bin/env bash script_path="/app/services/" while [ : ] do # clear php -f "$script_path${1}".php fixedparameter ${2} > /dev/null 2>/dev/null sleep 1 done
如果您选择这些选项,则应将KillMode更改为混合模式以便杀死进程,bash(主进程)和PHP(子进程)。
ExecStart=/app/phpservice/runner.sh phpfile parameter > /dev/null 2>/dev/null KillMode=process
此方法也适用于解决内存泄漏问题。
注意:每次更改"myphpdaemon.service"时,必须运行`systemctl daemon-reload`,但如果您没有运行,系统将在需要时提醒您。
被低估的答案。我点赞。
太棒了。希望我们也可以为答案点赞,因为它不应该埋没在这个页面上。
嘿,我试图执行systemctl stop servicename,但php文件仍然输出到文件..我正在使用"working example"文件。
也许您启用了PHP中的忽略用户中止。
嗨,谢谢您的提示,但是服务仍然无法停止。我完全复制了php代码,并且当我运行ps -ef | grep php时,得到的结果是:user 14020 1 0 13:03 ? 00:00:00 /bin/sh -c /usr/bin/php -f /app/folder/test.php 2>&1 > /app/folder/log.out user 14021 14020 0 13:03 ? 00:00:00 /usr/bin/php -f /app/folder/test.php 我对pid控制器做的唯一更改是将用户和组设置为某个值。当然,我首先尝试了root,没有任何区别。
您应该检查`systemctl status
-l`输出,它会给您提示发生了什么。 将此答案用于Ubuntu/Debian和/或2018+。
对于Ubuntu,mysqld是mysql,而且必须在安装memcache之前安装。此外,更实用的是使用符号链接到类似/var/www/daemons/myservice.service的东西。
MySQL和Memcached只是演示了如何使用服务依赖项,这是不必要的。
我在PHP中使用mysqli,不需要mysql服务引用吗?
您应该引用PHP服务器依赖的任何服务,以防止失败,但这并非必需。
感谢您的帮助。如何将其设置为自动启动?
`systemctl enable phpdaemon.service`
我有一些问题无法停止守护进程,即使使用了execStop,php也会无限运行,无法停止,多个脚本将同时运行,出现并发问题。
如果您的服务启动子脚本,应尝试其他配置的KillMode和ExecStop freedesktop.org/software/systemd/man/systemd.kill.html
鉴于现在是2019年,这应该真正替代被接受的答案。
我很惊讶为什么这不是被接受的答案...截至2020年最佳解决方案
sudo yum install -y supervisor
使用`systemd`如果使用`Type=simple`,则不需要`PIDFile=`。 freedesktop.org/software/systemd/man/…
是否可以将此解决方案用于多线程作业?
当然可以,使用`pcntl_fork`
对于运行systemd的Linux系统,我认为这是最佳答案。我为此点赞。
一个问题,为什么选择一个随机数来调用gc?假设rand是以大约20次迭代为种子,将调用gc_collect_cycles()。是一些明显的波动,但接近。我会建议使用计数器来监视脚本,并根据您的需求使用gc来调用,例如`if(($counter++ % 20) == 0)`,然后进行调整。
如何使用PHP内置服务器作为守护进程
在命令行(如bash)中,可以通过以下方式启动PHP脚本:
nohup php myscript.php &
&
将进程放在后台运行。
是的,这种方法存在一些缺点,但无法控制是错误的。
一个简单的kill processid
命令将停止它。这仍然是最好和最简单的解决方法。
如果终端退出,进程不会结束。这就是为什么要使用"nohup"命令的原因。多年来,我一直在所有服务器上使用这种方式将PHP脚本作为守护进程运行。可能有更好的解决方法,但这是最快捷的方法。
这种方法不会在守护进程失败时重新启动它,也没有简单的方法来管理守护进程。
我同意这里说的话-这是一个糟糕的解决方法。你应该创建一个初始化脚本,原因有几个:1)初始化脚本在启动时自动启动2)你可以使用启动/停止/重启命令来管理守护进程。以下是来自servefault的一个例子:serverfault.com/questions/229759/…
嘿伙计们...在我看来,nohup
和&
做的事情是一样的:将启动的进程与当前shell实例分离。为什么我需要同时使用它们?我不能只做php myscript.php &
或nohup myscript.php
吗?谢谢
为了更清晰地解释这个问题。nohup
会让脚本忽略SIGTERM
信号,但显然仍会在收到KILL
信号时终止。你需要同时使用nohup
和&
,nohup
会确保如果父进程死亡,脚本不会随之死亡,&
会确保脚本被立即推到后台运行。简而言之,这是一种不错但有点hacky的守护进程方法,在PHP中,对于这种用例,你几乎完全依赖于hacky的方法。
如果脚本通过echo或var_dump写入stdout,则可以使用以下命令将这些信息捕获到日志文件中:nohup php myscript.php > myscript.log &
-1:这里的建议很糟糕,会导致进程没有正确与控制终端隔离,并产生僵尸进程。
如何将PHP内置服务器用作守护进程
在使用PHP内置服务器作为守护进程时,有时会遇到问题。下面是问题出现的原因和解决方法:
问题原因:
- 使用/etc/init/myphpworker.conf
脚本文件时,如果PHP脚本返回字符串"ERROR",守护进程会停止运行。
- 使用sudo service myphpworker start
命令启动守护进程时,可能会出现myphpworker: unrecognized service
错误,因为这个命令只适用于在/etc/init.d
目录下的服务,而不是upstart服务。
- 在脚本中如何传递参数?
解决方法:
- 创建一个新的脚本文件,在/etc/init/myphpworker.conf
路径下,用于启动和管理守护进程。
- 在脚本文件中设置启动和停止事件,以及自动重启守护进程的配置。
- 使用sudo service myphpworker start/stop/status
命令来启动、停止和检查守护进程的状态。
下面是一个使用Upstart作为守护进程的例子:
# Info description "My PHP Worker" author "Jonathan" # Events start on startup stop on shutdown # Automatically respawn respawn respawn limit 20 5 # Run the script! # Note, in this example, if your PHP script returns # the string "ERROR", the daemon will stop itself. script [ $(exec /usr/bin/php -f /path/to/your/script.php) = 'ERROR' ] && ( stop; exit 1; ) end script
启动和停止守护进程的命令:
sudo service myphpworker start sudo service myphpworker stop
检查守护进程是否正在运行:
sudo service myphpworker status
需要注意的是,Ubuntu正在逐渐转向使用systemd而不是Upstart作为守护进程管理器。
感谢Kevin van Zonneveld的博客文章,我从中学到了这个技巧。
如果需要在启动时传递参数给脚本,可以使用以下方式:
exec /usr/bin/php -f /path/to/your/script.php SOME_PARAM1 SOME_PARAM2
这样,在守护进程自动重启时,会使用相同的参数。
通过使用Upstart作为守护进程管理器,我们可以轻松地将PHP内置服务器作为守护进程运行,并在系统启动时自动启动它。同时,我们还可以通过设置脚本文件来控制守护进程的行为,例如自动重启和停止条件。如果需要传递参数给脚本,可以在启动命令中指定参数。