Cinco maneiras simples de ajustar seu aplicativo LAMP

A arquitetura Linux, Apache, MySQL, and PHP (LAMP) é uma das escolhas mais populares para arquitetura de servidor da Web em uso hoje. O autor John Mertic examina cinco coisas que todos os aplicativos LAMP devem aproveitar para obter desempenho máximo.

John Mertic, Software Engineer, SugarCRM

John Mertic é um engenheiro de software na SugarCRM, e tem vários anos de experiência com aplicativos PHP da Web. Na SugarCRM, ele especializou-se em arquitetura de interface com o usuário, móvel e integração de dados. Um ávido escritor, ele teve artigos publicados na php|architect, IBM developerWorks e na Apple Developer Connector, e é autor do livro "The Definitive Guide to SugarCRM: Better Business Applications". Ele também já fez contribuições a vários projetos de software livre, mais notavelmente ao projeto PHP onde ele é o criador e mantenedor do PHP Windows Installer. Seu e-mail de contato é jmertic@gmail.com.



12/Abr/2011

Introdução

Importantes propriedades da Web, como Wikipédia, Facebook e Yahoo!, usam a arquitetura LAMP para servir milhões de solicitações por dia, e software de aplicativos da Web como Wordpress, Joomla, Drupal e SugarCRM usam essa arquitetura para permitir que organizações implementem aplicativos da Web facilmente.

A força da arquitetura está na sua simplicidade. Enquanto pilhas como tecnologia .NET e Java™ podem usar hardware massivo, pilhas de software caras e ajuste complexo de desempenho, a pilha LAMP pode ser executada em hardware de commodity, usando pilhas de software livre. Como a pilha de software é um conjunto vago de componentes em vez de uma pilha monolítica, ajustar o desempenho pode ser um desafio, já que cada componente precisa ser analisado e ajustado.

Entretanto, há várias simples tarefas de desempenho que podem ter um enorme impacto no desempenho de Web sites de qualquer tamanho. Neste artigo, examinaremos cinco dessas tarefas, projetadas para otimizar o desempenho de aplicativos LAMP. Esses itens devem exigir pouca ou nenhuma alteração em sua arquitetura, o que as torna uma opção segura e fácil para maximizar a responsividade e requisitos de hardware de seu aplicativo da Web.


Usar um cache opcode

A coisa mais fácil para melhorar o desempenho de qualquer aplicativo PHP (o "P" em LAMP, claro) é aproveitar o cache opcode. Para qualquer Web site em que trabalho, essa é a única coisa que exijo estar presente, já que o impacto no desempenho é enorme (muitas vezes com tempos de resposta que são metade do que seriam sem um cache opcode). Mas a maior pergunta que a maioria das pessoas novatas em PHP faz é por que a melhoria é tão drástica. A resposta está na maneira como o PHP lida com solicitações da Web. A Figura 1 delineia o fluxo de uma solicitação PHP.

Figura 1. Solicitação de PHP
Solicitação de PHP

Como PHP é uma linguagem interpretada, e não compilada como C ou Java, as etapas de análise/compilação/execução são executadas para cada solicitação. Você pode ver como isso pode consumir tempo e recursos, especialmente quando os scripts raramente mudam entre as solicitações. Após o script ser analisado e compilado, ele está em um estado analisável por máquina em uma série de opcodes. É aqui que entra um cache opcode. Ele armazena em cache esses scripts compilados como uma série de opcodes, para evitar as etapas de análise e compilação para cada solicitação. A Figura 2 mostra como um fluxo de trabalho assim funcionaria.

Figura 2. Solicitação de PHP que usa um cache opcode
Solicitação de PHP que usa um cache opcode

Quando houver opcodes armazenados em cache de um script PHP, podemos ignorar as etapas de análise e compilação do processo de solicitação de PHP e executar diretamente os opcodes em cache e enviar os resultados. O algoritmo de verificação cuida de situações nas quais foi feita uma mudança no arquivo do script, de modo que, na primeira solicitação do script alterado, os opcodes serão automaticamente recompilados e armazenados em cache para solicitações posteriores, substituindo o script em cache.

