Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

RSS iMasters

[Resolvido] Acelere o carregamento de páginas: técnicas incomuns

Recommended Posts

Introdução

Mais do que geralmente, a velocidade de umsite é o principal fator que determina o seu sucesso. Quando eu falo develocidade de um site, estou falando sobre a percepção do usuário em determinarse o carregamento das páginas do site está sendo rápido ou não.

No artigo anterior, falei sobre um fatorimportante que muitas vezes afeta bastante os efeitos da percepção do usuáriosobre a velocidade de um site, que é a presença de conteúdo de sites externosque geram lentidão no carregamento das páginas, como publicidade e widgets.

No artigo em questão, apresentei umatécnica que estou usando para que o conteúdo externo não tenha efeito sobre apercepção do usuário na velocidade do site. Neste artigo, irei falar sobreoutro fator que também pode afetar a percepção da velocidade do site, mas destavez relacionado a aspectos no ambiente do lado do servidor.

Processos background do lado do servidor

Ser capaz de servir disponibilizar web rápido osuficiente não depende somente do servidor web e do código da linguagem quegera as páginas. Em um servidor, existem muitos processos sendoexecutados em paralelo. Às vezes, esses processos não têm nada a ver com entregar páginas web. Vamos chamar esses processos de processos background.

Muitas vezes, esses processos backgroundexcedem o número de processos do servidor web. Às vezes, processos background consomem mais CPU e outros recursos da máquina do que os processosdo servidor web.

Assim, esses processos podem executartarefas que são importantes para o site, mas que não influenciam na velocidadeda entrega das páginas web. Exemplos dessas tarefas são: entrega denewsletters, processos de back up, percorrer as páginas do site para atualizaro mecanismo de busca, e outras tarefas de manutenção que devem ser executadasregularmente no site.

O problema é que todos esses processos estãocompetindo pelos núcleos disponíveis da CPU e muitas vezes afetam a velocidade dageração e de entrega das páginas web. Portanto,é muito importante garantir que esses outros processos não afetemsignificativamente a performance dos principais processos do servidor. Casocontrário, a percepção do usuário da velocidade será amplamente afetada.

Limitação da CPU (CPU Throttling) emprocessos background

Uma solução óbvia para evitar que osprocessos background afetem os processos do servidor web é comprar um oumais servidores e dividir essas tarefas pesadas em máquinas diferentes. Issopoderia resolver o problema, mas ficaria mais dispendioso manter o site.

Na verdade, mover os processos backgroundpesados em máquinas diferentes é um dos caminhos a ser seguido se esses  processos background estiverem consumindomuita CPU e outros recursos durante todo o dia. No entanto, esse geralmente nãoé o caso.

Por exemplo, se você tiver que entregar umanewsletter para os usuários registrados em seu site, a entrega para todos elespode levar de minutos a horas. O script que executa a entrega da newsletterpode requerer muito trabalho da CPU, até que seja finalizado. Por outro lado, aentrega da newsletter pode não ser urgente. Portanto, se a atrasarmos de vez emquando, isso não será um problema. Na pior das hipóteses, os usuários irãoreceber a newsletter um pouco depois.

A técnica para controlar a velocidade de umprograma ao desacelerá-lo quando necessário é chamada de Limitação de CPU (CPU throttling).

Limitação de CPU no PHP

Uma maneira pela qual podemos atrasar aentrega de newsletter ou de qualquer outro processo repetidamente executado nobackground é inserir código nos loops repetitivos que pausem o script por um tempo.No PHP, isso pode ser feito, por exemplo, com a função sleep (). Essa funçãosimplesmente espera por alguns segundos, pausando efetivamente o script PHP.Durante esse tempo, o SO irá dar para a CPU outros processos.

Agora que sabemos como pausar um script PHP,a única questão que falta respondermos é quando devemos fazer isso de modo queos scripts dos processos background não consumam tanta CPU a ponto de afetaros principais processos do servidor web. Se você não sabe a resposta, esse é osegredo que este artigo irá revelar.

Primeiramente, você precisa compreender muitobem como os sistemas operacionais funcionam. A maioria dos sistemasoperacionais modernos implementa o que é chamado de mutitarefas. Issosignifica que quando existe um certo número de processos sendo executados nosistema, todos eles precisam da CPU para executar seu código, e então todosdevem esperar em fila.

