데몬 프로세스로 PHP 스크립트를 실행


154

데몬 프로세스로 PHP 스크립트를 실행해야합니다 (지시를 기다리고 작업을 수행하십시오). cron job은 지시가 도착하자마자 조치를 취해야하기 때문에 나를 위해 그것을하지 않을 것입니다. 메모리 관리 문제로 인해 PHP가 데몬 프로세스에 가장 적합한 옵션은 아니지만 여러 가지 이유로 인해이 경우 PHP를 사용해야한다는 것을 알고 있습니다. 데몬 프로세스를 관리하는 데 도움이되는 데몬 ( http://libslack.org/daemon ) 이라는 libslack 도구를 발견 했지만 지난 5 년 동안 업데이트가 없었으므로 일부를 알고 있는지 궁금합니다. 내 경우에 적합한 다른 대안. 모든 정보는 정말 감사하겠습니다.


2
내 대답을 확인하십시오. 감사합니다
Henrik P. Hessel


1
나는이 게시물 gonzalo123.com/2010/05/23/ 을 발견했다 ... 내가 믿는 것은 편안하고 안정적입니다.
Teson

답변:


167

커맨드 라인 (예 : bash)에서 PHP 스크립트를 사용하여 시작할 수 있습니다

nohup php myscript.php &

&백그라운드에서 프로세스를 둔다.

편집 :
예, 몇 가지 단점이 있지만 제어 할 수 없습니까? 그건 잘못이야
간단 kill processid하게 막을 수 있습니다. 그리고 여전히 가장 우수하고 간단한 솔루션입니다.


터미널이 존재하면 프로세스가 종료되지 않습니다. 이것이 "nohup"명령이있는 이유입니다. 나는 몇 년 동안 이와 같은 모든 서버에서 PHP 스크립트를 데몬으로 사용 해왔다. 더 나은 해결책이있을 수 있지만 이것이 가장 빠릅니다.
CDR

27
데몬이 실패하면 데몬을 다시 시작하지 않으며 데몬을 전혀 쉽게 관리 할 수있는 방법이 없습니다.
Phil Wallach

6
나는 여기에서 말한 것에 동의합니다. 이것은 나쁜 해결책입니다. 몇 가지 이유로 초기화 스크립트를 작성해야합니다. 1) 초기화 스크립트가 시작시 자동으로 시작됩니다. 2) start / stop / restart 명령으로 데몬을 관리 할 수 ​​있습니다. servefault의 예제는 다음과 같습니다. serverfault.com/questions/229759/…
Simian

1
얘들 아 ... 그것은 나에게 보인다 nohup&같은 매우 일을 : 쉘의 현재 intance에서 실행 된 프로세스를 분리. 왜 둘 다 필요합니까? 난 그냥 할 수 없습니다 php myscript.php &또는 nohup myscript.php?? 감사합니다
nourdine

1
스크립트가 echo 또는 var_dump를 통해 stdout에 쓰는 경우 다음과 같은 로그 파일로이 정보를 포착 할 수 있습니다.nohup php myscript.php > myscript.log &
Mischa

167

또 다른 옵션은 Upstart 를 사용하는 것 입니다. 원래 Ubuntu 용으로 개발되었으며 기본적으로 패키지로 제공되지만 모든 Linux 배포판에 적합합니다.

이 방법은 시스템 부팅시 데몬을 자동으로 시작하고 스크립트 완료시 다시 생성한다는 점에서 Supervisorddaemontools 와 유사합니다 .

설정 방법 :

에 새 스크립트 파일을 작성하십시오 /etc/init/myphpworker.conf. 예를 들면 다음과 같습니다.

# 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

감사

Kevin van Zonneveld 에게 감사의 말을 전합니다 .


2
이것을 사랑합니다. 단지 여러 명의 동시 작업자를 보유 할 수 있습니까? 한 근로자로는 더 이상 충분하지 않다는 문제가 있습니다.
Manuel

1
시스템 시작시 자동으로 실행됩니까?
slier

2
Sudo "service myphpworker start"가 작동하지 않았습니다. "sudo start myphpworker"를 사용했는데 완벽하게 작동합니다.
Matt Sich

3
@Pradeepta 게시물에 오류가 있기 때문입니다. 정확히 무엇을 테스트하지 않았으며 아직 테스트하지 않은 sudo service myphpworker start/stop/status서비스 만 작동 한다고 생각 /etc/init.d합니다. @ matt-sich가 올바른 구문을 발견 한 것 같습니다. 또 다른 옵션은 Gearman 또는 Resque를 사용하여 백그라운드 처리 및 디몬 제거를 허용하는 것입니다.
ckm

3
우분투 자체는 시작 대신에 systemd를 사용하도록 이동하고 있습니다 : zdnet.com/article/after-linux-civil-war-ubuntu-to-adopt-systemd
Kzqai

