Neste post vou exemplificar os passos para configurar um Webserver que consome poucos recursos e é extremamente rápido no Debian Lenny.
PHP-FPM: é um gerenciador de processos CGI do php, similar ao Phpcgi, porém com várias vantagens como:
- Gerenciador de Processos muito eficiente, com capacidade de parar e iniciar seus deamons caso necessário
- Possibilidade de Iniciar processos com usuários diferentes e com arquivos php.ini diferentes
- Uploads otimizados
- Capacidade de reinicializar processos caso ocorra algum problema
- Escalabilidade de processos, ele pode criar mais processos de acordo com a demanda
- e muito mais.
XCache: é um gerenciador de cache, que armazena os scripts php em opcode para uso futuro, é extremamente rápido e muito usado no mundo em servidores com alta demanda.
Nginx: Conheci este webserver lendo o blog da boo-box, ele é um Servidor web e proxy reverso extremamente veloz e que vem ganhando mercado nos últimos meses devido a sua facilidade de uso e capacidade de carga.
Para agilizar a configuração, vamos usar alguns pacotes (php5.3, php-fpm) pré compilados e mantidos www.dotdeb.org. os testes que eu realzei usando estes pacotes tiveram um ganho de performance enorme.
Instalação:
Vamos começar adicionado os repositórios do dotdeb no /etc/apt/sources.list:
deb http://php53.dotdeb.org stable all deb-src http://php53.dotdeb.org stable all
Vamos instalar os pacotes e algumas dependências para o nginx:
aptitude update aptitude install php5-fpm php5-xcache php5-gd php5-curl \ php5-mysql php5-pgsql libssl-dev libpcre3-dev build-essential -y
Agora temos o php instalado, vamos compilar o nginx:
cd mkdir src cd src wget http://nginx.org/download/nginx-0.7.64.tar.gz tar -zxvf nginx-0.7.64.tar.gz cd nginx-0.7.64 ./configure --prefix=/usr/local/nginx --user=www-data --group=www-data \ --without-mail_pop3_module --without-mail_imap_module \ --without-mail_smtp_module --with-http_stub_status_module \ --with-http_ssl_module --http-log-path=/var/log/nginx/access.log \ --conf-path=/etc/nginx/nginx.conf --pid-path=/var/run/nginx.pid make make install
Se tudo ocorreu bem, você já tem o nginx instalado, vamos apenas coloca-lo para inicializar automáticamente, crie o arquivo /etc/init.d/nginx e coloque o conteúdo:
#! /bin/sh ### BEGIN INIT INFO # Provides: nginx # Required-Start: $all # Required-Stop: $all # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts the nginx web server # Description: starts nginx using start-stop-daemon ### END INIT INFO PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/local DAEMON=/usr/local/nginx/sbin/nginx NAME=nginx DESC=nginx test -x $DAEMON || exit 0 # Include nginx defaults if available if [ -f /etc/default/nginx ] ; then . /etc/default/nginx fi set -e case "$1" in start) echo -n "Starting $DESC: " start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON -- $DAEMON_OPTS || true echo "$NAME." ;; stop) echo -n "Stopping $DESC: " start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON || true echo "$NAME." ;; restart|force-reload) echo -n "Restarting $DESC: " start-stop-daemon --stop --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON || true sleep 1 start-stop-daemon --start --quiet --pidfile \ /var/run/$NAME.pid --exec $DAEMON -- $DAEMON_OPTS || true echo "$NAME." ;; reload) echo -n "Reloading $DESC configuration: " start-stop-daemon --stop --signal HUP --quiet --pidfile /var/run/$NAME.pid \ --exec $DAEMON || true echo "$NAME." ;; configtest) echo -n "Testing $DESC configuration: " if nginx -t > /dev/null >&1 then echo "$NAME." else exit $? fi ;; *) echo "Usage: $NAME {start|stop|restart|reload|force-reload|configtest}" >&2 exit 1 ;; esac exit 0
depois vamos torna-lo executável e atualizar o rc.d:
chmod +x /etc/init.d/nginx update-rc.d nginx defaults
Com isso o processo de instalação está concluído, vamos configurar!
Configuração do XCache
Coloque a seguinte configuração no arquivo /etc/php5/fpm/conf.d/xcache.ini:
; configuration for php xcache module extension=xcache.so [xcache.admin] xcache.admin.user = "secom" ; xcache.admin.pass = md5($your_password) xcache.admin.pass = "" [xcache] ; ini only settings, all the values here is default unless explained ; select low level shm/allocator scheme implemenation xcache.shm_scheme = "mmap" ; to disable: xcache.size=0 ; to enable : xcache.size=64M etc (any size > 0) and your system mmap allows xcache.size = 64M ; set to cpu count (cat /proc/cpuinfo |grep -c processor) xcache.count = 1 ; just a hash hints, you can always store count(items) > slots xcache.slots = 8K ; ttl of the cache item, 0=forever xcache.ttl = 0 ; interval of gc scanning expired items, 0=no scan, other values is in seconds xcache.gc_interval = 0 ; same as aboves but for variable cache xcache.var_size = 64M xcache.var_count = 1 xcache.var_slots = 8K ; default ttl xcache.var_ttl = 0 xcache.var_maxttl = 0 xcache.var_gc_interval = 300 xcache.test = Off ; N/A for /dev/zero xcache.readonly_protection = Off ; for *nix, xcache.mmap_path is a file path, not directory. ; Use something like "/tmp/xcache" if you want to turn on ReadonlyProtection ; 2 group of php won't share the same /tmp/xcache ; for win32, xcache.mmap_path=anonymous map name, not file path xcache.mmap_path = "/dev/zero" ; leave it blank(disabled) or "/tmp/phpcore/" ; make sure it's writable by php (without checking open_basedir) xcache.coredump_directory = "" ; per request settings xcache.cacher = On xcache.stat = On xcache.optimizer = On [xcache.coverager] ; per request settings ; enable coverage data collecting for xcache.coveragedump_directory and xcache_coverager_start/stop/get/clean() functions (will hurt executing performance) xcache.coverager = Off ; ini only settings ; make sure it's readable (care open_basedir) by coverage viewer script ; requires xcache.coverager=On xcache.coveragedump_directory = ""
Configuração do Nginx
Edite o arquivo em /etc/nginx/nginx.conf:
user www-data; #Coloque quantos processos simultaneos, o ideal é um para cada nucleo do sistema: worker_processes 4; error_log /var/log/nginx/error.log; events { # numero de conexões simultaneas por worker worker_connections 1024; } http { include mime.types; default_type application/octet-stream; access_log /var/log/nginx/access.log; sendfile on; # isso é interessante, dá um ganho enorme na navegação, e o nginx aguenta tranquilamente keepalive_timeout 60; tcp_nodelay on; ## Compressão gzip on; gzip_http_version 1.0; gzip_comp_level 2; gzip_proxied any; gzip_min_length 1100; gzip_buffers 16 8k; # mime types para zipar e adicionar header de cache gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript image/gif image/jpeg image/png; # Desabilita compressão em algumas versões do IE6 gzip_disable "MSIE [1-6].(?!.*SV1)"; # Impede que servidores proxy mandem versões em gzip do arquivo para os IE6 gzip_vary on; server { root /var/www/; server_name localhost; listen 80; location / { index index.php index.html index.htm; } #error_page 404 /404.html; # redirect server error pages to the static page /50x.html error_page 500 502 503 504 /50x.html; location = /50x.html { root /var/www/nginx-default; } # Joga requisições para arquivos .php para o php-fpm location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi_params; fastcgi_param SCRIPT_FILENAME /var/www/$fastcgi_script_name; fastcgi_param SERVER_NAME $http_host; fastcgi_ignore_client_abort on; } } }
Configuração do php-fpm
Edite o arquivo: /etc/php5/fpm/php5-fpm.conf e faça os ajustes que você achar interessante, aqui eu só aumento os max_childrens (Numero de clientes CGI) de 5 para 50, esta configuração depende do seu hardware.
Configuração do Logrotate
Vamos configurar agora o logrotate para não enchermos os discos com logs do nginx, edite o arquivo /etc/logrotate.d/nginx:
/var/log/nginx/*.log { daily missingok rotate 7 compress delaycompress notifempty create 640 root adm sharedscripts postrotate [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.p$ endscript }
Finalizando
Agora que está tudo configurado, vamos reinicalizar os serviços:
/etc/init.d/php5-fpm restart /etc/init.d/nginx restart
crie um arquivo /var/www/index.php e vamos testar o php:
e acesse: http://ip_do_servidor/

Fala ai Carlos,
você fez alguma comparação de performance entre as soluções padrões (like, apache+php)?
Tem algum gráfico de performance ou algum “vmstat 1″ p/ analisarmos?
Mas foi uma ótima dica ! Obrigado!
Também gostei do passo-a-passo. Porém faltou um comparativo como o Erick citou.
Se der tempo vou testar essa solução em breve.
Estou meio “viciado” em otimização de perfomance em servidores web. Ultimamente tudo que vejo sobre o assunto estou lendo e pesquisando.
Obrigado pela contribuição
Olá,
kra, não fiz nenhum teste localmente, mas pesquisei vários no google e por isso decidi implementar…
o que posso dizer, eh que nosso servidor (Do governo do Tocantins) é um Pentium 4, com 1gb de memória… com o apache ele começava a engasgar com 200 conexões… com o nginx já passou de 1000 conexões! e o uso da maquina não passa de 5%
fiz até um post sobre isso: http://ferrari.eti.br/nginx-webserver-proxy-reverso-e-perfeito/ dá uma conferida
Dá uma navegada nos sites:
http://to.gov.br
[]‘s
Salve,
É Carlos só falta um comparativo entre apache2+php e nginx+php. Com configurações “iguais”, se otimiza em 1, faz o mesmo no outro.
Está bem legal o artigo, valeu pela dica.
Thanks you very much for this tutorial, i was stopped by php-fpm install to make a full great install ! (only install nginx with fastCGI)
olá Carlos. excelente post e blog também !
pergunta básica: nada contra a distro Debian, muito pelo contrário, mas como tenho mais contato com Ubuntu, como você vê a possibilidade de implementação desta configuração em um servidor Ubuntu ?
@Henrique Dias
No Ubuntu não vai mudar muita coisa, aliás, acho que não muda nada visto que a base do Ubuntu é o próprio Debian.
Os pacotes possivelmente serão os mesmos.
@Henrique Dias, @Diego
Pode executar os processos sem nenhuma mudança no Ubuntu Server ou Desktop que funciona sem problemas.
[]‘s
Acabei de instalar e testar a solução proposta e estou impressionado.
Configurei o jMeter pra 2000 threads em 60 segundos e nem fez cócegas no servidor (virtual). Tudo bem que o teste foi acessar a página do PHP Info, mas mesmo assim a performance foi muito boa.
Vou configurar outra máquina virtual de testes para replicar o mesmo ambiente, mas dessa vez com Apache e fazer um teste comparativo.
Carlos, você já testou o Webserver Lighthttpd,
pois estou testando e ele está aguentando o tranco, ou o cherokee -> http://www.cherokee-project.com/
Esse ultimo também está muito rápido, mas prefiro o LIghtHTTPD
benchmark:
http://www.rkblog.rk.edu.pl/w/p/lighttpd-and-cherokee-benchmark/
http://www.rkblog.rk.edu.pl/w/p/pylons-benchmark-various-servers/
Tem outro benchmark Legal, mas eu prefiro o LightHTTPD, pois ele é mais fácil de instalar e configurar.
http://www.alobbs.com/1345/Cherokee_0_8_1_benchmark.html
Pessoal,
Atendendo pedidos, e com ajuda do Ferrari na configuração, fiz um teste real: Apache X Nginx.
Primeiro Server: CentOS+Apache+2core500+1GbRam
Segundo Server: Ubuntu+Nginx+2core300+300MbRam
Quem leva a melhor nessa? façam suas apostas.
Coloquei o mesmo site nos 2 servers, um site de noticias, com MySQL e várias consultas na home. Medi o tempo de execução da home do site nos 2 servidores e peguei os maiores valores depois de algumas tentativas.
Primeiro Server (apache): 0.6 segundos
Segundo Server (nginx): 0.023 segundos
Venceu o Nginx com 2600% de dianteira.
Valeu Ferrari.
Não consigo colocar o Zend Framework pra rodar com o Nginx. É possível? Alguém conseguiu? Ou tenho que fazer proxy com o Apache?
@Diego,
é possivel sim, nunca usei o ZF, mas acredito que ele faz o uso do .htaccess, o htacces é do apache, no caso do nginx vc tem que configurar as rotas no arquivo de configuração, é tão simples quanto o metodo do apache e também é muito mais veloz.
http://wiki.nginx.org/NginxHttpRewriteModule
[]‘s
@caferrari Exatamente, o Zend Framework utiliza o .htaccess. Achei vários blogs com várias configurações diferentes para rodar o ZF no Nginx, porém nenhuma funciona. Estou sem tempo agora mas assim que possível vou verificar a wiki que você indicou. Obrigado.
Eita. Acho que era problema na minha aplicação de testes. Peguei o exemplo do Quickstart http://framework.zend.com/manual/en/learning.quickstart.intro.html
e funcionou.
Grande artigo, estou procurando uma alternativa mais rápida para rodar um sistema desenvolvido em PHP com JS (Ext).
Como uso centos e esse usa o PHP 5.1.6 não tenho muita experiencia no Debia.
Tenho uma duvida, como instalar suporte a MSSQL no PHP5?
Muito obrigado.
Ferrari, obrigado pelo ótimo tutorial. Encontrei esse script para benchmark: http://benchmarks.nickbarrett.org/
E esse site com um comparativo entre PHP-FPM vs Spawn-FCGI vs FastCGI: http://vpsbible.com/php/php-benchmarking-phpfpm-fastcgi-spawnfcgi/
Obrigado pelo comentário @Rogério Madureira
Bom apesar desse seu teste mostrar que o PHP-FPM é mais lento um pouco que as outras soluções, o FPM ainda tem vantagens.. como o spawn automático de threads dependendo da necessidade e os controles internos dele que garantem que seja fail-safe.
[]‘s
Será que eu compreendi errado? havia entendido que o benchmarking havia apontado o PHP-FPM como a solução mais rápida, com tempo médio de 374ms para completar as operações do teste, contra 413ms do SPAWN-FCGI e 461ms do PHP-FASTCGI…
Não.. eu entendi errado mesmo… então pronto.. php-fpm é perfeito.. XD
vlw!