Mesmo se a sua máquina tiver CPUs múltilpasou múltiplos núcleos de CPU, geralmente existem mais processos esperando a CPUpara serem executados do que CPUs disponíveis. Portanto, o SO tem querotacionar os núcleos disponíveis da CPU entre todos os processos que estão sendoexecutados. Um SO multitarefas faz isso alocando um período de tempo para cadaprocesso. Quando esse período termina, o SO suspende aquele processo e alocaoutro período de tempo para o próximo processo que precisa da CPU.

Em sistemas operacionais como o Linux, existeuma maneira simples de determinar o número de processos esperando pela CPU. OLinux disponibiliza as estatísticas dos processos de carregamento através doarquivo /proc/loadavg. Na verdade, esse não é um arquivo real armazenado no disco. Éapenas uma variável do sistema no sistema de arquivos virtuais /proc.Você consegue acessá-lo usando chamados regulares de acesso a arquivos. No PHP,você pode utilizar open() e fread() ou chamadas file_get_contents() para acessá-lo.

A classe system monitor

Então a solução para implementar a limitaçãode CPU nos scripts PHP no Linux é bastante simples. Nós apenas lemos o arquivo loadavgregularmente. Se ele disser que o carregamento atual está muito alto, nósapenas chamamos a função sleep () para esperar um tempo. Então checamos oarquivo de carregamento mais uma vez. Se o carregamento da CPU ainda estivermuito alto, esperamos mais um tempo até que o carregamento esteja baixo osuficiente.

Para simplificar esseprocesso, eu desenvolvi há muitos anos uma classe chamada system monitor quefaz toda a checagem do carregamento da CPU para você. Eu publiquei aclasse system monitor no site PHPClasses, paraque todos possam se beneficiar dela.

Como de praxe, ela está disponível através dalicença BSD. Então você pode usá-la, modificá-la, desde que seus direitosoriginais de copyright sejam mantidos. Peço apenas que preserve quaisquer URLsque você encontre no arquivo da classe, de modo que outras pessoas consigamsaber onde encontrar as últimas atualizações da mesma.

A maneira de usar essa classe para limitar osseus scripts é muito simples. Existe uma function call chamada Throttle. Essafunção retorna um valor que diz se o sistema está sob um alto carregamento. Elaconsidera um limite de carregamento que você pode definir ao configurar avariável da classe cpu_load_limit.

Se a função Throttle disserque o carregamento da CPU está muito alto, podemos chamar a função sleep () erepetir o processo até que o carregamento da CPU se torne baixo novamente.

Portanto, o único fatorque devemos decidir agora é o limite de carregamento que será a referência paraque o carregamento da CPU seja considerado alto e baixo o suficiente.

Eu uso o seguintecritério: pego o número de núcleos da CPU disponível na máquina e o multiplicopor 2. Portanto, se o seu servidor tiver 1 CPU com 2 núcleos, o limite decarregamento da CPU deve ser definido por 2 x 2 = 4. Isso significa que se houver 2 oumais processos esperando por um núcleo da CPU, os processos background devemficar em espera por um tempo.

Outros fatores que você deve configurar sãoos períodos que determinam por quanto tempo seus processos devem esperar quandoo carregamento está muito ato e com qual frequência você deve checar ocarregamento da CPU para determinar se o sistema está muito pesado ou leve.

O arquivo loadavg fornece 3 médias deestatísticas de CPUs: uma para o último minuto e outras duas para os últimos 5e 15 minutos. Por padrão, a classe system monitor usa aquela para o último minuto,mas você pode mudar isso.

Com a média docarregamento da CPU no último minuto, parece razoável checar a variável decarregamento da CPU pelo menos uma vez a cada 60 segundos. Você pode checá-lomais de uma vez se quiser reagir mais rapidamente quando o carregamento dosistema surgir. Também parece razoável esperar por 60 segundos quando ocarregamento do sistema estiver muito alto, mas você também pode esperar menostempo se não quiser atrasar muito os processos background.

O loop das suas tarefasintensivas na CPU deve se parecer com isto:

$monitor = new system_monitor_class;

