Nota do editor:
É possível configurar uma nova instalação WordPress usando Nginx, FastCGI e HHVM? É, pois. Pode fazer-se? Pode, claro. É fácil? É mais complicado que cozer um ovo e menos complicado que estabelecer acordos entre partidos políticos. Alguém o fez recentemente? Sim, Luís Rodrigues, Solutions Architect & Business Developer, tratou disso. E o melhor de tudo é que aceitou partilhar connosco o método e os resultados.
Sopa de letras: PHP, CGI e HHVM
É certo e sabido que, sem um empurrãozinho, o PHP não é das linguagens de programação com maior desempenho. É uma linguagem interpretada e, como tal, o seu tempo de execução é condicionado pelo desempenho do próprio interpretador e do ecossistema de componentes em volta.
No seu modelo de execução mais simples e convencional, um servidor web recebe um pedido do browser para gerar conteúdo dinâmico a partir de um script PHP. Para satisfazer o pedido, o servidor reencaminha-o para o interpretador da linguagem, que inicia um processo separado, executa o código e devolve o resultado. O servidor, por sua vez, retorna este resultado ao browser do visitante. Através deste método, denominado Common Gateway Interface (CGI), cada pedido implica um novo processo do interpretador PHP para executar o código necessário. Findo o pedido, o processo do interpretador é terminado.
O CGI foi o standard durante muito tempo desde a sua criação em meados da década de 1990, não obstante as suas deficiências arquitecturais: quantos mais pedidos, mais processos ocupam a memória e CPU do sistema. Mais: em situações de sobrecarga, os recursos da máquina esgotam-se em ciclos que nada têm a ver com execução de PHP e prendem-se com a inicialização do interpretador e a comunicação entre processos. Mas essas situações eram raras numa época em que a maioria da web dependia de ficheiros e conteúdos estáticos.
As exigências de processamento e memória das aplicações web modernas obrigaram por isso ao desenvolvimento de melhoramentos e alternativas. Criaram-se extensões, como o mod_php
, que embebem o interpretador da linguagem no servidor, reduzindo os custos de comunicação entre componentes. Também se introduziram compiladores de opcodes e os mais diversos mecanismos decache, como APC ou Varnish, para guardar o resultado dos scripts e evitar a execução repetitiva do mesmo código.
Outra abordagem desenvolvida foi o FastCGI. Semelhante ao CGI, na medida em que a execução do código é independente do servidor web, o protocolo FastCGI centraliza a gestão de processos do interpretador e elimina por completo o overhead que o modelo“um pedido = um processo” acarreta. Em FastCGI, uma única ligação e o mesmo processo PHP podem ser reutilizados para correr inúmeros scripts. A escalabilidade da arquitectura é ainda facilitada pela possibilidade de ter múltiplos servidores FastCGI (em muitas máquinas distintas se necessário).
FastCGI (em especial a implementação PHP-FPM, ou FastCGI Process Manager, com o servidor Nginx) é, à data, o método preferido e recomendado para instalações WordPress de elevado desempenho, também usado no WordPress.com para servir milhões e milhões de pedidos diários.
Apesar de todas as melhorias, que elevaram o desempenho de muitas aplicações em PHP para níveis muito mais satisfatórios, infraestruturas complexas e em constante utilização como a rede social Facebook (também desenvolvida em PHP) continuaram a debater-se com problemas de escalabilidade.
Assim, os engenheiros do Facebook começaram em 2008 a trabalhar no projecto HPHP (ou HipHop), com o intuito de criar um transformador de código PHP em C++. O investimento revelou-se muito proveitoso, e o C++, uma vez compilado, passou a garantir seis vezes o débito da abordagem anterior.
No entanto, este método complicava os processos de depuração de código, além de que cada mexida na aplicação obrigava a recompilar um ficheiro executável com mais de 1 GB.
Para contornar estes problemas, o Facebook aproveitou todo o know-how adquirido com o desenvolvimento do HipHop e cruzou-o com o modelo de máquinas virtuais e compilação Just-In-Time usado em linguagems de programação altamente eficientes como Java ou C#. Assim surgiu o HipHop Virtual Machine, ou HHVM.
O HHVM converte PHP em código intermédio (chamado bytecode) e daí dinamicamente para código máquina, para ser executado ao nível mais baixo do hardware, garantindo o melhor desempenho possível.
Em Dezembro de 2013, o HHVM passou a suportar FastCGI, reduzindo grandemente o atrito à adopção desta tecnologia. Qualquer servidor web configurado para suportar FastCGI (Apache 2 com mod_fastcgi
, Nginx, Lighttpd, etc.) pode agora tirar partido do HHVM, bastando ao administrador ajustar a opção do socket de comunicação.
O WordPress é também suportado, sendo inclusivamente usado no blogue do projecto HHVM e em vários exemplos e comparativos oficiais.
Adiante veremos como, em poucos passos, poderemos configurar uma nova instalação WordPress usando Nginx, FastCGI e HHVM.
Instalação
Os passos aqui descritos para instalação e configuração do WordPress sobre HHVM correspondem ao Ubuntu 13.10 (Saucy Salamander), e podem variar consoante a distribuição Linux.
Os passos para instalação do WordPress em Nginx podem ser obtidos tanto da documentação do Nginx como do Codex, pelo que não me irei alargar sobre a configuração inicial.
Feito isto, será necessário adicionar o repositório do HHVM às fontes do APT, actualizar os pacotes do sistema e instalar ohhvm-fastcgi
:
$ echo deb http://dl.hhvm.com/ubuntu saucy main | sudo tee /etc/apt/sources.list.d/hhvm.list
$ sudo apt-get update
$ sudo apt-get install hhvm-fastcgi
Por fim, procederemos à sua integração com o Nginx. Caso esteja configurado para usar php5-fpm
, seguindo as instruções na documentação oficial, as alterações serão mínimas. Apenas é necessário garantir que o contexto server
relativo ao nosso siteWordPress na configuração do Nginx contém algo do género:
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_keep_conn on;
# De momento, o HHVM suporta apenas comunicação via sockets TCP:
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi_params;
}
Recordo que sempre que as configurações do Nginx ou do HHVM forem alteradas, é necessário reiniciar os servidores com:
$ sudo service nginx restart
$ sudo service hhvm-fastcgi restart
Comparativo
Os seguintes testes foram executados com o ab
sobre uma máquina virtual com 2 cores e 2 GB de RAM, e uma configuração intocada do Nginx tal como instalado no Ubuntu (excepto para configurar o HHVM).
Para cada situação, o ab
foi invocado para um total de 2000 pedidos, com 50 pedidos em concorrência:
$ ab -c 50 -n 2000 http://wordpress.local/
PHP-FPM vs HHVM (sem cache de FastCGI)
Os benefícios do HHVM são mais vincados quando a cache do FastCGI se encontra desligada. Uma vez que a cache reduz ou elimina a necessidade de executar código PHP, não estaríamos efectivamente a comparar o desempenho dos motores de execução.
Assim sendo, os resultados do ab
nas condições acima indicadas para PHP-FPM e HHVM foram:
PHP-FPM | HHVM (1.ª vez) | HHVM (seguintes) | |
---|---|---|---|
Requests per second (mean) | 58.45 | 80.90 | 127.33 |
Time per request (ms, mean) | 855.502 | 618.014 | 392.693 |
Time per request (ms, mean across all) | 17.110 | 12.360 | 7.854 |
Transfer rate (Kbytes/sec) | 666.30 | 921.08 | 1449.58 |
Os testes com HHVM foram executados duas vezes para melhor comparar o desempenho antes e depois da compilação do PHP embytecode.
PHP-FPM vs HHVM (com cache de FastCGI)
Para a segunda ronda de testes comparativos, configurei a cache do FastCGI de forma semelhante à recomendada pela rtCamp. Apenas usei as directivas relacionadas com a cache do FastCGI e nenhuma outra. (Também não houve qualquer optimização adicional do número de processos e ligações do Nginx, tempos de keep-alive ou alterações ao limite de file descriptors usados.)
Como esperado, as diferenças entre os vários métodos esbatem-se, embora o HHVM continue a liderar os resultados:
PHP-FPM | HHVM (1.ª vez) | HHVM (seguintes) | |
---|---|---|---|
Requests per second (mean) | 3418.66 | 3701.06 | 4241.91 |
Time per request (ms, mean) | 14.626 | 13.510 | 11.787 |
Time per request (ms, mean across all) | 0.293 | 0.270 | 0.236 |
Transfer rate (Kbytes/sec) | 26023.86 | 28173.58 | 32290.69 |
Production-ready?
A tecnologia promete, mas como em tudo o que é bleeding edge, é ainda prematuro recomendar o HHVM para sistemas de produção. Embora todo o site do Facebook corra actualmente sobre HHVM, os desenvolvimentos não estão terminados e a compatibilidade com a miríade de produtos e frameworks PHP no mercado ainda não atingiu os 100% (mas para lá caminha).
Os ganhos também são limitados face aos que se podem obter com a correcta configuração da cache do FastCGI. O HHVM não se justifica, por isso, para sites maioritariamente de leitura, e que não contem com muitos visitantes autenticados. Poderá, no entanto, ser equacionado para situações em que as caches sejam frequentemente invalidadas devido às interacções dos utilizadores (como fóruns de discussão ou redes sociais).
De notar ainda que, à data, a única forma de comunicar com o servidor FastCGI do HHVM é através de sockets TCP. Este método é bastante menos eficiente do que com comunicação através de sockets Unix, e será de esperar um salto considerável no desempenho mal o método seja introduzido.
Finalmente, o HHVM está disponível apenas para ambientes de 64 bits, e não se prevê que venha a suportar outra coisa.
Já se aventuraram com o WordPress em HHVM? O que têm a dizer? Partilhem a vossa experiência no espaço de comentários.
Wow! Obrigado Luís Rodrigues. Confesso que estou muito aquém do tema mas gostei imenso da análise, clareza e forma.
o código na shell está a precisar de uma maozinha 😉 delete this please
@pedrocarvalho: Um ligeiro atrofio com o Markdown, penso estar corrigido agora. Obrigado!