Otimizando o PHP-FPM para alto desempenho

O PHP está em toda parte e é sem dúvida a linguagem mais amplamente implantada na Internet.


No entanto, não é exatamente conhecido por seus recursos de alto desempenho, especialmente quando se trata de sistemas altamente concorrentes. E é por isso que, para casos de uso especializados, idiomas como Node (sim, eu sei, não é um idioma), Go e Elixir estão assumindo.

Dito isto, há MUITO que você pode fazer para melhorar o desempenho do PHP no seu servidor. Este artigo se concentra no lado das coisas php-fpm, que é a maneira natural de configurar no seu servidor se você estiver usando o Nginx.

Caso você saiba o que é php-fpm, sinta-se à vontade para pular para a seção sobre otimização.

O que é php-fpm?

Muitos desenvolvedores não estão interessados ​​no DevOps lado das coisas, e mesmo entre os que sabem, muito poucos sabem o que está acontecendo sob o capô. Curiosamente, quando o navegador envia uma solicitação para um servidor executando PHP, não é o PHP que forma o ponto do primeiro contato; em vez disso, é o servidor HTTP, sendo os principais o Apache e o Nginx. Esses “servidores da web” precisam decidir como se conectar ao PHP e passar o tipo de solicitação, dados e cabeçalhos para ele..

O ciclo de solicitação-resposta no caso do PHP (crédito de imagem: ProinerTech)

Nos aplicativos PHP modernos, a parte “find file” acima é o index.php, no qual o servidor está configurado para delegar todas as solicitações para.

Agora, como o servidor da Web se conecta exatamente ao PHP evoluiu, e este artigo explodiria em comprimento se quiséssemos entrar no âmago da questão. Mas, grosso modo, durante o tempo em que o Apache dominou como o servidor web preferido, o PHP foi um módulo incluído dentro do servidor.

Portanto, sempre que uma solicitação fosse recebida, o servidor iniciaria um novo processo, que incluirá automaticamente o PHP, e a executará. Este método foi chamado mod_php, abreviação de “php as module”. Essa abordagem tinha suas limitações, que o Nginx superou com php-fpm.

No php-fpm, a responsabilidade de gerenciar o PHP, os processos estão no programa PHP dentro do servidor. Em outras palavras, o servidor da Web (Nginx, no nosso caso) não se importa com a localização e o carregamento do PHP, desde que ele saiba como enviar e receber dados dele. Se desejar, você pode pensar no PHP nesse caso como outro servidor em si, que gerencia alguns processos filhos do PHP para solicitações recebidas (portanto, temos a solicitação para chegar a um servidor, que foi recebido por um servidor e repassado para um servidor – muito louco! :-P).

Se você fez alguma configuração do Nginx, ou até mesmo se meteu nelas, encontrará algo assim:

localização ~ \ .php $ {
try_files $ uri = 404;
fastcgi_split_path_info ^ (. + \. php) (/.+) $;
fastcgi_pass unix: /run/php/php7.2-fpm.sock;
fastcgi_index index.php;
inclua fastcgi_params;
fastcgi_param SCRIPT_FILENAME $ document_root $ fastcgi_script_name;
}

A linha na qual estamos interessados ​​é: fastcgi_pass unix: /run/php/php7.2-fpm.sock ;, que instrui o Nginx a se comunicar com o processo PHP através do soquete chamado php7.2-fpm.sock. Portanto, para cada solicitação recebida, o Nginx grava dados nesse arquivo e, ao receber a saída, envia de volta ao navegador.

Mais uma vez, devo enfatizar que essa não é a imagem mais completa ou precisa do que acontece, mas é totalmente precisa para a maioria das tarefas do DevOps.

Com isso de lado, vamos recapitular o que aprendemos até agora:

  • O PHP não recebe solicitações enviadas diretamente pelos navegadores. Servidores da Web como o Nginx primeiro interceptam esses.
  • O servidor web sabe como se conectar ao processo PHP e transmite todos os dados da solicitação (literalmente cola tudo) para o PHP.
  • Quando o PHP termina sua parte, ele envia a resposta de volta ao servidor da Web, que a envia de volta ao cliente (ou navegador, na maioria dos casos).

Ou graficamente:

Como PHP e Nginx funcionam juntos (Crédito de imagem: DataDog)

Ótimo até agora, mas agora vem a pergunta de um milhão de dólares: o que exatamente é o PHP-FPM?

A parte “FPM” no PHP significa “Fast Process Manager”, que é apenas uma maneira elegante de dizer que o PHP executado em um servidor não é um processo único, mas sim alguns processos PHP gerados, controlados e eliminados desativado por esse gerente de processo do FPM. É nesse gerenciador de processos que o servidor da web passa as solicitações para.

O PHP-FPM é um buraco de coelho inteiro em si, portanto, fique à vontade para explorar se desejar, mas, para nossos propósitos, essa explicação será suficiente. ��

