将 php 脚本作为守护进程运行
我需要运行一个 php 脚本作为守护进程(等待指令并执行操作)。 cron 作业不会为我做这件事,因为指令到达后需要立即采取行动。我知道由于内存管理问题,PHP 并不是守护进程的最佳选择,但由于各种原因,我在这种情况下必须使用 PHP。我遇到了 libslack 的一个名为 Daemon 的工具(http://libslack.org/daemon),它似乎对我有帮助管理守护进程,但过去 5 年没有任何更新,所以我想知道您是否知道其他适合我的情况的替代方案。任何信息将不胜感激。
I need to run a php script as daemon process (wait for instructions and do stuff). cron job will not do it for me because actions need to be taken as soon as instruction arrives. I know PHP is not really the best option for daemon processes due to memory management issues, but due to various reasons I have to use PHP in this case. I came across a tool by libslack called Daemon (http://libslack.org/daemon) it seems to help me manage daemon processes, but there hasn't been any updates in the last 5 years, so I wonder if you know some other alternatives suitable for my case. Any information will be really appreciated.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(15)
来从命令行(即 bash)启动 php 脚本,
您可以使用nohup php myscript.php &
&
将您的进程置于后台。编辑:
是的,有一些缺点,但无法控制?这是错误的。
一个简单的
kill processid
将停止它。它仍然是最好、最简单的解决方案。You could start your php script from the command line (i.e. bash) by using
nohup php myscript.php &
the
&
puts your process in the background.Edit:
Yes, there are some drawbacks, but not possible to control? That's just wrong.
A simple
kill processid
will stop it. And it's still the best and simplest solution.另一种选择是使用 Upstart。它最初是为 Ubuntu 开发的(默认情况下与它一起打包),但旨在适用于所有 Linux 发行版。
此方法类似于 Supervisord 和 daemontools,因为它会在系统启动时自动启动守护进程,并在脚本完成时重新生成。
如何设置:
在
/etc/init/myphpworker.conf
创建一个新的脚本文件。这是一个例子:启动&停止你的守护进程:
检查你的守护进程是否正在运行:
谢谢
非常感谢 Kevin van Zonneveld,我从那里学到了这项技术。
Another option is to use Upstart. It was originally developed for Ubuntu (and comes packaged with it by default), but is intended to be suitable for all Linux distros.
This approach is similar to Supervisord and daemontools, in that it automatically starts the daemon on system boot and respawns on script completion.
How to set it up:
Create a new script file at
/etc/init/myphpworker.conf
. Here is an example:Starting & stopping your daemon:
Check if your daemon is running:
Thanks
A big thanks to Kevin van Zonneveld, where I learned this technique from.
使用新的 systemd 您可以创建一个服务。
您必须在
/etc/systemd/system/
中创建一个文件或符号链接,例如: myphpdaemon.service 并放置像这样的内容,myphpdaemon 将是服务的名称:您将能够使用命令
systemctlmyphpdaemon
您可以通过
php -S 127.0.0.1:
使用 PHP 本机服务器或将其作为脚本运行。使用 PHP 脚本,您应该有一种“永远循环”来继续运行。工作示例:
如果您的 PHP 例程应在一个周期内执行一次(如摘要),您可以使用 shell 或 bash 脚本调用 systemd 服务文件,而不是直接调用 PHP,例如:
如果您选择了这些选项,则应更改将 KillMode 更改为
mixed
来处理、 bash(main) 和 PHP(child) 被杀死。如果您面临内存泄漏,此方法也很有效。
With new systemd you can create a service.
You must create a file or a symlink in
/etc/systemd/system/
, eg. myphpdaemon.service and place content like this one, myphpdaemon will be the name of the service:You will be able to start, get status, restart and stop the services using the command
systemctl <start|status|restart|stop|enable> myphpdaemon
You can use the PHP native server using
php -S 127.0.0.1:<port>
or run it as a script. Using a PHP script you should have a kind of "forever loop" to continue running.Working example:
If your PHP routine should be executed once in a cycle (like a diggest) you may use a shell or bash script to be invoked into systemd service file instead of PHP directly, for example:
If you chose these option you should change the KillMode to
mixed
to processes, bash(main) and PHP(child) be killed.This method also is effective if you're facing a memory leak.
如果可以的话 - 获取UNIX 环境中的高级编程的副本。整个第 13 章都致力于守护进程编程。示例是用 C 编写的,但是您需要的所有函数都有 PHP 中的包装器(基本上是 pcntl 和 posix 扩展)。
简而言之 - 编写一个守护进程(这仅在基于 *nix 的 OS-es 上可行 - Windows 使用服务)如下所示:
umask(0)
以防止权限问题。fork()
并拥有父出口。setsid()
。SIGHUP
的信号处理(通常会被忽略或用于向守护进程发出信号以重新加载其配置)和SIGTERM
(告诉进程正常退出)。fork()
并让父进程退出。chdir()
更改当前工作目录。fclose()
stdin
,stdout 和
stderr
并且不要写入它们。正确的方法是将它们重定向到/dev/null
或文件,但我找不到在 PHP 中执行此操作的方法。当您启动守护进程时,可以使用 shell 重定向它们(您必须自己找出如何做到这一点,我不知道:)。另外,由于您使用的是 PHP,所以要小心循环引用,因为 PHP 5.3 之前的 PHP 垃圾收集器无法收集这些引用,并且该进程将发生内存泄漏,直到最终崩溃。
If you can - grab a copy of Advanced Programming in the UNIX Environment. The entire chapter 13 is devoted to daemon programming. Examples are in C, but all the function you need have wrappers in PHP (basically the pcntl and posix extensions).
In a few words - writing a daemon (this is posible only on *nix based OS-es - Windows uses services) is like this:
umask(0)
to prevent permission issues.fork()
and have the parent exit.setsid()
.SIGHUP
(usually this is ignored or used to signal the daemon to reload its configuration) andSIGTERM
(to tell the process to exit gracefully).fork()
again and have the parent exit.chdir()
.fclose()
stdin
,stdout
andstderr
and don't write to them. The corrrect way is to redirect those to either/dev/null
or a file, but I couldn't find a way to do it in PHP. It is possible when you launch the daemon to redirect them using the shell (you'll have to find out yourself how to do that, I don't know :).Also, since you are using PHP, be careful for cyclic references, since the PHP garbage collector, prior to PHP 5.3, has no way of collecting those references and the process will memory leak, until it eventually crashes.
我运行大量 PHP 守护进程。
我同意您的观点,即 PHP 不是执行此操作的最佳(甚至是良好)语言,但守护进程与面向 Web 的组件共享代码,因此总的来说,它对我们来说是一个很好的解决方案。
我们为此使用 daemontools。它智能、清洁且可靠。事实上,我们用它来运行所有的守护进程。
您可以在 http://cr.yp.to/daemontools.html 上查看。
编辑:功能的快速列表。
I run a large number of PHP daemons.
I agree with you that PHP is not the best (or even a good) language for doing this, but the daemons share code with the web-facing components so overall it is a good solution for us.
We use daemontools for this. It is smart, clean and reliable. In fact we use it for running all of our daemons.
You can check this out at http://cr.yp.to/daemontools.html.
EDIT: A quick list of features.
您可以
nohup
。screen
并将 PHP 程序作为其中的常规进程运行。与使用nohup
相比,这为您提供了更多的控制权。我建议使用最简单的方法(我认为是屏幕),然后如果您想要更多特性或功能,请转向更复杂的方法。
You can
nohup
as Henrik suggested.screen
and run your PHP program as a regular process inside that. This gives you more control than usingnohup
.I'd recommend the simplest method (screen in my opinion) and then if you want more features or functionality, move to more complex methods.
解决这个问题的方法不止一种。
我不知道具体细节,但也许还有另一种方法来触发 PHP 进程。例如,如果您需要基于 SQL 数据库中的事件运行代码,您可以设置一个触发器来执行脚本。这在 PostgreSQL 下非常容易做到:http://www.postgresql。 org/docs/current/static/external-pl.html 。
老实说,我认为最好的选择是使用 nohup 创建一个 Damon 进程。 nohup 允许命令在用户注销后继续执行:
然而,存在一个非常严重的问题。正如您所说,PHP 的内存管理器完全是垃圾,它是在脚本仅执行几秒钟然后存在的假设下构建的。几天后,您的 PHP 脚本将开始使用 GIGABYTES 的内存。您还必须创建一个每 12 或 24 小时运行一次的 cron 脚本,它会杀死并重新生成您的 php 脚本,如下所示:
但是,如果该脚本正在执行作业怎么办?那么kill -3 是一个中断,它与在CLI 上执行ctrl+c 相同。您的 php 脚本可以使用 PHP pcntl 库捕获此中断并正常退出: http ://php.oregonstate.edu/manual/en/function.pcntl-signal.php
这是一个示例:
$lock 背后的想法是 PHP 脚本可以使用 fopen("file ”,“w”);。只有一个进程可以对文件进行写锁定,因此使用此功能可以确保只有一份 PHP 脚本正在运行。
祝你好运!
There is more than one way to solve this problem.
I do not know the specifics but perhaps there is another way to trigger the PHP process. For instance if you need the code to run based on events in a SQL database you could setup a trigger to execute your script. This is really easy to do under PostgreSQL: http://www.postgresql.org/docs/current/static/external-pl.html .
Honestly I think your best bet is to create a Damon process using nohup. nohup allows the command to continue to execute even after the user has logged out:
There is however a very serious problem. As you said PHP's memory manager is complete garbage, it was built with the assumption that a script is only executing for a few seconds and then exists. Your PHP script will start to use GIGABYTES of memory after only a few days. You MUST ALSO create a cron script that runs every 12 or maybe 24 hours that kills and re-spawns your php script like this:
But what if the script was in the middle of a job? Well kill -3 is an interrupt, its the same as doing a ctrl+c on the CLI. Your php script can catch this interrupt and exit gracefully using the PHP pcntl library: http://php.oregonstate.edu/manual/en/function.pcntl-signal.php
Here is an example:
The idea behind the $lock is that the PHP script can open a file with a fopen("file","w");. Only one process can have a write lock on a file, so using this you can make sure that only one copy of your PHP script is running.
Good Luck!
Kevin van Zonneveld 就此写了一篇非常详细的文章,在他的示例中,他使用了
System_Daemon
PEAR 包(最后发布日期为 2009 年 9 月 - 02)。Kevin van Zonneveld wrote a very nice detailed article on this, in his example he makes use of the
System_Daemon
PEAR package (last release date on 2009-09-02).查看 https://github.com/shaneharter/PHP-Daemon
这是一个面向对象的守护进程库。它内置了对日志记录和错误恢复等功能的支持,并且支持创建后台工作人员。
Check out https://github.com/shaneharter/PHP-Daemon
This is an object-oriented daemon library. It has built-in support for things like logging and error recovery, and it has support for creating background workers.
我最近需要一个跨平台解决方案(Windows、Mac 和 Linux)来解决将 PHP 脚本作为守护进程运行的问题。我通过编写自己的基于 C++ 的解决方案并制作二进制文件解决了这个问题:
https://github.com/cubiclesoft /service-manager/
完全支持 Linux(通过 sysvinit),还支持 Windows NT 服务和 Mac OSX 启动。
如果您只需要 Linux,那么这里介绍的其他几个解决方案就足够好了,具体取决于风格。现在还有 Upstart 和 systemd,它们可以回退到 sysvinit 脚本。但使用 PHP 的一半原因是它本质上是跨平台的,因此用该语言编写的代码很有可能在任何地方按原样工作。当某些外部本机操作系统级别方面(例如系统服务)出现时,缺陷就会开始显现出来,但大多数脚本语言都会遇到这个问题。
尝试捕获信号,正如有人在 PHP 用户区中建议的那样,这不是一个好主意。仔细阅读有关
pcntl_signal()
的文档,您很快就会了解到 PHP 使用一些相当令人不快的方法(特别是“ticks”)来处理信号,这些方法会消耗掉一堆进程很少看到的循环(即信号)。 PHP 中的信号处理也仅在 POSIX 平台上几乎可用,并且支持因 PHP 版本而异。它最初听起来像是一个不错的解决方案,但它距离真正有用还差得很远。随着时间的推移,PHP 在内存泄漏问题上也得到了更好的解决。您仍然必须小心(DOM XML 解析器仍然会泄漏),但现在我很少看到失控的进程,而且与以前相比,PHP 错误跟踪器非常安静。
I recently had a need for a cross-platform solution (Windows, Mac, and Linux) to the problem of running PHP scripts as daemons. I solved the problem by writing my own C++ based solution and making binaries:
https://github.com/cubiclesoft/service-manager/
Full support for Linux (via sysvinit), but also Windows NT services and Mac OSX launchd.
If you just need Linux, then a couple of the other solutions presented here work well enough and, depending on the flavor. There is also Upstart and systemd these days, which have fallbacks to sysvinit scripts. But half of the point of using PHP is that it is cross-platform in nature, so code written in the language has a pretty good chance of working everywhere as-is. Deficiencies start showing up when certain external native OS-level aspects enter the picture such as system services, but you'll get that problem with most scripting languages.
Attempting to catch signals as someone here suggested in PHP userland is not a good idea. Read the documentation on
pcntl_signal()
carefully and you will quickly learn that PHP handles signals using some rather unpleasant methods (specifically, 'ticks') that chew up a bunch of cycles for something rarely seen by processes (i.e. signals). Signal handling in PHP is also only barely available on POSIX platforms and support differs based on the version of PHP. It initially sounds like a decent solution but it falls pretty short of being truly useful.PHP has also been getting better about memory leak issues as time progresses. You still have to be careful (the DOM XML parser tends to leak still) but I rarely see runaway processes these days and the PHP bug tracker is pretty quiet by comparison to the days of yore.
你可以在这里检查pm2,http://pm2.keymetrics.io/
创建一个ssh文件,比如将worker.sh放入您将要处理的php脚本中。
worker.sh
守护进程启动
干杯,就是这样。
you can check pm2 here is, http://pm2.keymetrics.io/
create a ssh file, such as worker.sh put into your php script that you will deal with.
worker.sh
daemon start
Cheers, that is it.
正如其他人已经提到的,将 PHP 作为守护进程运行非常容易,并且可以使用单行命令来完成。但实际的问题是保持它的运行和管理。我很久以前就遇到过同样的问题,尽管已经有很多可用的解决方案,但其中大多数都有很多依赖项,或者难以使用且不适合基本用法。我编写了一个 shell 脚本,可以管理任何进程/应用程序,包括 PHP cli 脚本。它可以设置为 cronjob 来启动应用程序,并将包含应用程序并对其进行管理。如果再次执行,例如通过相同的 cronjob,它会检查应用程序是否正在运行,如果运行,则简单地退出并让其先前的实例继续管理应用程序。
我已将其上传到github,请随意使用它: https://github.com/sinasalek/EasyDeamonizer
EasyDeamonizer
只需监视您的应用程序(启动、重新启动、记录、监控等)。确保您的应用程序保持正常运行的通用脚本。它有意使用进程名称代替 pid/lock 文件来防止其所有副作用,并使脚本尽可能简单和简单,因此即使 EasyDaemonizer 本身重新启动,它也始终可以工作。
功能
As others have already mentioned, running PHP as a daemon is quite easy, and can be done using a single line of command. But the actual problem is keeping it running and managing it. I've had the same problem quite some time ago and although there are plenty of solutions already available, most of them have lots of dependencies or are difficult to use and not suitable for basic usages. I wrote a shell script that can manage a any process/application including PHP cli scripts. It can be set as a cronjob to start the application and will contain the application and manage it. If it's executed again, for example via the same cronjob, it check if the app is running or not, if it does then simply exits and let its previous instance continue managing the application.
I uploaded it to github, feel free to use it : https://github.com/sinasalek/EasyDeamonizer
EasyDeamonizer
Simply watches over your application (start, restart, log, monitor, etc). a generic script to make sure that your appliation remains running properly. Intentionally it uses process name instread of pid/lock file to prevent all its side effects and keep the script as simple and as stirghforward as possible, so it always works even when EasyDaemonizer itself is restarted.
Features
我一直在寻找一个简单的解决方案,无需安装额外的东西,并且与允许 SSH 访问的常见主机兼容。
我最终为我的聊天服务器设置了这样的设置:
脚本:
startChatServer.sh
stopChatServer.sh
restartChatServer.sh
最后但并非最不重要的一点是,我已将最后一个脚本放在 cron 作业上,以检查“聊天服务器”是否已启动正在运行”,如果没有,则启动它:
Cron job 每分钟
checkChatServerRunning.sh
因此,通过此设置:
I was looking for a simple solution without having to install additional stuff and compatible with common hostings that allow SSH access.
I've ended up with this setup for my chat server:
And the scripts:
startChatServer.sh
stopChatServer.sh
restartChatServer.sh
And last but not least, I have put this last script on a cron job, to check if the "chat server is running", and if not, to start it:
Cron job every minute
checkChatServerRunning.sh
So with this setup:
我编写并部署了一个简单的 php-daemon,代码在线
https://github.com/jmullee/PhpUnixDaemon< /a>
功能:权限删除、信号处理、日志记录
我在队列处理程序中使用了它(用例:从网页触发冗长的操作,而不使页面生成的 php 等待,即启动异步操作)
https://github.com/jmullee/PhpIPCMessageQueue
I wrote and deployed a simple php-daemon, code is online here
https://github.com/jmullee/PhpUnixDaemon
Features: privilege dropping, signal handling, logging
I used it in a queue-handler (use case: trigger a lengthy operation from a web page, without making the page-generating php wait, i.e. launch an asynchronous operation)
https://github.com/jmullee/PhpIPCMessageQueue
扩展 Emil Ivaov 答案,您可以执行以下操作来关闭 php 中的 STDIN、STDOUT 和 STDERROR
基本上您关闭了标准流,以便 PHP 没有地方可写。以下
fopen
调用会将标准 IO 设置为/dev/null
。我从Rob Aley - PHP Beyond the web一书中读到了这篇文章
Extending Emil Ivaov answer, You can do the following to close STDIN, STDOUT AND STDERROR in php
Basically you close the standard streams so that PHP has no place to write. The following
fopen
calls will set the standard IO to/dev/null
.I have read this from book of Rob Aley - PHP beyond the web