php e seus demônios
DESCRIPTION
Criando Daemons em PHP Macro tópicos • Forks • Sinais • Daemons • Spawn • Zombies • IPCTRANSCRIPT
![Page 1: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/1.jpg)
PHP e seus demôniosCRIANDO DAEMONS EM PHP
![Page 2: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/2.jpg)
PALESTRANTE
�2
![Page 3: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/3.jpg)
Henrique Moody
• Desenvolvedor web com foco em PHP desde 2007
• Usuário assíduo de Linux desde 2008 • Zend Certified Engineer 5.3 desde 2011 • Contribui com vários projetos Open Source • Líder Técnico • Desenvolvedor PHP Senior
�3
![Page 4: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/4.jpg)
PALESTRA
�4
![Page 5: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/5.jpg)
PHP e seus demônios
• Forks • Sinais • Daemons • Spawn • Zombies • IPC
�5
![Page 6: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/6.jpg)
FORKS
�6
![Page 7: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/7.jpg)
• Em sistemas operacionais Unix-‐like fork é uma operação em que um processo cria uma cópia de si mesmo
• Fork é uma forma de um processo executar outro ou outros processos a partir de si mesmo
• Quando a cópia do processo é criada essa cópia é chamada de processo filho tornando o processo original o processo pai
• No PHP é necessária a extensão PCNTL habilitada e extremamente recomendável a extensão POSIX também habilitada
�7
![Page 8: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/8.jpg)
PCNTL (Process Control)
• Deve ser habilitada no momento da compilação do PHP (——enable-pcntl)
• Suportada apenas para sistemas Unix-‐like • Não funciona em web servers • Cria e gerencia processos e sinais
�8
![Page 9: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/9.jpg)
POSIX (Portable Operating System Interface)
• Habilitada por padrão na compilação do PHP • Suportada apenas para sistemas Unix-‐like • Fornece uma API padrão para desenvolvimento em sistemas Unix-‐like
• Gerencia processos, sessões, grupos, usuários e arquivos de sistemas Unix-‐like
�9
![Page 10: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/10.jpg)
Funcionamento
• A função pcntl_fork() criará o fork e retornará um valor diferente para cada processo (pai e filho)
• Caso pcntl_fork() retorne -1 ocorreu um erro no fork • Caso pcntl_fork() retorne 0 houve sucesso no fork. O processo atual é o filho
• Caso pcntl_fork() retorne um número maior do que 0 houve sucesso no fork. O processo atual é o pai e o retorno de pcntl_fork() é o PID do filho
• Nada impede um processo filho criar forks de si mesmo • Todas as variáveis inicializadas no processo pai estarão disponíveis para os filhos
�10
![Page 11: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/11.jpg)
Forks/pcntl.php<?php$pid = pcntl_fork();if ($pid == -1) { // Falha na criação do fork echo 'Falha na criação do fork' . PHP_EOL;!} elseif ($pid > 0) { // Sou o processo pai echo 'Fork criado com sucesso sob o PID ' . $pid . PHP_EOL;!} else { // Sou o processo filho, em background mail('vagrant@localhost', 'Lorem ipsum', 'Dolor sit amet');}
�11
![Page 12: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/12.jpg)
Forks/pcntl+posix.php<?php$pid = pcntl_fork();if ($pid == -1) { // Falha na criação do fork echo 'Falha na criação do fork' . PHP_EOL;!} elseif ($pid > 0) { // Sou o processo pai echo 'Fork criado com sucesso sob o PID ' . $pid . PHP_EOL;!} else { // Sou o processo filho, em background if (0 !== posix_getuid()) { error_log('É necessário ser root para alterar informações do processo'); exit(2); }! if (! posix_setuid(1000)) { error_log('Não foi possível definir o usuário do processo como 1000'); exit(3); }! if (! posix_setgid(1000)) { error_log('Não foi possível definir o grupo do processo como 1000'); exit(4); }! mail('vagrant@localhost', 'Lorem ipsum', 'Dolor sit amet');}
�12
![Page 13: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/13.jpg)
SINAIS
�13
![Page 14: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/14.jpg)
• Em sistemas Unix-‐like, um sinal é uma notificação de software a um processo da ocorrência de um evento
• Um sinal é gerado pelo SO quando o evento que causa o sinal acontece
• Existem vários sinais que podem ser enviados para um processo, alguns deles podem ser manipulados pela aplicação já outros apenas pelo próprio SO
• Podemos enviar através da função posix_kill() • Podemos definir um callback para manipular sinais através da função pcntl_signal()
�14
![Page 15: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/15.jpg)
Lista de constantes de sinais do PHP• SIGABRT• SIGALRM• SIGBABY• SIGBUS• SIGCHLD• SIGCONT• SIGFPE• SIGHUP• SIGILL• SIGINT• SIGIO
• SIGIOT• SIGKILL• SIGPIPE• SIGPROF• SIGQUIT• SIGSEGV• SIGSTOP• SIGSYS• SIGTERM• SIGTRAP• SIGTSTP
• SIGTTIN• SIGTTOU• SIGURG• SIGUSR1• SIGUSR2• SIGVTALRM• SIGWINCH• SIGXCPU• SIGXFSZ
�15
![Page 16: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/16.jpg)
Mais comuns• SIGHUP: enviado quando o sessão (terminal) do processo é fechada
• Pode ser interceptado • SIGINT: enviado quando um se pretende interromper o processo
• Pode ser interceptado • Pode ser enviado via teclado, com Control-C, e em alguns sistemas com delete ou break
• SIGTSTP: enviado quando se pretende pausar o processo • Pode ser interceptado • Pode ser enviado via teclado, com Control-Z
• SIGCONT: enviado quando se pretende despausar o processo após SIGTSTP • Pode ser interceptado
• SIGTERM: enviado quando se pretende terminar o processo (amigavelmente). • Pode ser interceptado
• SIGQUIT: enviado quando se pretende encerrar o processo e obter um dump de memória. • Pode ser interceptado • Pode ser enviado via teclado, com Control-\
• SIGKILL: enviado quando se pretende encerrar imediatamente o processo • Não ser interceptado
�16
![Page 17: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/17.jpg)
Sinais/envio.php<?php!// Envia um 0 (verifica se o PID é válido ou não)posix_kill($pid, 0);!// Envia um SIGUSR1 (User-defined signal 1)posix_kill($pid, SIGUSR1);!// Envia um SIGSTOP (pausa a execução do processo)posix_kill($pid, SIGSTOP);!// Envia um SIGCONT (continua a execução do processo)posix_kill($pid, SIGCONT);!// Envia um SIGKILL (mata instantâneamente o processo)posix_kill($pid, SIGKILL);
�17
![Page 18: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/18.jpg)
Sinais/manipulacao.php<?php!declare(ticks = 1);function signalHandler($signal){ switch ($signal) { case SIGQUIT; error_log('Me fecharam com o teclado (Control-\)'); exit(1); case SIGINT: error_log('Me interromperam com o teclado (Control-C)'); exit(1); case SIGHUP: error_log('Fecharam meu terminal'); exit(1); case SIGTERM: error_log('Me pediram para me matar'); exit(0); }} !pcntl_signal(SIGQUIT, 'signalHandler');pcntl_signal(SIGINT, 'signalHandler');pcntl_signal(SIGHUP, 'signalHandler');pcntl_signal(SIGTERM, 'signalHandler');pcntl_signal(SIGTSTP, 'signalHandler');pcntl_signal(SIGTSTP, SIG_IGN); // SIG_IGN faz com que SIGTSTP seja ignoradopcntl_signal(SIGCONT, SIG_IGN); // SIG_IGN faz com que SIGCONT seja ignorado!echo 'PID: ' . getmypid() . PHP_EOL;while (true) { echo date('Y-m-d H:i:s') . PHP_EOL; sleep(1);}
�18
![Page 19: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/19.jpg)
DAEMONS
�19
![Page 20: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/20.jpg)
• Acrônimo de Disk And Execution MONitor (Monitor de Execução e de Disco)
• Em Unix e outros sistemas operacionais multi-‐tarefas é um programa de computador que roda de forma independente em background, ao invés de ser controlado diretamente por um usuário
• Em um ambiente Unix, o processo pai de um daemon é normalmente (mas nem sempre) o processo init (PID=1)
• Alguns exemplos de daemons são: MySQL Server, Apache Server, Nginx Server, Cron
• Muitas vezes, um programa se torna um daemon através de forking
�20
![Page 21: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/21.jpg)
�21
CRIANDO UM DAEMON
![Page 22: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/22.jpg)
Passo a passo
1. Fork off and die 2. Máscara de criação dos arquivos 3. Entradas e saídas 4. Logging 5. Desligar sessão (SID) 6. Working directory 7. Locking
�22
![Page 23: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/23.jpg)
Fork off and die
• Você apenas criará o fork e encerrará imediatamente o processo pai
• O processo filho será o daemon, executando em background
�23
![Page 24: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/24.jpg)
Daemons/fork.php<?php$pid = pcntl_fork();if ($pid == -1) { echo 'Falha na criação do fork' . PHP_EOL; exit(2);!} elseif ($pid > 0) { echo 'Daemon inicializado (PID: ' . $pid . ').' . PHP_EOL; exit();}!while (true) { mail('vagrant@localhost', 'Lorem ipsum', 'Dolor sit amet'); sleep(2);}
�24
![Page 25: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/25.jpg)
Máscara de criação dos arquivos
• Para garantir que você possa ler e escrever arquivos restaure o umask para o padrão do sistema, com umask(0)
�25
![Page 26: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/26.jpg)
Daemons/fork+umask.php<?php$pid = pcntl_fork();if ($pid == -1) { echo 'Falha na criação do fork' . PHP_EOL; exit(2);!} elseif ($pid > 0) { echo 'Daemon inicializado (PID: ' . $pid . ').' . PHP_EOL; exit();}!umask(0);!while (true) { mail('vagrant@localhost', 'Lorem ipsum', 'Dolor sit amet'); sleep(2);}
�26
![Page 27: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/27.jpg)
Entradas e saídas
• O daemon não possui interação com o usuário, portanto você não deve permitir que os métodos de entrada e saída (STDIN, STDOUT e STDERR) sejam utilizados
• Você pode fechar STDIN, STDOUT e STDERR, mas caso você esteja utilizando essas constantes com certeza você terá problemas
• Você também pode utilizar as funções ob_* para evitar outputs
�27
![Page 28: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/28.jpg)
Daemons/fork+umask+file_descriptors.php<?php$pid = pcntl_fork();if ($pid == -1) { echo 'Falha na criação do fork' . PHP_EOL; exit(2);!} elseif ($pid > 0) { echo 'Daemon inicializado (PID: ' . $pid . ').' . PHP_EOL; exit();}!umask(0);!fclose(STDIN);fclose(STDOUT);fclose(STDERR);!$fd0 = fopen('/dev/null', 'r');$fd1 = fopen('/tmp/psd.log', 'a');$fd2 = fopen('php://stdout', 'a');!while (true) { mail('vagrant@localhost', 'Lorem ipsum', 'Dolor sit amet'); sleep(2);}
�28
![Page 29: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/29.jpg)
Logging
• Visto que não interação entre o daemon e o usuário, logs são uma ótima forma de obter feedback de um daemon
• Você pode fazer logs em: ‣ Arquivos ‣ Bancos de dados relacionais ‣ Bancos de dados não-‐relacionais ‣ Message Queue ‣ Syslog ‣ …
�29
![Page 30: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/30.jpg)
Daemons/fork+umask+file_descriptors+logging.php<?php$pid = pcntl_fork();if ($pid == -1) { echo 'Falha na criação do fork' . PHP_EOL; exit(2);!} elseif ($pid > 0) { echo 'Daemon inicializado (PID: ' . $pid . ').' . PHP_EOL; exit();}!umask(0);!fclose(STDIN);fclose(STDOUT);fclose(STDERR);!$fd0 = fopen('/dev/null', 'r');$fd1 = fopen('/tmp/psd.log', 'a');$fd2 = fopen('php://stdout', 'a');!openlog('PSD', LOG_PID | LOG_CONS, LOG_LOCAL0);while (true) { syslog(LOG_DEBUG, 'Envio de email iniciando'); $sent = mail('vagrant@localhost', 'Lorem ipsum', 'Lorem ipsum dolor sit amet'); if (true === $sent) { syslog(LOG_DEBUG, 'Envio de email terminado sucesso'); continue; } syslog(LOG_ERR, 'Falha ao enviar email'); sleep(2);}closelog();
�30
!
![Page 31: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/31.jpg)
Desligar sessão (SID)
• Mesmo que o processo filho seja executado em background, não dependendo do processo pai, eles estão na mesma sessão
• Quando a sessão terminar (o terminal fechado, por exemplo), o sistema matará o processo filho
• A função posix_setsid() cria uma nova sessão para o processo filho, desvinculando-‐o do processo pai e sua sessão
• O processo filho passa a ter o init (processo inicial que carrega todos os outros processos do sistema) como processo pai
�31
![Page 32: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/32.jpg)
Daemons/fork+umask+file_descriptors+logging+detach_sid.php<?php$pid = pcntl_fork();if ($pid == -1) { echo 'Falha na criação do fork' . PHP_EOL; exit(2);!} elseif ($pid > 0) { echo 'Daemon inicializado (PID: ' . $pid . ').' . PHP_EOL; exit();}!umask(0);!fclose(STDIN);fclose(STDOUT);fclose(STDERR);!$fd0 = fopen('/dev/null', 'r');$fd1 = fopen('/tmp/psd.log', 'a');$fd2 = fopen('php://stdout', 'a');!openlog('PSD', LOG_PID | LOG_CONS, LOG_LOCAL0);!if (posix_setsid() < 0) { syslog(LOG_ERR, 'Não foi possível desvincular processo de sua sessão'); exit(2);}!while (true) { /** Payload **/ }closelog();
�32
![Page 33: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/33.jpg)
Working directory
• O filho herda o working directory do pai • Este working directory pode ser um volume montado que pode ser desmontado em algum momento
• Para desmontar um volume o sistema irá matar qualquer processo que ainda está usando o diretório
�33
![Page 34: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/34.jpg)
Daemons/fork+umask+file_descriptors+logging+detach_sid+chdir.php<?php$pid = pcntl_fork();if ($pid == -1) { echo 'Falha na criação do fork' . PHP_EOL; exit(2);!} elseif ($pid > 0) { echo 'Daemon inicializado (PID: ' . $pid . ').' . PHP_EOL; exit();}!umask(0);!fclose(STDIN);fclose(STDOUT);fclose(STDERR);!$fd0 = fopen('/dev/null', 'r');$fd1 = fopen('/tmp/psd.log', 'a');$fd2 = fopen('php://stdout', 'a');!openlog('PSD', LOG_PID | LOG_CONS, LOG_LOCAL0);!if (posix_setsid() < 0) { syslog(LOG_ERR, 'Não foi possível desvincular processo de sua sessão'); exit(2);}!chdir(__DIR__);!while (true) { /** Payload **/ }closelog();
�34
![Page 35: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/35.jpg)
pidfile
• Contém o PID do daemon • Impede que o daemon seja executado mais de uma vez
�35
![Page 37: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/37.jpg)
Daemons/fork+umask+file_descriptors+logging+detach_sid+chdir+pidfile.php<?php!$pidfile = '/var/run/psd/daemon.pid';if (file_exists($pidfile)) { $daemonPid = (int) file_get_contents($pidfile); if (true === posix_kill($daemonPid, 0)) { echo 'Daemon já em execução (PID ' . $daemonPid . ').' . PHP_EOL; exit(2); } unlink($pidfile);}!$pidfileHandler = fopen($pidfile, 'w+');!if (! flock($pidfileHandler, LOCK_EX | LOCK_NB)) { echo 'Falha ao bloquear acesso externo ao pidfile' . PHP_EOL; exit(3);}!$pid = pcntl_fork();if ($pid == -1) { echo 'Falha na criação do fork' . PHP_EOL; exit(4);!} elseif ($pid > 0) { if (! fwrite($pidfileHandler, $pid)) { echo 'Falha ao escrever PID no pidfile' . PHP_EOL; exit(5); }! echo 'Daemon inicializado (PID: ' . $pid . ').' . PHP_EOL; exit();}!register_shutdown_function('unlink', $pidfile); !// Corpo do daemon
�37
![Page 38: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/38.jpg)
SPAWN
�38
![Page 39: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/39.jpg)
• Muito utilizado no processamento de filas quando você precisa de processos concorrentes
• Um processo pode criar outros processos e delegar tarefas para cada um deles
• Esse recurso muitas vezes é confundido com multi-‐threading, mas não é isso. O PHP não possui suporte a este recurso mas existe uma extensão PECL para isso
• Geralmente os processos pai são daemons sendo seus filhos workers
• Você não pode alterar o SID dos filhos pois você precisa deles na mesma sessão do processo pai
�39
![Page 40: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/40.jpg)
Spawn/exemplo.php<?php$pid = pcntl...// Fluxo normal do daemon!$childrenLimit = 10;$childrenPids = array();while (true) { if (count($childrenPids) >= $childrenLimit) { $firstChildPid = array_shift($childrenPids); pcntl_waitpid($firstChildPid, $status); }! $childPid = pcntl_fork();! if ($childPid == -1) { syslog(LOG_ERR, 'Falha ao criar filho'); continue; }! if ($childPid > 0) { $childrenPids[] = $childPid; continue; }! syslog(LOG_DEBUG, 'Envio de email iniciando'); $sent = mail('vagrant@localhost', 'Lorem ipsum', 'Lorem ipsum dolor sit amet'); if (true === $sent) { syslog(LOG_DEBUG, 'Envio de email terminado sucesso'); exit(0); } syslog(LOG_ERR, 'Falha ao enviar email'); exit(3);}closelog();
�40
![Page 41: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/41.jpg)
ZOMBIES
�41
![Page 42: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/42.jpg)
• Um processo zombie é um processo que já foi completamente executado mas ainda se encontra na tabela de processos do SO, permitindo que o processo que o criou leia o seu valor de saída
• Quando um processo termina, a memória a ele associada é libertada, no entanto a informação sobre esse processo continua disponível, embora ele já não exista
• Normalmente os processos zombie não duram muito tempo já que o sinal SIGCHLD é emitido quando ele entra nesse estado, possibilitando ao processo pai saber quando isso acontece para ler as informações necessárias
• Se o processo pai explicitamente ignora o SIGCHLD definindo seu manipulador como SIG_IGN todos as informações de término dos processos filhos serão descartadas e os processos zombies continuarão na tabela
�42
![Page 43: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/43.jpg)
Zombies/reaper.php<?php!function reaper($signal){ if ($signal != SIGCHLD) { return; }! while (pcntl_waitpid(-1, $status, WNOHANG | WUNTRACED) > 0) { usleep(1000); }}!pcntl_signal(SIGCHLD, 'reaper');
�43
![Page 44: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/44.jpg)
Inter-‐Process Communication
IPC
�44
![Page 45: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/45.jpg)
• Cada processo possui um contexto de execução próprio. Um processo não tem conhecimento do contexto de outro processo sendo assim os processos não conseguem transferir informação entre si
• Inter-‐Process Communication (IPC), é o grupo de mecanismos que permite aos processos transferirem informação entre si
• Usando IPC um processo pai consegue obter informações precisar de seus filhos
• Para IPC podemos utilizar: ‣ Arquivos ‣ Filas de mensagens ‣ Memória Compartilhada ‣ Sinais ‣ Par de Sockets ‣ …
�45
![Page 46: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/46.jpg)
Arquivos
• Você pode escrever dados em um processo e ler em outro processo, desde que ambos tenham permissão de leitura
• Nome do arquivo deve ser único
�46
![Page 47: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/47.jpg)
IPC/file.php<?php!$filename = '/tmp/' . getmypid() . '.ipc';if (! is_file($filename)) { touch($filename);}!$dataWritten = 'PHP e seus Demônios';if (false === file_put_contents($filename, $dataWritten)) { echo 'Falha ao gravar dados no arquivo' . PHP_EOL; exit(2);}!$dataGiven = file_get_contents($filename);if (false === $dataGiven) { echo 'Falha ao ler dados no arquivo' . PHP_EOL; exit(3);}!echo 'Dado lido no arquivo: ' . $dataGiven . PHP_EOL;!if (! unlink($filename)) { echo 'Falha ao tentar remover o arquivo' . PHP_EOL; exit(3);}
�47
![Page 48: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/48.jpg)
Memória compartilhada• É um fácil caminho para usar funções que permitem o PHP ler, escrever, criar e deletar segmentos de memória compartilhada UNIX
• O PHP possui duas API’s, as funções shmop_* e shm_*: • Para habilitar as funções shmop_* é preciso compilar o PHP com a opção --enable-shmop do configure
• Para habilitar as funções shm_* é preciso compilar o PHP com a opção --enable-sysvshm do configure
• Funciona basicamente com uma chave, por ela você pode ler e escrever dados na memória
• Utilize o comando ipcs para monitorar os seguimentos criados e ipcrm shm ID para remover seguimentos (você também pode usar ipcmk para criar seguimentos)
�48
![Page 49: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/49.jpg)
IPC/shmop.php<?php!$key = getmypid();$flag = 'c';$permission = 0644;$memorySize = 1024;!$shmId = shmop_open($key, $flag, $permission, $memorySize);if (! $shmId) { echo 'Não foi possível criar o segmento de memória' . PHP_EOL; exit(1);}!$stringWritten = 'PHP e seus demônios';$shmBytesWritten = shmop_write($shmId, $stringWritten, 0);if ($shmBytesWritten != strlen($stringWritten)) { echo 'Não foi possível gravar o dado e com seu tamanho correto' . PHP_EOL; exit(2);}!$stringRead = shmop_read($shmId, 0, $memorySize);if (! $stringRead) { echo 'Não foi possível ler o dado na memória compartilhada' . PHP_EOL; exit(2);}!echo 'Dado lido na memória compartilhada foi: ' . $stringRead . PHP_EOL;!if (! shmop_delete($shmId)) { echo 'Não foi possível marcar o bloco de memória compartilhada para remoção';}!shmop_close($shmId);
�49
![Page 50: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/50.jpg)
IPC/shm.php<?php!$key = getmypid();$permission = 0644;$memorySize = 1024;!$shmId = shm_attach($key, $memorySize, $permission);if (! $shmId) { echo 'Falha ao criar o segmento de memória' . PHP_EOL; exit(1);}!$stringWritten = 'PHP e seus demônios';if (! shm_put_var($shmId, 1, $stringWritten)) { echo 'Falha ao gravar o dado na memória compartilhada' . PHP_EOL; exit(2);}!if (! shm_has_var($shmId, 1)) { echo 'Nenhum dado na chave 1 foi encontrado na memória' . PHP_EOL; exit(2);}!$stringRead = shm_get_var($shmId, 1);if (! $stringRead) { echo 'Falha ao ler o dado da chave 1 na memória compartilhada' . PHP_EOL; exit(2);}!echo 'Dado lido na memória compartilhada foi: ' . $stringRead . PHP_EOL;!if (! shm_remove($shmId)) { echo 'Falha ao remover do bloco de memória compartilhada';}!if (! shm_detach($shmId)) { echo 'Falha ao se desconectar do bloco de memória compartilhada';}
�50
![Page 51: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/51.jpg)
Filas de mensagens
• O PHP possui suporte a filas de mensagens do • Para habilitar as funções msg_* é preciso compilar o PHP com a opção --enable-sysvmsg do configure
• Utilize o comando ipcs para monitorar os seguimentos criados e ipcrm msg ID para remover seguimentos (você também pode usar ipcmk para criar seguimentos)
�51
![Page 52: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/52.jpg)
IPC/msg.php<?php!$key = getmypid();$messageQueueId = msg_get_queue($key);!$messageSent = 'PHP e seus demônios';$messageWasSent = msg_send($messageQueueId, 2, $messageSent);if (! $messageWasSent) { echo 'Falha ao enviar mensagem' . PHP_EOL; exit(2);}!if (! msg_receive($messageQueueId, 2, $msgType, 1024, $messageReceived, true, 0, $error)) { echo 'Falha ao ler mensagem' . $error . PHP_EOL; exit(3);}echo 'Mensagem recebida: ' . $messageReceived . PHP_EOL;!if (! msg_remove_queue($messageQueueId)) { echo 'Falha ao remover fila de mensagens'. PHP_EOL; exit(3);}
�52
![Page 53: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/53.jpg)
Par de sockets
• Dois sockets conectados armazenados em um array
• Conexão de duas vias, as mensagens são entregues no mesmo instante
�53
![Page 54: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/54.jpg)
IPC/msg.php<?php!$sockets = array();!if (false === socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $sockets)) { echo 'Falha ao criar par de sockets: ' . socket_strerror(socket_last_error()) . PHP_EOL;}!$pid = pcntl_fork();if ($pid == -1) { echo 'Falha na criação do fork' . PHP_EOL;} elseif ($pid > 0) {! socket_close($sockets[0]); $messageWritten = 'Mensagem enviada pelo processo pai'; if (false === socket_write($sockets[1], $messageWritten, strlen($messageWritten))) { echo 'Falha ao escrever dados no socket: ' . socket_strerror(socket_last_error($sockets)); exit(3); }! $messageGiven = socket_read($sockets[1], 1024, PHP_BINARY_READ);! echo 'Mensagem no processo pai: ' . "\t" . $messageGiven . PHP_EOL; socket_close($sockets[1]);!} else {! socket_close($sockets[1]); $messageWritten = 'Mensagem enviada pelo processo filho'; if (false === socket_write($sockets[0], $messageWritten, strlen($messageWritten))) { echo 'Falha ao escrever dados no socket: ' . socket_strerror(socket_last_error($sockets)); exit(3); }! $messageGiven = socket_read($sockets[0], 1024, PHP_BINARY_READ);! echo 'Mensagem no processo filho: ' . "\t" . $messageGiven . PHP_EOL; socket_close($sockets[0]);}
�54
![Page 55: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/55.jpg)
Outras formas
• APC • Memcached • MongoDB • MySQL • RabbitMQ • Redis • SQLite • …
�55
![Page 56: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/56.jpg)
PERFORMANCE
�56
![Page 57: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/57.jpg)
• Não existe garbage collection, o processo principal não morre
• Utilize as funções gc_enable() e gc_collect_cycles()
• O PHP possui um cache padrão de arquivos abertos (em memória) isso pode prejudicar a performance do daemon, utilize clearstatcache() para remover esse cache
• Utilizar IPC sem limpar os dados corretamente pode ocasionar uma série de problemas
�57
![Page 58: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/58.jpg)
BIBLIOTECAS
�58
![Page 59: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/59.jpg)
• Arara\Process (https://github.com/Arara/Proccess)
• PHP-‐Daemon (https://github.com/shaneharter/PHP-‐Daemon)
• System_Daemon (http://pear.php.net/package/System_Daemon)
• ZendX_Console_Process_Unix (http://framework.zend.com/manual/1.12/en/zendx.console.process.unix.html)
�59
![Page 60: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/60.jpg)
PERGUNTAS
�60
![Page 61: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/61.jpg)
CONCLUSÃO
�61
![Page 62: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/62.jpg)
Links
• @henriquemoody na maioria das redes sociais (about.me, BitBucket, Coderbits, GitHub, SlideShare, Twitter…)
• Código da palestra: https://github.com/henriquemoody/php-‐e-‐seus-‐demonios/tree/1.0.0
• Ícones: http://www.visualpharm.com • Formatação de código: https://sublime.wbond.net/packages/Highlight
�62
![Page 63: PHP e seus demônios](https://reader038.vdocuments.mx/reader038/viewer/2022103117/559c5c3c1a28ab7e6e8b4854/html5/thumbnails/63.jpg)
Referências• http://en.wikipedia.org/wiki/Cron • http://en.wikipedia.org/wiki/Daemon_(computing) • http://en.wikipedia.org/wiki/Init • http://en.wikipedia.org/wiki/POSIX • http://man7.org/linux/man-‐pages/man7/signal.7.html • http://php.net/ChangeLog-‐4.php • http://php.net/cli • http://php.net/ncurses • http://php.net/newt • http://php.net/pcntl • http://php.net/posix • http://php.net/readline • http://pt.wikipedia.org/wiki/Daemon_(computação) • http://www.slideshare.net/jkeppens/php-‐in-‐the-‐dark • http://www.win.tue.nl/~aeb/linux/lk/lk-‐10.html
�63