Por que otimizar php-fpm?

Então, por que se preocupar com toda essa dança quando as coisas estão funcionando bem? Por que não deixar as coisas como estão.

Ironicamente, esse é precisamente o conselho que dou para a maioria dos casos de uso. Se sua configuração estiver funcionando bem e não tiver casos de uso extraordinários, use os padrões. No entanto, se você deseja expandir além de uma única máquina, é essencial espremer o máximo de uma, pois isso pode reduzir as contas do servidor pela metade (ou até mais!).

Outra coisa a perceber é que o Nginx foi criado para lidar com grandes cargas de trabalho. Ele é capaz de lidar com milhares de conexões ao mesmo tempo, mas se o mesmo não acontecer com a configuração do PHP, você desperdiçará recursos, pois o Nginx terá que esperar o PHP concluir o processo atual e aceitar o Em seguida, negativamente conclusivas quaisquer vantagens que o Nginx foi construído para fornecer!

Então, com isso fora do caminho, vamos ver exatamente o que mudaríamos ao tentar otimizar php-fpm.

Como otimizar o PHP-FPM?

O local do arquivo de configuração para php-fpm pode ser diferente no servidor, portanto, você precisará pesquisar para localizá-lo. Você pode usar o comando find se estiver no UNIX. No meu Ubuntu, o caminho é /etc/php/7.2/fpm/php-fpm.conf. O 7.2 é, obviamente, a versão do PHP que estou executando.

Veja como são as primeiras linhas deste arquivo:

;;;;;;;;;;;;;;;;;;;;;;
; Configuração de FPM;
;;;;;;;;;;;;;;;;;;;;;;

; Todos os caminhos relativos neste arquivo de configuração são relativos à instalação do PHP
; prefixo (/ usr). Esse prefixo pode ser alterado dinamicamente usando o método
; argumento ‘-p’ na linha de comando.

;;;;;;;;;;;;;;;;;;
; Opções Globais;
;;;;;;;;;;;;;;;;;;

[global]
; Arquivo Pid
; Nota: o prefixo padrão é / var
; Valor padrão: nenhum
pid = /run/php/php7.2-fpm.pid

; Arquivo de log de erro
; Se estiver definido como "syslog", log é enviado para syslogd em vez de ser gravado
; em um arquivo local.
; Nota: o prefixo padrão é / var
; Valor padrão: log / php-fpm.log
error_log = /var/log/php7.2-fpm.log

Algumas coisas devem ser imediatamente óbvias: a linha pid = /run/php/php7.2-fpm.pid nos diz qual arquivo contém o ID do processo do php-fpm.

Também vemos que /var/log/php7.2-fpm.log é onde o php-fpm armazenará seus logs.

Dentro deste arquivo, adicione mais três variáveis ​​como esta:

emergency_restart_threshold 10
emergency_restart_interval 1m
process_control_timeout 10s

As duas primeiras configurações são cautelares e informam ao processo php-fpm que, se dez processos filhos falharem em um minuto, o processo principal do php-fpm deve ser reiniciado automaticamente.

Isso pode não parecer robusto, mas o PHP é um processo de curta duração que vaza memória; portanto, reiniciar o processo principal em casos de alta falha pode resolver muitos problemas.

A terceira opção, process_control_timeout, diz ao processo filho que aguarde tanto tempo antes de executar o sinal recebido do processo pai. Isso é útil nos casos em que os processos filhos estão no meio de algo quando os processos pais enviam um sinal KILL, por exemplo. Com dez segundos em mãos, eles terão mais chances de concluir suas tarefas e sair graciosamente.

Surpreendentemente, essa não é a carne da configuração php-fpm! Isso porque, para atender solicitações da Web, o php-fpm cria um novo conjunto de processos, que terá uma configuração separada. No meu caso, o nome do pool acabou sendo www e o arquivo que eu queria editar era /etc/php/7.2/fpm/pool.d/www.conf.

Vamos ver como esse arquivo começa:

; Inicie um novo pool chamado ‘www’.
; a variável $ pool pode ser usada em qualquer diretiva e será substituída pelo
; nome do pool (‘www’ aqui)
[www]

; Por prefixo de pool
; Aplica-se apenas às seguintes diretivas:
; – ‘access.log’
; – ‘slowlog’
; – ‘ouvir’ (unixsocket)
; – ‘chroot’
; – ‘chdir’
; – ‘php_values’
; – ‘php_admin_values’
; Quando não definido, o prefixo global (ou / usr) se aplica.
; Nota: Esta diretiva também pode ser relativa ao prefixo global.
; Valor padrão: nenhum
; prefixo = / caminho / para / pools / $ pool

; Usuário / grupo de processos Unix
; Nota: O usuário é obrigatório. Se o grupo não estiver definido, o grupo de usuários padrão
; será usado.
usuário = www-data
group = www-data