$monitor->cpu_load_limit = 4;

 

/* Work loop starts here */

 

for($i = $start; $i < $end; ++$i)

{

 

/* do some heavy work here, say

deliver a bunch of newsletters messages */

 

for(;;)

{

if(!$monitor->Throttle($cause))

die('Fatal error: '.$monitor->error);

 

if($cause == THROTTLE_CAUSE_NONE)

break;

 

sleep(60);

}

}

Limitando programas externos

Limitar os processos de scripts PHP se tornoufácil com as instruções acima. No entanto, você só é capaz de aplicar essemétodo para limitar scripts sobre os quais você tem o controle do código. Se vocêconfiar em um programa externo que executa uma tarefa pesada mas você nãocontrola esse código, muitas vezes porque ele foi escrito em outra linguagem,essa solução não irá limitar esse programa externo. 

O site do PHPClasses começou com esse problema,porque o mecanismo de busca interno se apoiava em um programa externo chamadohtDig. É um programa open source bastante antigo, escrito em C++. Ele éusado para indexar o site todo. Esse processo demora muito, porque existem maisde 50 mil páginas para analisar.

Talvez seria melhor desenvolver um mecanismode busca para substituí-lo em PHP, pois então seria mais fácil limitar o códigoa ser analisado. Infelizmente, essa não é uma solução viável no momento, poisiria demorar muito para refazer a integração do htDig com os recursos de busca relacionados aoPHPClasses.

Felizmente, eu consegui elaborar uma abordagemdiferente. No Linux, existe uma maneira muito fácil de colocar programas emexecução em espera por um tempo, desde que você utilize o mesmo SO que vocêiniciou ou programa ou que ?você? seja o usuário raiz.

A ideia consiste em enviar um sinal para oprocesso background em execução chamado SIGSTOP. Isso faz com que osprocessos fiquem em espera até que eles recebam outro sinal chamado SIGCONT. No PHP,você pode enviar sinais para processos em execução usando a funçãoproc_terminate(). Apesar do nome da função, ela não necessariamente finaliza oprograma. Apenas especifique o sinal certo a ser enviado. Se você quisercomeçar e controlar a execução de um processo em PHP e deixar o programarodando no background, você pode usar a função proc_open().

Eu melhorei a classesystem monitor para usar essas funções e para automatizar todo o processo deexecução de um programa externo no PHP e limitar sua execução. Tudo que vocêprecisa é chamar a função ThrottleExecute passando a linha de comando doprograma externo que você quer executar. Você pode passar parâmetros adicionaispara controlar outros aspectos como capturar o output do comando.

O script de limitação para seu programa externo devese parecer com isto:

$monitor = new system_monitor_class;

$monitor->cpu_load_limit = 4;

 

$command = 'path_to_external_command command parameters';

 

$parameters = array(

'Command' => $command,

'CaptureOutput' => 'string',

);

 

if(!$monitor->ThrottleExecute($parameters))

die('Fatal error: '.$monitor->error);

 

if($parameters['Status'] != 0)

die('the command failed for some reason');

 

do_something_with_output($parameters['Output']);

Outros problemas de carregamentoexcessivo do servidor

Se você acessou o site do PHPClasses no período em que a autenticação OpenID foi implementada, vocêdeve ter experenciado dificuldade para acessá-lo em alguns períodos do dia. O carregamentoexcessivo foi uma das consequências de se ter muitos processos backgroundrodando ao mesmo tempo sem serem limitados.

Felizmente, a classe system monitor foiutilizada para resolver a maioria dos problemas, mas isso levou tempo, pois nãoé fácil saber quais partes dos scripts rodando no background devem serlimitadas. As coisas estão muito melhores agora, mas pode haver partes do diaem que o carregamento do servidor fique muito alto.

Outro problema que estava causando o excessode carregamento do servidor, mas que não estava relacionado ao uso excessivo daCPU, foi um erro de configuração. Eu gostaria de comentar sobre ele porque elefoi tão sutil que eu precisei de semanas para descobrir o que estava errado.Então isso pode acontecer com você também.

Tudo começou quando eu abri o site da autenticação OpenID e então o site JSClasses. Então eu pensei queseria uma boa ideia, por motivos de segurança, usar diferentes usuários debancos de dados para cada um dos sites, apesar de que todos estavam rodando nomesmo servidor.

