PHP守护进程/工作环境
问题:我想实现几个正在MQ服务器队列上侦听异步作业的php工作进程。现在的问题是,仅仅在服务器上以守护进程的形式运行这个进程并不能真正让我对实例(负载、状态、锁定)有任何级别的控制……除了转储ps-aux之外。 因此,我正在寻找某种运行时环境,它可以让我在系统(进程)级别或更高的层(某种Java风格的appserver)上监视和控制实例PHP守护进程/工作环境,php,parallel-processing,daemon,rabbitmq,process-control,Php,Parallel Processing,Daemon,Rabbitmq,Process Control,问题:我想实现几个正在MQ服务器队列上侦听异步作业的php工作进程。现在的问题是,仅仅在服务器上以守护进程的形式运行这个进程并不能真正让我对实例(负载、状态、锁定)有任何级别的控制……除了转储ps-aux之外。 因此,我正在寻找某种运行时环境,它可以让我在系统(进程)级别或更高的层(某种Java风格的appserver)上监视和控制实例 有什么提示吗?以下是一些可能有用的代码 <? define('WANT_PROCESSORS', 5); define('PROCESSOR_EXECUT
有什么提示吗?以下是一些可能有用的代码
<?
define('WANT_PROCESSORS', 5);
define('PROCESSOR_EXECUTABLE', '/path/to/your/processor');
set_time_limit(0);
$cycles = 0;
$run = true;
$reload = false;
declare(ticks = 30);
function signal_handler($signal) {
switch($signal) {
case SIGTERM :
global $run;
$run = false;
break;
case SIGHUP :
global $reload;
$reload = true;
break;
}
}
pcntl_signal(SIGTERM, 'signal_handler');
pcntl_signal(SIGHUP, 'signal_handler');
function spawn_processor() {
$pid = pcntl_fork();
if($pid) {
global $processors;
$processors[] = $pid;
} else {
if(posix_setsid() == -1)
die("Forked process could not detach from terminal\n");
fclose(stdin);
fclose(stdout);
fclose(stderr);
pcntl_exec(PROCESSOR_EXECUTABLE);
die('Failed to fork ' . PROCESSOR_EXECUTABLE . "\n");
}
}
function spawn_processors() {
global $processors;
if($processors)
kill_processors();
$processors = array();
for($ix = 0; $ix < WANT_PROCESSORS; $ix++)
spawn_processor();
}
function kill_processors() {
global $processors;
foreach($processors as $processor)
posix_kill($processor, SIGTERM);
foreach($processors as $processor)
pcntl_waitpid($processor);
unset($processors);
}
function check_processors() {
global $processors;
$valid = array();
foreach($processors as $processor) {
pcntl_waitpid($processor, $status, WNOHANG);
if(posix_getsid($processor))
$valid[] = $processor;
}
$processors = $valid;
if(count($processors) > WANT_PROCESSORS) {
for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--)
posix_kill($processors[$ix], SIGTERM);
for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--)
pcntl_waitpid($processors[$ix]);
} elseif(count($processors) < WANT_PROCESSORS) {
for($ix = count($processors); $ix < WANT_PROCESSORS; $ix++)
spawn_processor();
}
}
spawn_processors();
while($run) {
$cycles++;
if($reload) {
$reload = false;
kill_processors();
spawn_processors();
} else {
check_processors();
}
usleep(150000);
}
kill_processors();
pcntl_wait();
?>
您真的需要它持续运行吗
如果您只想根据请求生成新进程,可以在xinetd中将其注册为服务 听起来您已经在*nix系统上安装并运行了一个MQ,并且只想找到一种管理工作人员的方法 一个非常简单的方法是使用GNU屏幕。要启动10名工人,您可以使用:
#!/bin/sh
for x in `seq 1 10` ; do
screen -dmS worker_$x php /path/to/script.php worker$x
end
这将使用名为worker_1、2、3等的屏幕在后台启动10个worker
您可以通过运行screen-r worker_uu重新连接到屏幕,并使用screen-list列出正在运行的worker
有关更多信息,本指南可能有帮助:
还可以尝试:
- 屏幕-帮助
- 人幕
- 或者
对于生产服务器,我通常会建议使用正常的系统启动脚本,但多年来我一直在从启动脚本运行屏幕命令,没有出现任何问题。一个用于PHP的pcntl插件类型的服务器守护进程
下面是我们对@chaos-answer的工作实现。处理信号的代码被删除,因为此脚本通常只存在几毫秒 另外,在代码中,我们添加了两个函数来保存调用之间的PID:restore_processors_state()和save_processors_state()。我们在那里使用了
redis
,但您可以决定在文件上使用实现
我们使用cron每分钟运行一次这个脚本。Cron检查所有进程是否都处于活动状态。如果没有-它重新运行它们,然后死亡。如果我们想要终止现有进程,那么我们只需使用参数kill
:php script.php kill
运行这个脚本
运行worker的非常方便的方法,无需将脚本注入init.d
<?php
include_once dirname( __FILE__ ) . '/path/to/bootstrap.php';
define('WANT_PROCESSORS', 5);
define('PROCESSOR_EXECUTABLE', '' . dirname(__FILE__) . '/path/to/worker.php');
set_time_limit(0);
$run = true;
$reload = false;
declare(ticks = 30);
function restore_processors_state()
{
global $processors;
$redis = Zend_Registry::get('redis');
$pids = $redis->hget('worker_procs', 'pids');
if( !$pids )
{
$processors = array();
}
else
{
$processors = json_decode($pids, true);
}
}
function save_processors_state()
{
global $processors;
$redis = Zend_Registry::get('redis');
$redis->hset('worker_procs', 'pids', json_encode($processors));
}
function spawn_processor() {
$pid = pcntl_fork();
if($pid) {
global $processors;
$processors[] = $pid;
} else {
if(posix_setsid() == -1)
die("Forked process could not detach from terminal\n");
fclose(STDIN);
fclose(STDOUT);
fclose(STDERR);
pcntl_exec('/usr/bin/php', array(PROCESSOR_EXECUTABLE));
die('Failed to fork ' . PROCESSOR_EXECUTABLE . "\n");
}
}
function spawn_processors() {
restore_processors_state();
check_processors();
save_processors_state();
}
function kill_processors() {
global $processors;
foreach($processors as $processor)
posix_kill($processor, SIGTERM);
foreach($processors as $processor)
pcntl_waitpid($processor, $trash);
unset($processors);
}
function check_processors() {
global $processors;
$valid = array();
foreach($processors as $processor) {
pcntl_waitpid($processor, $status, WNOHANG);
if(posix_getsid($processor))
$valid[] = $processor;
}
$processors = $valid;
if(count($processors) > WANT_PROCESSORS) {
for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--)
posix_kill($processors[$ix], SIGTERM);
for($ix = count($processors) - 1; $ix >= WANT_PROCESSORS; $ix--)
pcntl_waitpid($processors[$ix], $trash);
}
elseif(count($processors) < WANT_PROCESSORS) {
for($ix = count($processors); $ix < WANT_PROCESSORS; $ix++)
spawn_processor();
}
}
if( isset($argv) && count($argv) > 1 ) {
if( $argv[1] == 'kill' ) {
restore_processors_state();
kill_processors();
save_processors_state();
exit(0);
}
}
spawn_processors();
生成方面在imho中不是一个大问题,因为工作人员的数量取决于系统性能,而系统性能通常是恒定的。更重要的是单个工人状态的监控方面(崩溃,不管怎样)。我刚刚发现的一个工具可能是DJBs Deamontools,这是一个选项。对于监视,您还可以使用flock()-ed PID文件。崩溃时所有锁都被释放。你从哪里得到的?开源项目还是你自己的代码?关于这里到底发生了什么,有什么文件或解释吗?@gAMBOOKa:你应该把它作为一个单独的答案,而不是一个评论。:)另见: