Escalabilidade no PHP

Atenção! Essa postagem foi escrita há mais de 2 anos. Na informática tudo evolui muito rápido e algumas informações podem estar desatualizadas. Embora o conteúdo possa continuar relevante, lembre-se de levar em conta a data de publicação enquanto estiver lendo. Caso tenha sugestões para atualizá-la, não deixe de comentar!

Prefácio

John Coggeshall, CTO da Automotive Computer Services e autor do Zend PHP Certification Practice Book e PHP5 Unleashed, palestrou no OSCON 2008 sobre os 10 maiores enganos na escalabilidade. Não estive lá, mas ele postou os slides na rede. Seguem algumas lições aprendidas.

E aí vai…

1. Defina os objetivos da escalabilidade para a sua aplicação. Se você não sabe para quantas requisições irá responder, não saberá se pode construir algo que funcionará e quanto tempo irá durar.

2. Meça tudo. Uso de CPU, uso de memória, E/S de disco, E/S de rede, requisições por segundo, com este último sendo o mais importante. Se você não sabe de onde partiu, não saberá o quanto progrediu.

3. Planeje o seu banco de dados com escalabilidade em mente. Presuma que você terá que implementar replicação.

4. Não confie no NFS para compartilhamento de código em uma rede de servidores. É lento e tem problemas com travas (concorrência). Enquanto a idéia de manter apenas uma cópia do código e deixar os demais servidores acessarem via NFS parece conveniente, na prática não funciona. Tente algumas práticas já tuilizadas, como rsync. Mantenha o código local para a máquina está servindo, mesmo que isso significe um tempo maior durante o webcast.

5. Aproveite os Buffers de E/S. Se você possui toneladas de memória, brinque com o tamanho do buffer TCP, pois o padrão é bem conservador. Se o seu site é escrito em PHP, utilize as funções de buffer de saída.

6. Utilize Discos RAM (Ram Disks) para quaisquer dados que sejam descartáveis. Mas você vai precisar de muita RAM sobrando.

7. Otimize o consumo de banda ativando compressão via mod_deflate, alterando o valor da diretiva zlib.put_compression para true nos sites PHP, redução do conteúdo Tidy para os sites PHP+Tidy.

8. Configure o PHP para ser veloz. Desligue as seguintes diretivas: register_globals, auto_globals_jit, magic_quotes_gpc, expose_php, register_argc_argv, always_populate_raw_post_data, session.use_trans_sid, session.auto_start. Altere o session.gc_divisor para 10,000 e output_buffering para 4096 (no exemplo do John).

9. Não utilize ferramentas que bloqueiem E/S, como ler uma página remota utilizando curl. Faça todas as chamadas serem não-bloqueaveis, de outra forma, a espera é algo que você não poderá otimizar. Utilize scripts que rodem em background para capturar os dados necessários para serem processados.

10. Não subestime o cache. Se uma página ficar em cache por 5 minutos, se você possuir 10 requisições por segundo nesta página, já são 3.000 requisições que o seu banco de dados não teve de processar.

11. Considere o Cache do PHP op-code. Estará embutido pra você no PHP6.

12. Para sites com muito conteúdo, considere tirar o que for estático do contexto dinâmico. Digamos que você tem uma página de notícias, onde o conteúdo é sempre o mesmo, mas o resto da página é personalizada pelo próprio usuário. Ao invés de pegar todos os dados dinamicamente do DB, pense na possibilidade de gerar um outro arquivo PHP na primeira requisição, onde o artigo ficaria armazenado num arquivo HTML puro e os dados dinâmicos enviados para usuários logados. Desse modo, o arquivo PHP gerado irá puxar os dados que realmente são dinâmicos.

13. Preste muita atenção no planejamento do banco de dados. Aprenda índices e como usá-los apropriadamente. InnoDB supera MyISAM na maioria dos contextos, mas não faz as chamadas “full-text search”.

14. Desenvolva aplicações PHP de modo abstrato, assim o sistema nunca irá precisar saber qual o IP do MySQL. Alguma coisa do tipo “escrever-no-mysql” e “ler-do-mysql” seria perfeitamente plausíveis numa aplicação PHP.

15. Rode scripts externos para monitorar a saúde do sistema. Faça os scripts trocaram os HOSTS se a coisa sair do controle.

16. Não realize a escolha de banco de dados dentro do PHP. Não perca seu tempo criando fallbacks caso o seu banco primário esteja offline. Utilize um proxy MySQL para simplificar as tarefas de conexão ao banco de dados.

17. Para leituras super-rápidas, considere SQLite. Mas não esqueça que ele é terrível com escrita.

18. Utilize o Keepalive apropriadamente. Use quando arquivos estáticos e dinâmicos são servidos no mesmo servidor e você pode controlar os timeouts, de forma que uma porção de requisições Keep-alive não sobrecarreguem seu servidor. Regra do John? Nenhuma requisição Keep-alive deve durar mais de 10 segundos.

19. Monitorar via comandos Linux familiares. Por exemplo, iostat e vmstat. O comando iostat é utilizado para monitorar a carga do dispositivo de entrada/saída do sistema a partir da observação do tempo ativo dos dispositivos em relação à taxa média de transferência. O comando iostat gera um relatório que pode ser utilizado para alterar configurações do sistema para melhor balançear a carga de entrada/saida entre os discos físicos. vmstat mostra informações acerca dos processos, memória, paginação, bloqueio de E/S, traps e atividade da cpu.

20. Tenha certeza de que está logando informações relevantes. De outra forma, debugar os problemas pode ser realmente uma dor de cabeça.

21. Priorize sua otimização. A otimização de 50% do código que roda em 2% das páginas irá resultar em 1% de melhoria total. A otimização de 10% do código que roda em 80% das páginas resultará em 8% de melhoria total.

22. Use perfiladores (profilers). Eles desenham gráficos bonitos e geralmente são fáceis de usar.

23. Acompanhe o desempenho do seu sistema sempre. Mantenha uma planilha com alguns dados que você está acompanhando, pois assim você pode dizer com propriedade o quanto você ganhou ao utilizar uma CPU mais rápida, instalar mais memória RAM ou ao atualizar o kernel do seu Linux.

Conclusão

Eu sempre me emociono quando falo em escalabilidade. É um assunto excitante que me desperta muito interesse… Espero que vocês também possam compartilhar dicas que utilizam enquanto estão escalando sistemas.

Aproveito pra pedir perdão pelo tempo que fiquei fora… Mas prometo que voltarei aos poucos…

Um grande abraço a todos e fiquem com Deus
Rafael Jaques