2009-04-15 5 views
14

문제점 : 비동기 작업을 위해 MQ 서버 대기열에서 수신 대기하는 여러 php-worker 프로세스를 구현하고자합니다. 문제는 이제이 프로세스를 서버의 데몬으로 실행하는 것만으로도 ps -aux를 덤프하는 경우를 제외하고 인스턴스 (로드, 상태, 잠김)를 제어 할 수있는 수준을 부여하지 못한다는 것입니다. 그 이유는 시스템 (프로세스) 레벨이나 상위 레이어 (Java 스타일 앱 서버의 일종)에서 인스턴스를 모니터링하고 제어 할 수있는 일종의 런타임 환경을 찾고 있기 때문입니다.PHP 데몬/작업자 환경

Any 포인터?

+0

참조 :이셨어요 경우 http://symfony.com/doc/master/components/process.html –

답변

12

다음은 유용한 코드입니다.

<? 
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(); 
?> 
+0

를? 오픈 소스 프로젝트 또는 자신의 코드? 여기에 정확히 무슨 일이 일어나고 있는지에 대한 문서 나 설명이 있습니까? – leek

+0

내 코드. 나는 그것을 설명하지 않을거야. 아니. – chaos

+0

또한 https://github.com/kvz/system_daemon. – HyderA

1

계속 실행하려면 실제로 필요합니까?

요청에 따라 새 프로세스를 생성하려는 경우 xinetd에서 서비스로 등록 할 수 있습니다.

+0

산란 양상은 노동자의 수가 보통 일정한 시스템 성능에 의존하기 때문에 큰 문제는 아닙니다. 더 중요한 것은 개별 근로자 상태 (추락, 기타)의 모니터링 측면입니다. 방금 발견 한 도구는 DJBs deamontools – Sebastian

+0

일 수 있습니다. 모니터링을 위해 flock() - ed PID 파일을 사용할 수도 있습니다. 충돌시 모든 잠금이 해제됩니다. – vartec

4

MQ가 이미 * nix 시스템에서 실행 중이며 작업자를 관리하기를 원하는 것처럼 들립니다.

매우 간단한 방법은 GNU 화면을 사용하는 것입니다. (10 명) 근로자를 시작하려면 다음을 사용할 수 있습니다이 등등 worker_1,2,3라는 이름의 화면을 사용하여 백그라운드에서 근로자 10 명을 시작합니다

#!/bin/sh 
for x in `seq 1 10` ; do 
screen -dmS worker_$x php /path/to/script.php worker$x 
end 

.

-r worker_ 화면을 실행하여 화면에 다시 첨부하고 screen-list를 사용하여 실행중인 작업자를 나열 할 수 있습니다. http://www.kuro5hin.org/story/2004/3/9/16838/14935

는 또한 시도 :

  • 화면 --help
  • 사람 화면
  • 또는 google이 가이드가 도움이 될 수 있습니다 더 많은 정보를 들어

    .

정상적인 시스템 시작 스크립트를 사용하는 것이 좋습니다. 그러나 몇 년 동안 시작 스크립트에서 화면 명령을 문제없이 실행했습니다.

0

우는 소리가 @chaos 대답 우리의 작업 구현을위한 pcntl 플러그인 타입 서버 데몬. 이 스크립트는 대개 몇 밀리 초 밖에 걸리지 않으므로 신호 처리 코드가 제거되었습니다.

또한 코드에서 restore_processors_state() 및 save_processors_state() 호출간에 pid를 저장하는 두 가지 기능을 추가했습니다. 여기에 redis을 사용했지만 파일에 구현을 사용하도록 결정할 수 있습니다.

우리는 cron을 사용하여 매분이 스크립트를 실행합니다. Cron은 모든 프로세스가 살아 있는지 확인합니다. 그렇지 않으면 다시 실행하여 죽게됩니다. 기존 프로세스를 종료하려면이 스크립트를 인수 kill : php script.php kill으로 실행하면됩니다.

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();