Há tempo que caches opcode são populares para PHP, sendo que alguns dos primeiros vieram nos dias do PHP V4. Hoje há algumas escolhas populares que estão em desenvolvimento ativo e sendo usadas:

  • Alternative PHP Cache (APC) é provavelmente o cache opcode mais popular para PHP (consulte Recursos). É desenvolvido por vários desenvolvedores PHP principais e recebeu importantes contribuições, ganhando sua velocidade e estabilidade de engenheiros do Facebook e Yahoo! Também apresenta várias outras melhorias para lidar com solicitações de PHP, incluindo um componente de cache de usuário que nós examinaremos mais tarde neste artigo.
  • Wincache é um cache opcode que tem maior desenvolvimento ativo pela equipe de Internet Information Services (IIS) na Microsoft® para uso apenas em Windows® usando o servidor da Web IIS (consulte Recursos). Foi desenvolvido predominantemente em um esforço para tornar o PHP uma plataforma de desenvolvimento de primeira classe na pilha Windows-IIS-PHP, já que se sabia que APC não funcionava bem nessa pilha. É muito semelhante a APC em sua função, e apresenta um componente de cache de usuário, bem como um manipulador de sessão integrado para aproveitar Wincache diretamente como manipulador de sessão.
  • eAccelerator é uma ramificação de um dos caches originais de PHP, o cache opcode Turck MMCache (consulte Recursos). Ao contrário de APC e Wincache, é apenas um cache opcode e otimizador, portanto não contém os componentes de cache do usuário. É totalmente compatível ao longo de pilhas UNIX® e Windows, e é muito popular em sites que não pretendem usar os recursos adicionais fornecidos pelo APC ou Wincache. Esse é geralmente o caso quando se usa uma solução como memcache para ter um servidor de cache de usuário separado para um ambiente com vários servidores da Web.

Sem dúvida, um cache opcode é a primeira etapa ao acelerar o PHP, removendo a necessidade de analisar e compilar um script em cada solicitação. Após a primeira etapa ser concluída, deve ocorrer uma melhora no tempo de resposta e carga do servidor. Mas há mais que você pode fazer para otimizar PHP, que veremos adiante.


Otimizar a configuração de PHP

Embora implementar um cache opcode seja um grande impulso na melhora do desempenho, há alguns outros ajustes que podem ser feitos para otimizar sua configuração de PHP, baseado nas configurações de seu arquivo php.ini. Essas configurações são mais apropriadas para instâncias de produção; em instâncias de desenvolvimento ou teste, pode não ser ideal fazer essas mudanças, pois elas podem dificultar a depuração de problemas do aplicativo.

Vamos examinar alguns itens que são importantes para ajudar o desempenho.

Coisas que deveriam ser desativadas

Há várias configurações em php.ini que deveriam ser desativadas, pois são mais usadas para compatibilidade com versões anteriores:

  • register_globals— Essa funcionalidade era o padrão antes de PHP V4.2, no qual variáveis de solicitação recebidas são automaticamente atribuídas a variáveis de PHP normais. Além dos importantes problemas de segurança em fazer isso (ter dados de solicitação recebida sem filtragem sendo misturados com o conteúdo normal de variáveis PHP), há também o gasto adicional de ter que fazer isso em cada solicitação. Portanto desligar isso torna seu aplicativo mais seguro e melhora o desempenho.
  • magic_quotes_*— Essa é outra relíquia do PHP V4, no qual dados recebidos escapavam automaticamente dados de formulário arriscados. Foi projetado para ser um recurso de segurança para ajudar a limpar dados recebidos antes de serem enviados a um banco de dados, mas não é muito eficiente, pois não protege os usuários dos tipos de ataques de injeção de SQL mais comuns por aí. Como a maioria das camadas de banco de dados oferecem suporte a declarações preparadas que lidam com este risco de forma bem melhor, desligar isso irá, novamente, remover um problema de desempenho que incomoda.
  • always_populate_raw_post_data— Isso só é realmente necessário se, por algum motivo, for preciso ver a carga útil inteira dos dados POST recebidos sem filtragem POST. Do contrário, está apenas armazenando na memória uma cópia duplicada dos dados POST, o que não é necessário.