Uma rápida olhada no final do snippet acima resolve o enigma do motivo pelo qual o processo do servidor é executado como www-data. Se você se deparar com problemas de permissão de arquivo ao configurar seu site, provavelmente alterou o proprietário ou o grupo do diretório para www-data, permitindo que o processo PHP possa gravar em arquivos de log e fazer upload de documentos, etc..

Finalmente, chegamos à fonte do problema, a configuração do gerenciador de processos (pm). Geralmente, você vê os padrões da seguinte forma:

pm = dinâmico
pm.max_children = 5
pm.start_servers = 3
pm.min_spare_servers = 2
pm.max_spare_servers = 4
pm.max_requests = 200

Então, o que “dinâmicoAqui significa? Acho que os documentos oficiais melhor explicam isso (quer dizer, isso já deve fazer parte do arquivo que você está editando, mas eu o reproduzi aqui apenas no caso de não estar):

; Escolha como o gerente de processos controlará o número de processos filhos.
; Valores possíveis:
; static – um número fixo (pm.max_children) de processos filhos;
; dinâmico – o número de processos filhos é definido dinamicamente com base no
; seguintes diretrizes. Com esse gerenciamento de processos, haverá
; sempre pelo menos 1 filho.
; pm.max_children – o número máximo de filhos que podem
; estar vivo ao mesmo tempo.
; pm.start_servers – o número de filhos criados na inicialização.
; pm.min_spare_servers – o número mínimo de filhos em ‘inativo’
; estado (aguardando para processar). Se o número
; processos ‘inativos’ é menor que isso
; número, em seguida, algumas crianças serão criadas.
; pm.max_spare_servers – o número máximo de filhos em ‘inativo’
; estado (aguardando para processar). Se o número
; processos ‘inativos’ é maior que isso
; número, então algumas crianças serão mortas.
; ondemand – nenhum filho é criado na inicialização. As crianças serão bifurcadas quando
; novos pedidos serão conectados. O seguinte parâmetro é usado:
; pm.max_children – o número máximo de filhos que
; pode estar vivo ao mesmo tempo.
; pm.process_idle_timeout – o número de segundos após o qual
; um processo ocioso será morto.
; Nota: Este valor é obrigatório.

Então, vemos que existem três valores possíveis:

  • Estático: Um número fixo de processos PHP será mantido, não importa o que.
  • Dinâmico: Especificamos o número mínimo e máximo de processos que o php-fpm manterá ativo a qualquer momento.
  • sob demanda: Processos são criados e destruídos, bem, sob demanda.

Então, como essas configurações são importantes?

Em termos simples, se você tem um site com pouco tráfego, a configuração “dinâmica” é um desperdício de recursos na maioria das vezes. Supondo que você tenha pm.min_spare_servers definido como 3, três processos PHP serão criados e mantidos, mesmo quando não houver tráfego no site. Nesses casos, “ondemand” é uma opção melhor, permitindo que o sistema decida quando iniciar novos processos.

Por outro lado, os sites que lidam com grandes quantidades de tráfego ou precisam responder rapidamente serão punidos nessa configuração. Criar um novo processo PHP, torná-lo parte de um pool e monitorá-lo, é uma sobrecarga extra que é melhor evitar.

O uso de pm = static corrige o número de processos filhos, permitindo que o máximo de recursos do sistema seja usado para atender às solicitações, em vez de gerenciar o PHP. Se você seguir esta rota, tenha cuidado com as diretrizes e armadilhas. Um artigo bastante denso, mas altamente útil, é aqui.

Palavras finais

Como os artigos sobre desempenho na Web podem desencadear guerras ou servir para confundir as pessoas, sinto que algumas palavras estão em ordem antes de encerrarmos este artigo. O ajuste de desempenho envolve tanto adivinhação e artes das trevas quanto conhecimento do sistema.

Mesmo se você conhece todas as configurações de php-fpm de cor, o sucesso não é garantido. Se você não tinha idéia da existência de php-fpm, não precisa perder tempo se preocupando com isso. Continue fazendo o que você já está fazendo e continue.

Ao mesmo tempo, evite o fim de ser um viciado em desempenho. Sim, você pode obter um desempenho ainda melhor recompilando o PHP do zero e removendo todos os módulos que não usará, mas essa abordagem não é sensata o suficiente em ambientes de produção. A idéia de otimizar algo é examinar se suas necessidades diferem dos padrões (o que raramente fazem!) E fazer pequenas alterações, conforme necessário.

Se você não estiver pronto para gastar tempo otimizando seus servidores PHP, considere aproveitar uma plataforma confiável como Kinsta que cuidam da otimização e segurança do desempenho.

Jeffrey Wilson Administrator
Sorry! The Author has not filled his profile.
follow me
    Like this post? Please share to your friends:
    Adblock
    detector
    map