system_daemon - 리눅스 php 데몬




데몬 프로세스로 PHP 스크립트 실행 (10)

Kevin van Zonneveld 는 이것에 대한 아주 좋은 기사를 썼습니다. 그의 예에서는 System_Daemon PEAR 패키지를 사용 합니다 (2009-09-02의 최종 출시일).

나는 데몬 프로세스 (지시를 기다리고 물건을 할 때)로 PHP 스크립트를 실행할 필요가있다. cron 작업은 명령이 도착하자마자 조치를 취해야하기 때문에 나를 위해하지 않습니다. 나는 PHP가 메모리 관리 문제로 인해 데몬 프로세스를위한 최선의 옵션이 아니라는 것을 알고 있습니다.하지만이 경우에는 PHP를 사용해야하는 여러 가지 이유로 인해서요. Daemon ( http://libslack.org/daemon )이라는 libslack 도구를 통해 데몬 프로세스를 관리하는 데 도움이되는 것처럼 보였지만 지난 5 년 동안 업데이트가 없었기 때문에 일부 정보를 알고 있는지 궁금합니다. 내 경우에 적합한 다른 대안. 모든 정보는 정말 감사하겠습니다.



너는 할 수있다.

  1. Henrik이 제안한대로 nohup 을 사용하십시오.
  2. screen 사용하고 PHP 프로그램을 그 내부의 정규 프로세스로 실행하십시오. 이것은 nohup 사용하는 것보다 더 많은 제어를 제공합니다.
  3. Supervisord 와 같은 daemoniser를 사용 Supervisord (파이썬으로 작성되었지만 모든 명령 행 프로그램을 daemonise 할 수 있으며이를 관리 할 수있는 원격 제어 기능을 제공합니다).
  4. Emil이 제안한 것처럼 자신의 daemonise 래퍼를 작성하십시오.하지만 과잉 IMO입니다.

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


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

github에 업로드 했으니 자유롭게 사용해보십시오. https://github.com/sinasalek/EasyDeamonizer

EasyDeamonizer

응용 프로그램 (시작, 다시 시작, 로그, 모니터 등)을 감시하기 만하면됩니다. 응용 프로그램이 제대로 실행되고 있는지 확인하기위한 일반 스크립트 의도적으로 pid / lock 파일의 프로세스 이름 instread를 사용하여 모든 부작용을 방지하고 스크립트를 가능한 단순하고 안정적으로 유지하므로 EasyDaemonizer 자체가 다시 시작될 때에도 항상 작동합니다. 풍모

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

또 다른 옵션은 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 에게 큰 감사를 드렸습니다. Kevin van Zonneveld 는이 기술을 배웠습니다.


새로운 systemd 를 사용하면 rhel 기반 Linux에서 서비스를 만들 수 있습니다.

/etc/systemd/system/ 에 파일이나 symlink 를 만들어야합니다. 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를주기 (예 : diggest)에서 한 번 실행해야한다면 PHP 대신 직접 systemd 서비스 파일에 호출 할 쉘 또는 bash 스크립트를 사용해야합니다. 예를 들면 다음과 같습니다.

#!/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

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


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

구체적인 내용은 모르지만 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 스크립트는이 인터럽트를 catch하여 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 스크립트 사본 하나만 실행되도록 할 수 있습니다.

행운을 빕니다!


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

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

Linux (sysvinit 경유)를위한 전폭 지원, 또한 Windows NT 서비스 및 Mac OSX launchd.

리눅스가 필요하다면 여기에 제시된 몇 가지 다른 솔루션들이 맛에 따라 충분히 잘 작동합니다. 요즘에는 Upstart와 systemd가 있는데, 이들은 sysvinit 스크립트를 대체합니다. 그러나 PHP 사용의 절반은 사실상 크로스 플랫폼이므로 언어로 작성된 코드는있는 그대로의 곳에서 작업 할 수있는 좋은 기회입니다. 특정 외부 네이티브 OS 레벨의 측면이 시스템 서비스와 같은 그림에 들어갈 때 결함이 나타나기 시작하지만 대부분의 스크립팅 언어에서 이러한 문제가 발생합니다.

PHP 유저 랜드에서 제안 된 것처럼 누군가와 신호를 잡으려고하는 것은 좋은 생각이 아닙니다. pcntl_signal() 에 대한 문서를주의 깊게 읽고 PHP가 프로세스 (예 : 신호)에서 거의 볼 수없는 여러 가지 사이클을 씹는 다소 불쾌한 방법 (특히 '틱')을 사용하여 신호를 처리한다는 것을 빨리 알게됩니다. PHP에서의 신호 처리는 POSIX 플랫폼에서만 거의 사용 가능하지 않으며 지원 버전은 PHP 버전에 따라 다릅니다. 처음에는 괜찮은 솔루션처럼 들리지만 실제로 유용하지는 못합니다.

PHP는 시간이 지남에 따라 메모리 누수 문제에 관해서도 개선되고 있습니다. 여전히 조심해야한다 (DOM XML 파서는 여전히 누수되는 경향이있다). 그러나 요즘에는 가출 프로세스가 거의 보이지 않으며 PHP 버그 추적기는 yore의 시절과 비교하여 꽤 조용하다.



Exilding Emil Ivaov Answer, 다음을 수행하여 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 로 설정합니다.

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





daemon