No entanto, desativar essas opções em código legado pode ser arriscado, pois eles podem contar com essas opções estarem ligadas para execução apropriada. Código novo não deve ser desenvolvido dependendo dessas opções, e você deve procurar maneiras de reconfigurar seu código existente para não usá-las se possível.

Coisas que deveriam ser ativadas ou ter sua configuração ativada

Há algumas boas opções de desempenho que podem ser ativadas no arquivo php.ini para aumentar um pouco a velocidade de seus scripts:

  • output_buffering— Você deve ter certeza de que isso está ligado, já que irá limpar a saída de volta para o navegador em um grande grupo em vez de a cada instrução echo ou print, sendo que este último pode aumentar bastante seu tempo de resposta de solicitações.
  • variables_order— Essa diretiva controla a ordem da análise de variáveis EGPCS (Environment, Obtenha , Post, Cookie e Server) para a solicitação recebida. Se você não estiver usando certos superglobais (como variáveis de ambiente), pode removê-las com segurança para obter um pequeno aumento de velocidade por não ter de analisá-las em cada solicitação.
  • date.timezone— Essa é uma diretiva que foi adicionada em PHP V5.1 para estabelecer o fuso horário padrão para uso com as funções DateTime introduzidas na época. Se você não configurar isso no arquivo php.ini, PHP fará algumas solicitações de sistema para descobrir qual é, e em PHP V5.3 um aviso será emitido a cada solicitação.

Essas são consideradas metas fáceis em termos de configurações que podem ser alteradas na sua instância de produção. Há mais uma coisa que você deve examinar em relação a PHP. É o uso de require() e include() (bem como seus irmãos require_once() e include_once()) em seu aplicativo. Eles otimizam a configuração e código PHP para evitar verificações desnecessárias de status de arquivo em cada solicitação, o que pode aumentar o tempo de resposta.


Gerencie seus require()s e include()s

Chamadas de status de arquivo (ou seja, chamadas feitas para o sistema de arquivos subjacente para verificar a existência de um arquivo) podem custar caro em termos de desempenho. Dois dos maiores culpados das estatísticas de arquivo são as instruções require() e include(), que são usadas para trazer código para seu script. As chamadas irmãs require_once() e include_once() podem ser mais problemáticas, pois não apenas precisam verificar a existência de um arquivo, como também verificar se ele já foi incluído antes.

E qual é a melhor maneira de lidar com isso? Há algumas coisas que você pode fazer para agilizar.

  • Use caminhos absolutos para todas as chamadas require() e include(). Isso deixará claro para o PHP qual é o arquivo exato que deve ser incluído, sendo desnecessário verificar todo o include_path para seu arquivo.
  • Mantenha o número de entradas em include_path baixo. Isso irá ajudar em situações nas quais é difícil fornecer um caminho absoluto para cada chamada require() e include() (geralmente no caso de grandes aplicativos legados) ao não verificar locais nas quais o arquivo sendo incluído não estará.

APC e Wincache também têm mecanismos para armazenar em cache os resultados de verificações de status de arquivo feitas por PHP, de modo que verificações repetidas do sistema de arquivo não são necessárias. Eles são mais eficientes quando se mantém os nomes dos arquivos estáticos em vez de conduzidos por variáveis, por isso é importante fazer isso sempre que possível.


Otimizar seu banco de dados

Otimização de banco de dados pode se tornar um tópico bem avançado rapidamente, e eu não tenho espaço aqui para fazer jus a esse tópico. Mas, se você estiver tentando otimizar a velocidade de seu banco de dados, há algumas etapas que você deve realizar primeiro, que devem ajudar com os problemas mais comuns encontrados.