Eu pensei que se algum cracker invadisse umsite e manipulasse seu banco de dados, ele não seria capaz de acessar os bancosde dados do outro site, pois ele não iria permitir que o mesmo usuário do bancode dados o acessasse. A ideia parece inteligente em termos de segurança, mas asconsequências foram catastróficas em termos de uso de recursos do servidor.

O problema é que esses sites usam conexõespersistentes de bancos de dados para acessar o servidor do banco de dados.Conexões persistentes são boas para evitar um grande tempo de conexão. Noentanto, se você utilizar usuários diferentes para acessar o mesmo servidor debanco de dados, o PHP estabelece diferentes conexões para cada usuário do banco.

Portanto, isso fez com que o servidor web executasseo PHP para estabelecer 3 servidores de bancos de dados a mais do que onecessário se ele estivesse usando o mesmo usuário do banco de dados. Aconsequência foi que todas as conexões do banco de dados estavam derrubando o servidorde banco de dados durante as horas de maior acesso do site. O servidor de bancode dados só se recuperava depois de alguns minutos.

Eu estava notando muitas conexões de bancosde dados, mas não conseguia entender por quê, uma vez que o servidor web sótinha 1/3 dos processos sendo executados. Infelizmente, somente depois dealgumas semanas eu percebi que cada processo do servidor web estavaestabelecendo diferentes conexões para cada usuário do banco de dados.

Eu consertei o problema rapidamente e deixeitodos os sites utilizarem o mesmo usuário de banco de dados, mas foi muitofrustrante perceber o problema somente várias semanas depois que ele tinhacomeçado. Uma consequência ruim para o conteúdo do site, além da frustração dousuário, é que o número de pacotes inseridos caiu drasticamente. Oscontribuidores do site estavam desistindo de inserir seus pacotes no site.Agora a taxa de contribuição está quase de volta nos seus níveis anteriores,mas essa foi definitivamente uma lição aprendida da maneira mais difícil.

Acredito que a maioria das empresas dehospedagem PHP tem problemas similares, porque consumidores utilizando o mesmoservidor web têm que usar usuários de bancos de dados diferentes. Nesse caso,eles não podem permitir que seus consumidores usem o mesmo usuário de banco dedados, pois dessa maneira eles seriam capazes de roubar os dados de cada bancode dados.

Normalmente eles incentivam seus clientes afazer o upgrade de seus planos para VPS ou servidor dedicado quando elescomeçam a utilizar muitos recursos do servidor, mas eu me pergunto se umasolução melhor não existiria nos níveis de configuração do PHP ou do servidor. Talvez encerrando automaticamenteconexões de bancos de dados que não foram usadas depois de um tempo, mesmo seelas tiverem sido iniciadas como conexões persistentes. Eu simplesmente nãoconsegui descobrir como fazer isso para MySQL. Mas acredito que existe algoparecido para Oracle na configuração PHP. 

Conclusão

Bom, esse foi mais um artigo sobre técnicasnão usuais para aceleração de sites. Se você estava tendo problemas parecidosde carregamento nos seus  servidores web,espero que a solução de limitação te ajude a balancear e colocar mais processostrabalhando nas suas máquinas. Ela certamente ajudou o site PHPClasses.

A solução de checagem do carregamentofunciona bem no Linux, porque é o que o PHPClasses e muitos outros sites usamnos seus servidores. Portanto, não me dei ao trabalho de encontrar outra soluçãoque também funcione no Windows ou em outro sistema operacional. Se você souber como checar a média de carregamento da CPU ou suspender eresumir os processos em outros sistemas usando PHP, me informe. Talvez eu possaadaptar a classe system monitor para deixá-la útil para mais desenvolvedoresPHP.

?

Texto original eminglês de Manuel Lemos, disponível em http://www.phpclasses.org/blog/post/132-Accelerate-Page-Accesses-Throttling-Background-Tasks-Unusual-Site-Speedup-Techniques-Part-2.html

 

http://imasters.com.br/artigo/21827/php/acelere-o-carregamento-de-paginas-tecnicas-incomuns-de-aumento-de-velocidade-de-sites-parte-02

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.