72

새로 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

명령을 사용하여 서비스를 시작, 상태 확인, 다시 시작 및 중지 할 수 있습니다.

systemctl <start|status|restart|stop|enable> myphpdaemon

PHP 스크립트는 계속 실행하려면 일종의 "루프"가 있어야합니다.

<?php
gc_enable();//
while (!connection_aborted() || PHP_SAPI == "cli") {

  //Code Logic

  //sleep and usleep could be useful
    if (PHP_SAPI == "cli") {
        if (rand(5, 100) % 5 == 0) {
            gc_collect_cycles(); //Forces collection of any existing garbage cycles
        }
    }
}

작업 예 :

[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 루틴을 한 번에 한 번 실행해야하는 경우 (예 : 파기) 쉘 또는 bash 스크립트를 사용하여 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을mixed프로세스를 bash는 (주)와 PHP (아이가) 죽을.

ExecStart=/app/phpservice/runner.sh phpfile parameter  > /dev/null 2>/dev/null
KillMode=process

This method also is effective if you're facing a memory leak.

참고 : "myphpdaemon.service"를 변경할 때마다`systemctl daemon-reload '를 실행해야하지만, 그렇지 않으면 걱정할 필요가있을 때 경고가 표시됩니다.


7
과소 평가. 내 +1이 있습니다.
Gergely Lukacsy

2
대박. 이것이이 페이지에 묻혀서는 안되기 때문에 우리도 마음의 답을 얻을 수 있기를 바랍니다.
저스틴

1
systemctl status <your_service_name> -l출력 을 확인해야합니다 . 무슨 일이 일어나고 있는지 알 수 있습니다.
LeonanCarvalho

1
@LeandroTupone MySQL과 Memcached는 필요하지 않은 서비스 종속성을 사용하는 방법을 보여주었습니다.
LeonanCarvalho

3
이것은 현재 2019
spice

47

UNIX 환경에서 고급 프로그래밍 의 사본을 얻을 수있는 경우 . 13 장 전체는 데몬 프로그래밍에 관한 것입니다. 예제는 C에 있지만 필요한 모든 함수는 PHP에 래퍼 (기본적으로 pcntlposix 확장자)가 있습니다.

한 마디로-데몬 작성 (이는 * nix 기반 OS-es에서만 가능-Windows는 서비스 사용)은 다음과 같습니다.

  1. umask(0)권한 문제를 방지하기 위해 전화하십시오 .
  2. fork() 그리고 부모님 출구가 있습니다.
  3. 전화하십시오 setsid().
  4. 설정 신호 처리 SIGHUP(일반적으로 무시되거나 데몬이 구성을 다시로드하도록 신호를 보내는 데 사용됨) 및 SIGTERM프로세스가 정상적으로 종료되도록 지시합니다.
  5. fork() 다시 부모를 종료하십시오.
  6. 로 현재 작업 디렉토리를 변경하십시오 chdir().
  7. fclose() stdin, stdout그리고 stderr그들에게 쓰지 않는다. 올바른 방법은 /dev/null파일 을 하나 또는 파일 로 리디렉션하는 것이지만 PHP에서이를 수행하는 방법을 찾을 수 없습니다. 쉘을 사용하여 데몬을 리디렉션하기 위해 데몬을 시작할 때 가능합니다 (그 방법을 스스로 알아야합니다.)
  8. 일하세요!

또한 PHP를 사용하고 있으므로 순환 참조에주의하십시오. PHP 5.3 이전의 PHP 가비지 콜렉터는 이러한 참조를 수집 할 방법이없고 프로세스가 결국 충돌 할 때까지 메모리 누수가 발생합니다.


1
정보 주셔서 감사합니다. libslack의 데몬 프로그램은 언급 한 것처럼 모든 준비가 작동하는 것처럼 보입니다. 나는 다른 좋은 대안을 찾을 때까지 지금까지 고수 할 것이라고 생각합니다.
Beier

1
이 게시물을 발견하면 stdin 등을 닫지 않는 낡은 오래된 응용 프로그램에 복사하여 붙여 넣을 것으로 예상되는 코드가 실망했습니다. : p
ThiefMaster

1
왜 (5) fork ()를 다시합니까?
TheFox

나를 위해 일했습니다-훌륭합니다!
Gautam Sharma

미래 독자들에게 두 번 분기해야하는 이유 : stackoverflow.com/questions/881388/…-TL ; DR : 좀비 방지.
Ghedipunk

24

많은 수의 PHP 데몬을 실행합니다.

PHP는이 작업을 수행하는 데 가장 적합한 (또는 좋은 언어) 언어는 아니지만 데몬은 웹 연결 구성 요소와 코드를 공유하므로 전반적으로 우리에게 좋은 솔루션입니다.

이를 위해 daemontools를 사용합니다. 똑똑하고 깨끗하며 신뢰할 수 있습니다. 실제로 모든 데몬을 실행하는 데 사용합니다.

http://cr.yp.to/daemontools.html 에서 확인할 수 있습니다 .

편집 : 기능의 빠른 목록.

  • 재부팅시 데몬을 자동으로 시작합니다
  • 장애 발생시 자동으로 다시 시작
  • 롤오버 및 정리를 포함하여 로깅이 처리됩니다.
  • 관리 인터페이스 : 'svc'및 'svstat'
  • 유닉스 친화적 (아마도 모두에게 플러스가 아님)

예를 들어 apt!
Kzqai

14

당신은 할 수 있습니다

  1. nohupHenrik가 제안한대로 사용하십시오 .
  2. screenPHP 프로그램을 정기적으로 사용 하고 실행하십시오. 이렇게하면을 사용하는 것보다 더 많은 제어가 가능 nohup합니다.
  3. http://supervisord.org/ 와 같은 데몬을 사용 하십시오 (Python으로 작성되었지만 명령 행 프로그램을 디먼 할 수 있으며이를 관리하기위한 원격 제어를 제공 할 수 있습니다).
  4. Emil이 제안한대로 자신의 데몬 즈 래퍼를 작성하되 과도한 IMO입니다.

가장 간단한 방법 (내 의견으로는 화면)을 추천하고 더 많은 기능을 원한다면 더 복잡한 방법으로 이동하십시오.


비슷한 감독 구성을 제공 할 수 있습니까?
Alix Axel

11

이 문제를 해결하는 방법은 여러 가지가 있습니다.

구체적인 내용을 모르지만 PHP 프로세스를 트리거하는 다른 방법이있을 수 있습니다. 예를 들어 SQL 데이터베이스의 이벤트를 기반으로 코드를 실행해야하는 경우 스크립트를 실행하도록 트리거를 설정할 수 있습니다. 이것은 PostgreSQL에서 매우 쉽습니다 : http://www.postgresql.org/docs/current/static/external-pl.html .

솔직히 가장 좋은 방법은 nohup을 사용하여 Damon 프로세스를 만드는 것입니다. nohup을 사용하면 사용자가 로그 아웃 한 후에도 명령을 계속 실행할 수 있습니다.

nohup php myscript.php &

그러나 매우 심각한 문제가 있습니다. PHP의 메모리 관리자는 완전한 쓰레기라고 말했듯이 스크립트는 몇 초 동안 만 실행되고 존재한다는 가정하에 작성되었습니다. PHP 스크립트는 며칠 후에 기가 바이트의 메모리를 사용하기 시작합니다. 다음과 같이 PHP 스크립트를 죽이고 다시 생성하는 12 시간 또는 24 시간마다 실행되는 cron 스크립트를 작성해야합니다.

killall -3 php
nohup php myscript.php &

그러나 대본이 작업 도중에 있다면 어떨까요? kill -3은 인터럽트이며 CLI에서 ctrl + c를 수행하는 것과 같습니다. PHP 스크립트는 PHP pcntl 라이브러리를 사용하여이 인터럽트를 포착하고 정상적으로 종료 할 수 있습니다. http://php.oregonstate.edu/manual/en/function.pcntl-signal.php

예를 들면 다음과 같습니다.

function clean_up() {
  GLOBAL $lock;
  mysql_close();
  fclose($lock)
  exit();
}
pcntl_signal(SIGINT, 'clean_up');

$ lock의 기본 개념은 PHP 스크립트가 fopen ( "file", "w");로 파일을 열 수 있다는 것입니다. 하나의 프로세스 만 파일에 대한 쓰기 잠금을 가질 수 있으므로이를 사용하여 PHP 스크립트의 사본 하나만 실행되도록 할 수 있습니다.

행운을 빕니다!




3

최근에 PHP 스크립트를 데몬으로 실행하는 문제에 대한 크로스 플랫폼 솔루션 (Windows, Mac 및 Linux)이 필요했습니다. 내 C ++ 기반 솔루션을 작성하고 바이너리를 만들어 문제를 해결했습니다.

https://github.com/cubiclesoft/service-manager/

sysvinit를 통한 Linux에 대한 완벽한 지원뿐만 아니라 Windows NT 서비스 및 Mac OSX도 출시되었습니다.

Linux 만 있으면 여기에 제시된 몇 가지 다른 솔루션이 맛에 따라 충분히 잘 작동합니다. 요즘 Upstart와 systemd도 있는데, sysvinit 스크립트로 대체되었습니다. 그러나 PHP를 사용하는 시점의 절반은 본질적으로 크로스 플랫폼이기 때문에 언어로 작성된 코드는 그대로 어디서나 작업 할 수있는 좋은 기회가 있습니다. 시스템 서비스와 같은 특정 외부 고유 OS 레벨 측면이 그림에 들어 오면 결함이 나타나기 시작하지만 대부분의 스크립팅 언어에서 문제가 발생합니다.

PHP userland에서 누군가 제안한 것처럼 신호를 잡으려고 시도하는 것은 좋은 생각이 아닙니다. 의 설명서를 읽으십시오pcntl_signal() 주의 깊게 읽으면 PHP는 프로세스에서 거의 볼 수없는 무언가 (예 : 신호)에 대해 많은주기를 씹는 다소 불쾌한 방법 (특히 '틱')을 사용하여 신호를 처리한다는 것을 빨리 알게됩니다. PHP의 신호 처리는 POSIX 플랫폼에서만 사용 가능하며 PHP 버전에 따라 지원이 다릅니다. 처음에는 괜찮은 해결책처럼 들리지만 실제로 유용하지는 않습니다.

PHP는 시간이 지남에 따라 메모리 누수 문제에 대해 더 나아지고 있습니다. 여전히 조심해야합니다 (DOM XML 파서가 여전히 유출되는 경향이 있습니다). 요즘 런 어웨이 프로세스는 거의 보이지 않으며 PHP 버그 추적기는 요일과 비교하여 꽤 조용합니다.


1

다른 사람들이 이미 언급했듯이 PHP를 데몬으로 실행하는 것은 매우 쉽고 단일 명령 줄을 사용하여 수행 할 수 있습니다. 그러나 실제 문제는 계속 실행하고 관리하는 것입니다. 나는 꽤 오래 전에 같은 문제를 겪었고 이미 사용 가능한 솔루션이 많지만 대부분 의존성이 많거나 사용하기 어렵고 기본 사용법에는 적합하지 않습니다. PHP cli 스크립트를 포함한 모든 프로세스 / 응용 프로그램을 관리 할 수있는 쉘 스크립트를 작성했습니다. 응용 프로그램을 시작하기 위해 cronjob으로 설정할 수 있으며 응용 프로그램을 포함하고 관리합니다. 예를 들어 동일한 cronjob을 통해 다시 실행되면 앱이 실행 중인지 확인하고 실행 중인지 여부를 확인한 다음 단순히 종료하고 이전 인스턴스가 애플리케이션 관리를 계속하도록합니다.

나는 그것을 github에 업로드했다, 그것을 자유롭게 사용하십시오 : https://github.com/sinasalek/EasyDeamonizer

EasyDeamonizer

응용 프로그램 (시작, 다시 시작, 로그, 모니터 등)을 간단히 감시하십시오. 응용 프로그램이 제대로 실행되고 있는지 확인하기위한 일반 스크립트 의도적으로 pid / lock 파일의 프로세스 이름을 사용하여 모든 부작용을 방지하고 스크립트를 가능한 한 간단하고 단호하게 유지하므로 EasyDaemonizer 자체가 다시 시작된 경우에도 항상 작동합니다. 풍모

  • 응용 프로그램을 시작하고 선택적으로 각 시작에 대해 사용자 정의 된 지연
  • 하나의 인스턴스 만 실행되고 있는지 확인
  • CPU 사용량을 모니터링하고 정의 된 임계 값에 도달하면 앱을 자동으로 다시 시작합니다.
  • 어떤 이유로 든 중지 된 경우 EasyDeamonizer가 cron을 통해 다시 실행되도록 설정
  • 활동을 기록합니다

1

Emil Ivaov 답변을 확장 하면 다음을 수행하여 PHP에서 STDIN, STDOUT 및 STDERROR를 닫을 수 있습니다

if (!fclose(STDIN)) {
    exit("Could not close STDIN");
}

if (!fclose(STDOUT)) {
    exit("Could not close STDOUT");
}

if (!fclose(STDERR)) {
    exit("Could not close STDERR");
}

$STDIN = fopen('/dev/null', 'r');
$STDOUT = fopen('/dev/null', 'w');
$STDERR = fopen('/var/log/our_error.log', 'wb');

기본적으로 PHP가 작성할 장소가 없도록 표준 스트림을 닫습니다. 다음 fopen호출은 표준 IO를로 설정합니다 /dev/null.

나는 웹을 넘어 PHP-Rob Aley의 책에서 이것을 읽었습니다.



0

여기서 pm2를 확인할 수 있습니다 ( http://pm2.keymetrics.io/).

처리 할 PHP 스크립트에 worker.sh와 같은 ssh 파일을 만듭니다.

worker.sh

php /path/myscript.php

데몬 시작

pm2 start worker.sh

건배, 그게 다야.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.