Colocar o banco de dados em sua própria máquina

Consultas a bancos de dados podem se tornar bem intensas, geralmente usando 100% de um CPU fazendo simples instruções SELECT com conjuntos de dados de tamanho razoável. Se seu servidor da Web e servidor de aplicativos estiverem competindo por tempo de CPU em uma única máquina, isso irá definitivamente aumentar o tempo da sua solicitação. Por isso eu considero que um bom primeiro passo é colocar o servidor da Web e o servidor de banco de dados em máquinas separadas, e tornar o banco de dados o mais potente entre os dois (servidores de bancos de dados adoram muita memória e múltiplos CPUs).

Projetar e indexar tabelas adequadamente

Possivelmente o maior problema com o desempenho de banco de dados surge como resultado de design precário e ausência de índices. Instruções SELECT são, geralmente, os tipos mais comuns de consultas executadas em um aplicativo da Web típico. São também as consultas mais demoradas executadas em um servidor de banco de dados. Além disso, esses tipos de instruções SQL são os mais sensíveis a indexação e design apropriado de banco de dados, por isso observe as dicas a seguir para desempenho máximo.

  • Cada tabela deve ter uma chave primária. Isso dá à tabela uma ordem padrão e uma maneira rápida de mesclar a tabela com outras.
  • Chaves estrangeiras em uma tabela (ou seja, chaves que ligam um registro a um registro em outra tabela) devem ser indexadas adequadamente. A maioria dos bancos de dados força limites nessas chaves automaticamente, de modo que o valor de fato corresponda a um registro na outra tabela, o que pode ajudar nisso.
  • Tente limitar o número de colunas em uma tabela. Colunas demais em uma tabela pode tornar o tempo de varredura muito mais longo que apenas umas poucas colunas. Além disso, se você tiver uma tabela com muitas colunas que não são geralmente usadas, você está desperdiçando espaço em disco com campos de valor NULL. Isso também é verdade com campos de tamanho variáveis, tais como texto ou blob, nos quais o tamanho da tabela pode crescer mais que o necessário. Nesse caso, deve-se considerar dividir as colunas adicionais em tabelas diferentes, mesclando-as depois na chave primária dos registros.

Analisar as consultas sendo executadas no servidor

A melhor ferramenta para melhorar o desempenho do banco de dados é analisar quais consultas estão sendo executadas em seu servidor de banco de dados e o tempo que estão levando para serem executadas. Praticamente todos os bancos de dados existentes têm ferramentas para isso. Com MySQL, é possível aproveitar o log de consultas lentas para encontrar as consultas problemáticas. Para usar, defina a configuração slow_query_log para 1 no arquivo de configuração do MySQL, e log_output para FILE para fazer log no arquivo hostname-slow.log. É possível definir o limite long_query_time para o tempo que a consulta deve ser executada, em número de segundos, para ser considerada uma "consulta lenta". Eu recomendo configurar como 5 segundos primeiramente, e diminuir para 1 segundo com o tempo, dependendo do seu conjunto de dados. Se você examinar esse arquivo, verá as consultas detalhadas semelhantes à Listagem 1.

Listagem 1. Log de consultas lentas do MySQL
/usr/local/mysql/bin/mysqld, Version: 5.1.49-log, started with:
Tcp port: 3306  Unix socket: /tmp/mysql.sock
Time                 Id Command    Argument
# Time: 030207 15:03:33
# User@Host: user[user] @ localhost.localdomain [127.0.0.1]
# Query_time: 13  Lock_time: 0  Rows_sent: 117  Rows_examined: 234
use sugarcrm;
select * from accounts inner join leads on accounts.id = leads.account_id;

O aspecto principal que queremos olhar é Query_time, que mostra o tempo que a consulta levou. Outra coisa a ser examinada são os números Rows_sent e Rows_examined, pois eles podem indicar situações em que uma consulta possa estar escrita incorretamente se estiver examinando colunas demais ou retornando colunas demais. É possível examinar melhor como uma consulta é grava colocando EXPLAIN no início na consulta, o que retorna o plano da consulta em vez do conjunto de resultados, como mostra a Listagem 2.

