SlideShare uma empresa Scribd logo
1 de 63
Baixar para ler offline
PHP e seus demônios
CRIANDO	
  DAEMONS	
  EM	
  PHP
PALESTRANTE

2
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
PALESTRA

4
PHP	
  e	
  seus	
  demônios
•
•
•
•
•
•

Forks	
  
Sinais	
  
Daemons	
  
Spawn	
  
Zombies	
  
IPC

5
FORKS

6
• 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
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
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
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
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
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
SINAIS

13
• 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
Lista	
  de	
  constantes	
  de	
  sinais	
  do	
  PHP
• SIGABRT	

• SIGIOT	

• SIGTTIN	

• SIGALRM	

• SIGKILL	

• SIGTTOU	

• SIGBABY	

• SIGPIPE	

• SIGURG	

• SIGBUS	

• SIGPROF	

• SIGUSR1	

• SIGCHLD	

• SIGQUIT	

• SIGUSR2	

• SIGCONT	

• SIGSEGV	

• SIGVTALRM	

• SIGFPE	

• SIGSTOP	

• SIGWINCH	

• SIGHUP	

• SIGSYS	

• SIGXCPU	

• SIGILL	

• SIGTERM	

• SIGXFSZ

• SIGINT	

• SIGTRAP	

• SIGIO	

• SIGTSTP	
15
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
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
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 ignorado	
pcntl_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
DAEMONS

19
• 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
CRIANDO	
  UM	
  DAEMON
21
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
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
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
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
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
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
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
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
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
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
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
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
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
pidfile
• Contém	
  o	
  PID	
  do	
  daemon	
  
• Impede	
  que	
  o	
  daemon	
  seja	
  executado	
  mais	
  de	
  
uma	
  vez

35
Generated	
  by	
  https://www.lucidchart.com

36
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
SPAWN

38
• 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
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
ZOMBIES

41
• 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
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
Inter-­‐Process	
  Communication

IPC

44
• 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
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
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
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
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
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
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
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
Par	
  de	
  sockets
• Dois	
  sockets	
  conectados	
  armazenados	
  em	
  um	
  
array	
  
• Conexão	
  de	
  duas	
  vias,	
  as	
  mensagens	
  são	
  
entregues	
  no	
  mesmo	
  instante

53
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
Outras	
  formas
•
•
•
•
•
•
•
•

APC	
  
Memcached	
  
MongoDB	
  
MySQL	
  
RabbitMQ	
  
Redis	
  
SQLite	
  
…
55
PERFORMANCE

56
• 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
BIBLIOTECAS

