Otimizacao de websites em PHP

Post on 18-Nov-2014

8.225 views 2 download

description

Slides do workshop apresentado por mim, Felipe Ribeiro, na PHPConference 2009

Transcript of Otimizacao de websites em PHP

OTIMIZANDO A PERFORMANCE DE WEBSITES

EM PHP

FELIPE RIBEIRO

• Graduando (concluinte) em Ciência da Computação na UFCG

• Zend Certified Engineer - PHP5

• Trabalha como desenvolvedor Web e consultor com foco em performance e escalabilidade de Websites

• Experiência em grids computacionais e sistemas distribuídos

• Membro fundador do grupo PHP-PB

• Contribuidor do PHP e Mozilla Camino

OBJETIVO

• O objetivo desse mini-curso é apresentar alguns dos conceitos utilizados na otimização da performance e escalabilidade de web sites

• A abordagem utilizada será bottom-up, ou seja, iniciaremos de ajustes no servidor e back-end, para depois ajustarmos o front-end

• Em aplicações práticas, essa abordagem depende do problema.

• Quem está “sofrendo” mais? Servidor ou cliente?

Performance

a habilidade que uma aplicação tem de atingir um objetivo, como por exemplo responder no menor tempo possível

Escalabilidade

a habilidade de uma aplicação manter a performance quando a carga de trabalho aumenta.

PHP não é tão rápido...

Porém sua arquitetura shared-nothing simplifica a

escalabilidade

E PHP dificilmente é o gargalo

A maior parte do tempo é gasto no

banco de dados ou com o carregamento

do front-end

Sempre dá para espremer e melhorar

“OTIMIZAÇÃO PREMATURA É A RAÍZ DE TODOS OS PROBLEMAS”

DONALD KNUTH

É preciso medir antes de “adivinhar”

o que otimizar

É preciso medir antes de “adivinhar”

o que otimizar

E como medir?

Na medição, duas perguntas precisam

ser respondidas

1 - Quão rápido é meu sistema?

1 - Quão rápido é meu sistema?

Em aplicações Web, a métrica mais comum é o reqs/sec

1 - Quão rápido é meu sistema?

Essa pergunta é respondida com benchmarks

Testes de carga

Testes de carga

ApacheBench (ab)

Siege - www.joedog.org

Macintosh:~ felipe$ ab -c 10 -t 30 -k 'http://shoprizer.localhost/'This is ApacheBench, Version 2.3 <$Revision: 655654 $>Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking shoprizer.localhost (be patient)Finished 4379 requests

Server Software: Apache/2.0.59Server Hostname: shoprizer.localhostServer Port: 80

Document Path: /Document Length: 22320 bytes