Listagem 2. Resultados de EXPLAIN do MySQL
mysql> explain select * from accounts inner join leads on accounts.id = leads.account_id;
+----+-------------+----------+--------+--------------------------+---------+---
| id | select_type | table    | type   | possible_keys           
 | key     | key_len | ref                       | rows | Extra |
+----+-------------+----------+--------+--------------------------+---------+--------
|  1 | SIMPLE      | leads    | ALL    | idx_leads_acct_del       | NULL    | NULL    
| NULL                      |  200 |       |
|  1 | SIMPLE      | accounts | eq_ref | PRIMARY,idx_accnt_id_del | PRIMARY | 108    
| sugarcrm.leads.account_id |    1 |       |
+----+-------------+----------+--------+--------------------------+---------+---------
2 rows in set (0.00 sec)

O manual do MySQL analisa muito mais profundamente o tópico do resultado de EXPLAIN (consulte Recursos), mas a coisa importante que eu examino é lugares em que a coluna "type" é "ALL", pois isso exige que o MySQL faça uma varredura completa da tabela e não use uma chave para a consulta. Isso ajuda a indicar lugares nos quais a inclusão de índices ajudaria significativamente a velocidade da consulta.


Armazenar dados em cache efetivamente

Como vimos na seção anterior, bancos de dados podem facilmente ser o ponto mais problemático do desempenho de seu aplicativo da Web. Mas e se os dados que você estiver consultando não mudarem com frequência? Nesse caso, pode ser uma boa opção armazenar esses resultados localmente em vez de chamar a consulta em cada solicitação.

Dois dos caches opcode que analisamos anteriormente, APC e Wincache, têm recursos para fazer exatamente isso, permitindo armazenar dados PHP diretamente em um segmento de memória compartilhada para recuperação rápida. A Listagem 3 fornece um exemplo de como fazer isso.

Listagem 3. Exemplo do uso de APC para armazenar resultados de bancos de dados em cache
<?php

function getListOfUsers()
{
    $list = apc_fetch('getListOfUsers');
    
    if ( empty($list) ) {
        $conn = new PDO('mysql:dbname=testdb;host=127.0.0.1', 'dbuser', 'dbpass');
        $sql = 'SELECT id, name FROM users ORDER BY name';
        foreach ($conn->query($sql) as $row) {
            $list[] = $row;
        }
        
        apc_store('getListOfUsers',$list);
    }
    
    return $list;
}

Precisaremos usar a consulta apenas uma vez. Depois disso, colocamos o resultado no cache do usuário do APC sob a chave getListOfUsers. Daqui em diante, até que o cache expire, será possível recuperar o array de resultados diretamente do cache, ignorando a entrada SQL.

APC e Wincache não são as únicas escolhas para um cache de usuário; memcache e Redis são outras escolhas populares que não exigem que o cache do usuário seja executado no mesmo servidor que o servidor da Web. Isso oferece maior desempenho e flexibilidade, especialmente se seu aplicativo da Web for escalado ao longo de vários servidores da Web.


Conclusão

Neste artigo, examinamos cinco maneiras simples de ajustar seu aplicativo LAMP para obter melhor desempenho. Examinamos técnicas não apenas o nível do PHP, usando um cache de código e otimizando a configuração do PHP, mas também examinamos a otimização do design do banco de dados para indexação apropriada. Também examinamos o uso de um cache do usuário (usando APC como um exemplo) para mostrar como é possível evitar chamadas repetidas ao banco de dados quando os dados não mudam com frequência.


Download

DescriçãoNomeTamanho
Source codeos-5waystunelamp.zip---

Recursos

Aprender

Obter produtos e tecnologias

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Software livre, Linux
ArticleID=646881
ArticleTitle=Cinco maneiras simples de ajustar seu aplicativo LAMP
publish-date=04122011