58
• AraraProcess	
  (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
PERGUNTAS

60
CONCLUSÃO

61
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
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

Mais conteúdo relacionado

Mais procurados

utilitários de linha de comando bonitos em python
utilitários de linha de comando bonitos em pythonutilitários de linha de comando bonitos em python
utilitários de linha de comando bonitos em pythontdc-globalcode
 
Monitoramento funcional e não funcional em containers
Monitoramento funcional e não funcional em containersMonitoramento funcional e não funcional em containers
Monitoramento funcional e não funcional em containersRenan Petronilho Sant Anna
 
Container revolucao
Container revolucaoContainer revolucao
Container revolucaoFernando Ike
 
Desenvolvimento de Software I - USBWEBSERVER - PHP
Desenvolvimento de Software I - USBWEBSERVER - PHPDesenvolvimento de Software I - USBWEBSERVER - PHP
Desenvolvimento de Software I - USBWEBSERVER - PHPAndréia Santos
 
PHPSC Conference 2010 - Desenvolvimento de Extensões PECL
PHPSC Conference 2010 - Desenvolvimento de Extensões PECLPHPSC Conference 2010 - Desenvolvimento de Extensões PECL
PHPSC Conference 2010 - Desenvolvimento de Extensões PECLErick Belluci Tedeschi
 
Novidades PHP 7.4 e 8.0!
Novidades PHP 7.4 e 8.0!Novidades PHP 7.4 e 8.0!
Novidades PHP 7.4 e 8.0!Marcos Marcolin
 
Programando php com mais segurança
Programando php com mais segurançaProgramando php com mais segurança
Programando php com mais segurançaMichael Douglas
 
Lab python django - parte 2 - python + virtualenv
Lab python django - parte 2 - python + virtualenvLab python django - parte 2 - python + virtualenv
Lab python django - parte 2 - python + virtualenvPedro Fernandes Vieira
 
TDC2017 | POA Trilha Programacao Funicional - (Nunca) Ouvi falar de Rust... m...
TDC2017 | POA Trilha Programacao Funicional - (Nunca) Ouvi falar de Rust... m...TDC2017 | POA Trilha Programacao Funicional - (Nunca) Ouvi falar de Rust... m...
TDC2017 | POA Trilha Programacao Funicional - (Nunca) Ouvi falar de Rust... m...tdc-globalcode
 
Php além do LAMP
Php além do LAMPPhp além do LAMP
Php além do LAMPThiago Paes
 
TDC2016 | Trilha PHP - Xdebug: Seus problemas acabaram!
TDC2016 | Trilha PHP - Xdebug: Seus problemas acabaram!TDC2016 | Trilha PHP - Xdebug: Seus problemas acabaram!
TDC2016 | Trilha PHP - Xdebug: Seus problemas acabaram!tdc-globalcode
 
Xdebug seus problemas acabaram - TDC - PHPeste
Xdebug   seus problemas acabaram - TDC - PHPesteXdebug   seus problemas acabaram - TDC - PHPeste
Xdebug seus problemas acabaram - TDC - PHPesteVitor Mattos
 
TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...
TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...
TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...tdc-globalcode
 

Mais procurados (20)

utilitários de linha de comando bonitos em python
utilitários de linha de comando bonitos em pythonutilitários de linha de comando bonitos em python
utilitários de linha de comando bonitos em python
 
Monitoramento funcional e não funcional em containers
Monitoramento funcional e não funcional em containersMonitoramento funcional e não funcional em containers
Monitoramento funcional e não funcional em containers
 
Kernel cooperativo
Kernel cooperativoKernel cooperativo
Kernel cooperativo
 
Container revolucao
Container revolucaoContainer revolucao
Container revolucao
 
Desenvolvimento de Software I - USBWEBSERVER - PHP
Desenvolvimento de Software I - USBWEBSERVER - PHPDesenvolvimento de Software I - USBWEBSERVER - PHP
Desenvolvimento de Software I - USBWEBSERVER - PHP
 
PHPSC Conference 2010 - Desenvolvimento de Extensões PECL
PHPSC Conference 2010 - Desenvolvimento de Extensões PECLPHPSC Conference 2010 - Desenvolvimento de Extensões PECL
PHPSC Conference 2010 - Desenvolvimento de Extensões PECL
 
Igor Oliveira - Puppet
Igor Oliveira - PuppetIgor Oliveira - Puppet
Igor Oliveira - Puppet
 
Novidades PHP 7.4 e 8.0!
Novidades PHP 7.4 e 8.0!Novidades PHP 7.4 e 8.0!
Novidades PHP 7.4 e 8.0!
 
Programando php com mais segurança
Programando php com mais segurançaProgramando php com mais segurança
Programando php com mais segurança
 
UTools Unite Brasil
UTools Unite BrasilUTools Unite Brasil
UTools Unite Brasil
 
Primeira Aula PHP
Primeira Aula PHPPrimeira Aula PHP
Primeira Aula PHP
 
Lab python django - parte 2 - python + virtualenv
Lab python django - parte 2 - python + virtualenvLab python django - parte 2 - python + virtualenv
Lab python django - parte 2 - python + virtualenv
 
Drupal + Rex
Drupal + RexDrupal + Rex
Drupal + Rex
 
Fundamentos de Sockets
Fundamentos de SocketsFundamentos de Sockets
Fundamentos de Sockets
 
TDC2017 | POA Trilha Programacao Funicional - (Nunca) Ouvi falar de Rust... m...
TDC2017 | POA Trilha Programacao Funicional - (Nunca) Ouvi falar de Rust... m...TDC2017 | POA Trilha Programacao Funicional - (Nunca) Ouvi falar de Rust... m...
TDC2017 | POA Trilha Programacao Funicional - (Nunca) Ouvi falar de Rust... m...
 
Php além do LAMP
Php além do LAMPPhp além do LAMP
Php além do LAMP
 
TDC2016 | Trilha PHP - Xdebug: Seus problemas acabaram!
TDC2016 | Trilha PHP - Xdebug: Seus problemas acabaram!TDC2016 | Trilha PHP - Xdebug: Seus problemas acabaram!
TDC2016 | Trilha PHP - Xdebug: Seus problemas acabaram!
 
Xdebug seus problemas acabaram - TDC - PHPeste
Xdebug   seus problemas acabaram - TDC - PHPesteXdebug   seus problemas acabaram - TDC - PHPeste
Xdebug seus problemas acabaram - TDC - PHPeste
 
Zephir
ZephirZephir
Zephir
 
TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...
TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...
TDC2017 | São Paulo - Trilha Programação Funcional How we figured out we had ...
 

Destaque

TDC SP 2015 - PHP7: melhor e mais rápido
TDC SP 2015 - PHP7: melhor e mais rápidoTDC SP 2015 - PHP7: melhor e mais rápido
TDC SP 2015 - PHP7: melhor e mais rápidoBruno Ricardo Siqueira
 
Beautiful PHP CLI Scripts
Beautiful PHP CLI ScriptsBeautiful PHP CLI Scripts
Beautiful PHP CLI ScriptsJesse Donat
 
Docker - Demo on PHP Application deployment
Docker - Demo on PHP Application deployment Docker - Demo on PHP Application deployment
Docker - Demo on PHP Application deployment Arun prasath
 

Destaque (6)

TDC SP 2015 - PHP7: melhor e mais rápido
TDC SP 2015 - PHP7: melhor e mais rápidoTDC SP 2015 - PHP7: melhor e mais rápido
TDC SP 2015 - PHP7: melhor e mais rápido
 
Beautiful PHP CLI Scripts
Beautiful PHP CLI ScriptsBeautiful PHP CLI Scripts
Beautiful PHP CLI Scripts
 
Gof design patterns
Gof design patternsGof design patterns
Gof design patterns
 
Astah
AstahAstah
Astah
 
Design patterns de uma vez por todas
Design patterns de uma vez por todasDesign patterns de uma vez por todas
Design patterns de uma vez por todas
 
Docker - Demo on PHP Application deployment
Docker - Demo on PHP Application deployment Docker - Demo on PHP Application deployment
Docker - Demo on PHP Application deployment
 

Semelhante a Criando Daemons em PHP

Workshop Python para Android
Workshop Python para AndroidWorkshop Python para Android
Workshop Python para AndroidRafael Sanches
 
Como migrar seu ambiente de desenvolvimento para Linux
Como migrar seu ambiente de desenvolvimento para LinuxComo migrar seu ambiente de desenvolvimento para Linux
Como migrar seu ambiente de desenvolvimento para LinuxMarcelo Sabadini
 
Swift na linha de comando
Swift na linha de comandoSwift na linha de comando
Swift na linha de comandoTales Andrade
 
Integração de Sistemas usando tecnologias open source
Integração de Sistemas usando tecnologias open sourceIntegração de Sistemas usando tecnologias open source
Integração de Sistemas usando tecnologias open sourceTiago Peczenyj
 
Deploy automático em projeto PHP - PHPSPIMA 2016
Deploy automático em projeto PHP - PHPSPIMA 2016Deploy automático em projeto PHP - PHPSPIMA 2016
Deploy automático em projeto PHP - PHPSPIMA 2016Felipe Klerk Signorini
 
JS Experience 2017 - Utilizando a virtualização para simplificar o desenvolvi...
JS Experience 2017 - Utilizando a virtualização para simplificar o desenvolvi...JS Experience 2017 - Utilizando a virtualização para simplificar o desenvolvi...
JS Experience 2017 - Utilizando a virtualização para simplificar o desenvolvi...iMasters
 
Introdução ao Python & Web Services
Introdução ao Python & Web ServicesIntrodução ao Python & Web Services
Introdução ao Python & Web ServicesDorneles Treméa
 
Testes de unidade e TDD SoLiSC 2011
Testes de unidade e TDD SoLiSC 2011Testes de unidade e TDD SoLiSC 2011
Testes de unidade e TDD SoLiSC 2011Luís Cobucci
 
OpenShift: NoSQL "a la carte" num PaaS 100% Open Source
OpenShift: NoSQL  "a la carte"  num PaaS 100% Open SourceOpenShift: NoSQL  "a la carte"  num PaaS 100% Open Source
OpenShift: NoSQL "a la carte" num PaaS 100% Open SourceEdgar Silva
 
Qualidade em projetos PHP - SoLiSC 2011
Qualidade em projetos PHP - SoLiSC 2011Qualidade em projetos PHP - SoLiSC 2011
Qualidade em projetos PHP - SoLiSC 2011Luís Cobucci
 
Qualidade em projetos PHP - PHPSC Conf 2011
Qualidade em projetos PHP - PHPSC Conf 2011Qualidade em projetos PHP - PHPSC Conf 2011
Qualidade em projetos PHP - PHPSC Conf 2011Luís Cobucci
 
Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas ( Versão Segi...
 Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas ( Versão Segi... Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas ( Versão Segi...
Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas ( Versão Segi...Alexandro Silva
 
Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas
Proteja sua Hovercraft: Mantendo sua nave livre dos SentinelasProteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas
Proteja sua Hovercraft: Mantendo sua nave livre dos SentinelasSegInfo
 
Iccyber2012 sandro suffert apura - jacomo picolini teamcymru - desafio fore...
Iccyber2012   sandro suffert apura - jacomo picolini teamcymru - desafio fore...Iccyber2012   sandro suffert apura - jacomo picolini teamcymru - desafio fore...
Iccyber2012 sandro suffert apura - jacomo picolini teamcymru - desafio fore...Sandro Suffert
 
Node VM and ChildProcess: Executando códigos não confiáveis no seu servidor
Node VM and ChildProcess: Executando códigos não confiáveis no seu servidorNode VM and ChildProcess: Executando códigos não confiáveis no seu servidor
Node VM and ChildProcess: Executando códigos não confiáveis no seu servidortdc-globalcode
 

Semelhante a Criando Daemons em PHP (20)

Unix Process
Unix ProcessUnix Process
Unix Process
 
Puppet webcast 4linux
Puppet webcast 4linuxPuppet webcast 4linux
Puppet webcast 4linux
 
Workshop Python para Android
Workshop Python para AndroidWorkshop Python para Android
Workshop Python para Android
 
Como migrar seu ambiente de desenvolvimento para Linux
Como migrar seu ambiente de desenvolvimento para LinuxComo migrar seu ambiente de desenvolvimento para Linux
Como migrar seu ambiente de desenvolvimento para Linux
 
Swift na linha de comando
Swift na linha de comandoSwift na linha de comando
Swift na linha de comando
 
Integração de Sistemas usando tecnologias open source
Integração de Sistemas usando tecnologias open sourceIntegração de Sistemas usando tecnologias open source
Integração de Sistemas usando tecnologias open source
 
Git
GitGit
Git
 
Deploy automático em projeto PHP - PHPSPIMA 2016
Deploy automático em projeto PHP - PHPSPIMA 2016Deploy automático em projeto PHP - PHPSPIMA 2016
Deploy automático em projeto PHP - PHPSPIMA 2016
 
JS Experience 2017 - Utilizando a virtualização para simplificar o desenvolvi...
JS Experience 2017 - Utilizando a virtualização para simplificar o desenvolvi...JS Experience 2017 - Utilizando a virtualização para simplificar o desenvolvi...
JS Experience 2017 - Utilizando a virtualização para simplificar o desenvolvi...
 
Introdução ao Python & Web Services
Introdução ao Python & Web ServicesIntrodução ao Python & Web Services
Introdução ao Python & Web Services
 
Testes de unidade e TDD SoLiSC 2011
Testes de unidade e TDD SoLiSC 2011Testes de unidade e TDD SoLiSC 2011
Testes de unidade e TDD SoLiSC 2011
 
OpenShift: NoSQL "a la carte" num PaaS 100% Open Source
OpenShift: NoSQL  "a la carte"  num PaaS 100% Open SourceOpenShift: NoSQL  "a la carte"  num PaaS 100% Open Source
OpenShift: NoSQL "a la carte" num PaaS 100% Open Source
 
Qualidade em projetos PHP - SoLiSC 2011
Qualidade em projetos PHP - SoLiSC 2011Qualidade em projetos PHP - SoLiSC 2011
Qualidade em projetos PHP - SoLiSC 2011
 
Qualidade em projetos PHP - PHPSC Conf 2011
Qualidade em projetos PHP - PHPSC Conf 2011Qualidade em projetos PHP - PHPSC Conf 2011
Qualidade em projetos PHP - PHPSC Conf 2011
 
Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas ( Versão Segi...
 Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas ( Versão Segi... Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas ( Versão Segi...
Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas ( Versão Segi...
 
Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas
Proteja sua Hovercraft: Mantendo sua nave livre dos SentinelasProteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas
Proteja sua Hovercraft: Mantendo sua nave livre dos Sentinelas
 
Forense Computacional com Software Livre
Forense Computacional com Software LivreForense Computacional com Software Livre
Forense Computacional com Software Livre
 
Iccyber2012 sandro suffert apura - jacomo picolini teamcymru - desafio fore...
Iccyber2012   sandro suffert apura - jacomo picolini teamcymru - desafio fore...Iccyber2012   sandro suffert apura - jacomo picolini teamcymru - desafio fore...
Iccyber2012 sandro suffert apura - jacomo picolini teamcymru - desafio fore...
 
Processos (Linux)
Processos (Linux)Processos (Linux)
Processos (Linux)
 
Node VM and ChildProcess: Executando códigos não confiáveis no seu servidor
Node VM and ChildProcess: Executando códigos não confiáveis no seu servidorNode VM and ChildProcess: Executando códigos não confiáveis no seu servidor
Node VM and ChildProcess: Executando códigos não confiáveis no seu servidor
 

Criando Daemons em PHP

  • 1. PHP e seus demônios CRIANDO  DAEMONS  EM  PHP
  • 3. 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
  • 5. PHP  e  seus  demônios • • • • • • Forks   Sinais   Daemons   Spawn   Zombies   IPC 5
  • 7. • 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
  • 8. 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
  • 9. 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
  • 10. 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
  • 11. 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
  • 12. 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
  • 14. • 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
  • 15. Lista  de  constantes  de  sinais  do  PHP • SIGABRT • SIGIOT • SIGTTIN • SIGALRM • SIGKILL • SIGTTOU • SIGBABY • SIGPIPE • SIGURG • SIGBUS • SIGPROF • SIGUSR1 • SIGCHLD • SIGQUIT • SIGUSR2 • SIGCONT • SIGSEGV • SIGVTALRM • SIGFPE • SIGSTOP • SIGWINCH • SIGHUP • SIGSYS • SIGXCPU • SIGILL • SIGTERM • SIGXFSZ • SIGINT • SIGTRAP • SIGIO • SIGTSTP 15
  • 16. 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
  • 17. 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
  • 18. 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 ignorado pcntl_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
  • 20. • 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
  • 22. 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
  • 23. 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
  • 24. 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
  • 25. 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
  • 26. 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
  • 27. 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
  • 28. 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
  • 29. 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
  • 30. 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
  • 31. 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
  • 32. 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
  • 33. 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
  • 34. 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
  • 35. pidfile • Contém  o  PID  do  daemon   • Impede  que  o  daemon  seja  executado  mais  de   uma  vez 35
  • 37. 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
  • 39. • 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
  • 40. 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
  • 42. • 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
  • 43. 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
  • 45. • 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
  • 46. 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
  • 47. 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
  • 48. 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
  • 49. 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
  • 50. 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
  • 51. 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
  • 52. 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
  • 53. Par  de  sockets • Dois  sockets  conectados  armazenados  em  um   array   • Conexão  de  duas  vias,  as  mensagens  são   entregues  no  mesmo  instante 53
  • 54. 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
  • 55. Outras  formas • • • • • • • • APC   Memcached   MongoDB   MySQL   RabbitMQ   Redis   SQLite   … 55
  • 57. • 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
  • 59. • AraraProcess  (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
  • 62. 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
  • 63. 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