Concurrency Level: 10Time taken for tests: 30.010 secondsComplete requests: 4379Failed requests: 0Write errors: 0Total transferred: 99436344 bytesHTML transferred: 97806240 bytesRequests per second: 145.92 [#/sec] (mean)Time per request: 68.532 [ms] (mean)Time per request: 6.853 [ms] (mean, across all concurrent requests)Transfer rate: 3235.74 [Kbytes/sec] received

Macintosh:~ felipe$ siege -b -t30s 'http://shoprizer.localhost/'** SIEGE 2.67** Preparing 10 concurrent users for battle.The server is now under siege...Lifting the server siege... done.Transactions: 4909 hitsAvailability: 100.00 %Elapsed time: 29.84 secsData transferred: 104.49 MBResponse time: 0.06 secsTransaction rate: 164.51 trans/secThroughput: 3.50 MB/secConcurrency: 9.93Successful transactions: 4909Failed transactions: 0Longest transaction: 2.28Shortest transaction: 0.00

2 - Por que meu sistema tem essa performance?

Profiling

2 - Por que meu sistema tem essa performance?

Xdebug arrebenta no profiling!

• Instale a extensão Xdebug

• Habilite a opção xdebug.profiler_enable caso queira que toda execução gere o log

• Ou a opção xdebug.profiler_enable_trigger para que o log só seja gerado quando você passar?XDEBUG_PROFILE na URL

• Rode o script que você quer analisar

• Abra o log gerado pelo Xdebug no KCacheGrind caso use Linux, ou no WebGrind em qualquer outra plataforma.

• xdebug_memory_usage( ) diz quanto de memória o script está usando no momento da chamada

• xdebug_peak_memory_usage( ) diz qual o valor máximo de memória que foi usada durante a execução

Ajustes nos servidores

APACHE

MOD_DEFLATE

• Comprime o arquivo com gzip antes de enviar (se o navegador suportar)

• O custo de processamento normalmente é compensado com a economia de banda

• Só compacte arquivos de texto (html, xml, css, js)

MOD_DEFLATE

• Configurando:

$ a2enmod deflate

/etc/apache2/mods-available/deflate.conf<IfModule mod_deflate.c>AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript</IfModule>

MOD_EXPIRES

• Diga ao visitante até quando ele pode usar a versão atual de um arquivo sem precisar acessar o servidor novamente

• Use o cache do cliente, economize requisições e dê a ele a impressão de mais rapidez

• mod_expires coloca no cabeçalho HTTP a data de expiração daquele arquivo

MOD_EXPIRES

$ a2enmod expires

No seu .htaccess ou configuração do site:

ExpiresActive OnExpiresDefault "access plus 30 days" ExpiresByType text/html "access plus 1 month 15 days 2 hours"ExpiresByType image/gif "modification plus 5 hours 3 minutes"

DIRECTORYINDEX

• No Apache você pode configurar o DirectoryIndex que especifica qual arquivo é o “index” de cada diretório

• Você pode especificar mais de um e o Apache segue a sequência até achar o que exista:

<Directory /var/www>    DirectoryIndex index.html index.htm index.php</Directory>• Para isso, é feita uma syscall para verificar a existência dos arquivos

a cada requisição

DIRECTORYINDEX

• O impacto é pequeno mas podemos evitar isso

• Configure o DirectoryIndex para ir direto para o arquivo correto

<Directory /var/www>    DirectoryIndex index.php</Directory>

Use um servidor a parte para arquivos estáticos

http://static.example.com

Algo mais leve também resolve...

Lighttpdnginxthttpd

PHP

APC

• PHP compila os arquivos (JIT) e gera um código intermediário (opcode) a cada execução

• Essa compilação pode ser evitada, para isso é necessário fazer cache do opcode

• A solução padrão é o APC

• Virá “built-in” no PHP6

APC

• Existem outras alternativas com o mesmo propósito

• XCache

• Zend Platform

APC

• A instalação é trivial, no Ubuntu basta executar :

# apt-get install php-apc

• Por padrão o cache do opcode já é habilitado

• O parâmetro apc.stat permite que o APC não cheque se o arquivo foi alterado (aumentando ainda mais a performance), o que é bom para sistemas em produção. Mas qualquer alteração implica num restart do Apache.

BANCOS DE DADOS

MySQL

MYSQL• MySQL é o SGBD mais comumente utilizado com o PHP

• Foi feito com foco em performance, mas com o tempo vem ganhando funcionalidades voltadas para integridade relacional e consistência dos dados

• Implementa um cache interno de queries

• Os principais engines são:

• MyISAM

• InnoDB

• Ambos usam índices organizados internamente em árvores B

• Qual escolher?

MYSQL - MYISAM

• Rápida para leitura

• Table-level locking

• Uma escrita trava todos os acessos paralelos à tabela

• INSERT DELAYED é não bloqueante e permite que seu PHP continue executando enquanto a query fica na fila para ser executada

• Índices FullText

MYSQL - MYISAM

• Menor consumo de memória e espaço em disco

• Utiliza recursos de cache do sistema operacional

MYSQL - INNODB

• Integridade relacional

• Chaves estrangeiras

• Row-level locking

• Na escrita, só é travado para acessos paralelos o registro que está sendo escrito

• Maior consumo de memória e espaço em disco

• Utiliza implementação própria de cache

ÍNDICES

ÍNDICES

• Índices agilizam as buscas e tornam as escritas mais lentas

• Transforme em índice todas as colunas que são utilizadas como parâmetro de consulta ou ordenação

• Remova o índice das colunas que não são utilizadas nessas situações.

TIPOS DE DADOS

TIPOS DE DADOS

• Não armazene números em VARCHAR

• Não armazene datas em VARCHAR

• Se o campo tem tamanho fixo use CHAR

• Ex.: Uma senha em MD5 (32) ou SHA1 (41)

• Economiza espaço e facilita as comparações

CACHE

CACHE

• Cache é a solução mais comum para otimização de performance em diversas áreas da computação

• Consiste em armazenar uma informação que é mais acessada num meio mais rápido do que a sua real origem.

• Por exemplo: Memória RAM serve de cache para o disco

CACHE

• Consulta a dados que não se alteram com muita frequência podem ser colocadas em cache. Por exemplo:

• Um site de notícias não precisa acessar o banco todas as vezes que uma mesma notícia precisa ser exibida.

• Um site que agrega conteúdo de vários outros não precisa consultar as APIs a cada acesso dos seus usuários. Ele pode manter um cache local.

CACHE

• Iremos discutir a implementação de 4 tipos de cache:

• Smarty (Cache em disco)

• APC (Cache em memória)

• Memcache (Cache em memória em ambiente distribuído)

• Funky Caching (Cache em disco com a criação de arquivos estáticos)

SMARTY

• Smarty é uma biblioteca muito popular de “template engine”

• Porém ela também oferece a funcionalidade de cache dos templates já com as informações agregadas

• Gerando no disco um arquivo específico para cada registro “cacheado”

• Você pode setar um TTL para o objeto em cache

SMARTY

<?phprequire 'smarty/Smarty.class.php';

$id = (int) $_GET['id'];$smarty = new Smarty();$smarty->caching = 1;

if(!$smarty->is_cached('noticia.tpl',$id)) { //Carrega do banco de dados}$smarty->display('noticia.tpl',$id);

http://smarty.net/manual/pt_BR/caching.php

APC

• O mesmo APC que faz cache do Opcode também faz cache de objetos na memória

• apc.shm_size determina quanto de memória o APC pode usar para armazenar objetos, quando esse espaço é ocupado, os que foram usados a mais tempo são removidos (LRU)

• Você pode setar um TTL para o objeto em cache

APC

<?php$id = (int) $_GET['id'];$cache_id = "noticia::$id";

if(!($noticia = apc_fetch($cache_id))) {

$noticia = new Noticia($id);

//Armazena o valor no cache em memória do APC apc_store($cache_id, $noticia);}

...

http://br.php.net/apc

MEMCACHE

• O Memcache independe do PHP, é executado como um daemon externo

• Conecta-se via sockets, e por isso não é indicado para grandes objetos

• Utiliza também a política do LRU para remoção

• Você pode setar um TTL para o objeto em cache

MEMCACHE<?php$id = (int) $_GET['id'];$cache_id = "noticia::$id";

$memcache = new Memcache();$memcache->connect('localhost', 11211);

if(!($noticia = $memcache->get($cache_id))) { $noticia = new Noticia($id); $memcache->set($cache_id,$noticia);}

...

http://br.php.net/memcache

MEMCACHE

• Memcache também pode ser utilizado como mecanismo para armazenamento de dados de sessão.

• Isso permite que se tenha vários servidores Web e independente de qual servidor trate a requisição do usuário, pode-se acessar os dados de sessão que estão no servidor Memcache, basta setar no php.ini:

session.save_handler = memcachesession.save_path = "tcp://host_do_memcache:11211"

FUNKY CACHING

• Funky Caching é uma técnica não muito elegante mais muito eficiente

• Consiste em criar arquivos html estáticos sob demanda

• Usada no próprio site php.net

FUNKY CACHING

• No .htaccess ou outro arquivo de configuração do seu site no Apache, especifique como página de erro 404 um script PHP que é responsável por criar as páginas que não estão em cache.

• Por exemplo, no diretório http://www.example.com/noticias/ poderíamos criar um .htacces com a regra:

ErrorDocument 404 /noticias/gera_cache.php

FUNKY CACHING

• No gera_noticias.php faríamos tratamento da URL que foi requisitada e criaríamos o arquivo caso seja possível, por exemplo:

• http://www.example.com/noticias/1234.html indica que o usuário quer acessar a notícia de id 1234

• O PHP cria esse arquivo e nos próximos acessos o html existirá e o PHP não será mais chamado, pois não ocorrerá o erro 404.

FUNKY CACHING<?php$id = basename($_SERVER['REDIRECT_URL'], '.html');

/* Acessa a página dinâmica */$html = file_get_contents(sprintf("http://www.example.com/noticias.php?id=%d",$id));/* O ideal é fazer algum tratamento de erros, para evitar acriação de arquivos para ids inválidos */

/* Exibe o conteúdo */header(sprintf('%s 200', $_SERVER['SERVER_PROTOCOL']));echo $html;

/* Salva o conteúdo em um arquivo .html */file_put_contents(sprintf(dirname(__FILE__)."/%d.html", $id), $html);

E A NÍVEL DE BROWSER?

FIREBUG + YSLOW

• São plugins para o Mozilla Firefox

• Fazem análise para depuração (Firebug) e otimização (YSlow) de toda a parte client-side

• YSlow foi desenvolvido pelo Yahoo Performance Team

FIREBUG - NETMostra o tempo de requisição, espera e download de cada

componente da página

FIREBUG - NET

YSLOW - GRADEAnalisa vários critérios da página, dá “notas” e dá dicas de como

melhorar

YSLOW - GRADE

YSLOW - COMPONENTSPermite analisar a carga de cada componente carregado

YSLOW - COMPONENTS

YSLOW - STATISTICSMostra como a carga está proporcionalmente dividida entre os

componentes da página, com cache limpo e “quente”

YSLOW - STATISTICS

YSLOW - TOOLSFerramentas para compressão de Javascript, imagens, geração de

relatórios e análise de código

YSLOW - TOOLS

REFERÊNCIAS

• PHP - Simple is Hard - Rasmus Lerdorf - http://talks.php.net/show/w2e09

• Alta performance em Web Sites - Souders - Editora O’Reilly