O documento discute técnicas para otimizar e escalar aplicações PHP, dividido em duas partes: 1) dicas de otimização do MySQL e PHP e 2) como montar uma arquitetura escalável. É apresentado como criar índices no MySQL para melhorar desempenho de consultas, as diferenças entre motores MyISAM, InnoDB e Archive, e como usar cache nativo e balanceamento de carga horizontal. No PHP, é discutido usar versões mais recentes, desabilitar módulos desnecessários e configurar PHP accelerators como OPCache. Na segunda parte
Bom dia hoje vou falar para vocês os principais conceitos para escalar uma aplicação PHP, vou tentar dar um enfoque maior para a parte de Drupal.
Meu nome é Guilherme, tenho 21 anos sou desenvolvedor há cerca de 5 anos, atualmente trabalho na MMDA que é patrocinadora deste evento. Sou mais focado em desenvolvimento back-end sou certificado pela Acquia e aqui estão alguns locais onde vocês podem me encontrar para mandar feedbacks sugestões perguntas e tudo mais.
A grande diferença é que uma aplicação que escala bem tem que ser capaz de responder a um cenário crescente com a menor gradação de performance possível para usar menos recursos. Por exemplo você pode ter uma aplicação que performa bem no cenário atual mas ela não escala a medida que aumentam usuários.
eu quero falar para vocês algumas técnicas simples para otimização do MySQL, algumas dessas técnicas podem ser feitas sem alterar nada em sua aplicação somente usando recursos do banco de dados. Mesmo usando Drupal é saber da existência de tais técnicas que nem sempre o Schema que o Drupal e os modulos constroem para você é o melhor para o seu caso de uso, é bom ficar atento, conhecer suas necessidades e saber como o drupal e seus módulos funcionam, não somente utliza-los. As técnicas que vou citar a seguir são criação de Indices, diferençãs entre 3 tipos de engines do mysql e cuidados com Queries para garantir que o MySQL consiguirá usar cache de Queries.
Antes de continuar eu quero indicar para vocês uma ferramenta muito boa para debugar funções, módulos e queries lentas que é o new relic. Ele tem um painel onde mostra o tempo de execução das suas funções e queries faz um hanking do que está melhorando, faz sugestões de criação de indices etc. Ele ajuda bastante a corrigir futuros problemas na aplicação.
Basicamente um índice no MySQL é como um indice em um livro, quando você quer procurar algo dentro do livro é muito mais rápido você olha o indice e saber extamente o lugar onde está o que você procura. Sem indices você tem que fazer um Full table Scan para procurar o que você precisa. Já com um indice você pode saber que o que você procura está nas páginas 100, 108 e 400 por exemplo. Existem diferentes tipos de indices, o que eu vejo ser mais utlizado é o BTree. O ideal é você olhar a documentação do MySQL e ver se encaixa melhor para o seu caso.
Aqui temos um exemplo de como criar uma tabela com indice diretamente no banco de dados, além disso tu pode criar o indice com Alter table e também com um comando customizado Create INDEX
Com Drupal podemos criar com a função db_add_index, normalmente fazemos um hook update e adicionamos os indices necessários, na criação da tabela é possível também adicionar indices com hook_schema.
MyISAM, InnoDB e Archive são diferentes tipos de engines que o MySQL pode trabalhar. A principal diferença entre o MyISAM e o InnoDB é que o MyISAM trabalha com Table locking e o InnoDB trabalha com Transation Locking. Em tabelas que não mudam com frequência normalmente o MyISAM costuma performar melhor já para tabelas que tem mudanças constantes o InnoDB se mostra mais performático. Já o Archive é mais performático com tabelas que nunca mudarão, esse tipo de engine não suporta comandos como Delete, Update etc. Ela apresenta uma boa performance pois faz compreensão da tabela após as inserções, um bom caso de uso é para tabelas que vão guardar históricos por um grande intervalo de tempo e que não devem ser mudados.
O MySQL tem um cache nativo e temos que saber como fazer proveito desse cache. Cache funciona como chave valor, no caso do Mysql a chave sempre é a query que está sendo executada e o valor é o que ela retornou. É possível configurar o tamanho desse cache no arquivo de configuração do mysql. O mais importante é entendermos como ele funciona para fazer proveito do mesmo, lembrando que o cache do mysql é transparente ao usuário, isso quer dizer que você não vai controlar o mesmo, não precisa mudar sua aplicação para ele funcionar corretamente. Quanto a invalidação desse cache o próprio mysql já faz também. Uma caracteristica importante é que ele fica armazenado em memória.
Aqui tem um exemplo de uma query que faz mal uso do cache do mysql, alguem sabe dizer por que ?
Não simplesmente por que toda hora o cache é invalidado devido as funções chamadas retornam sempre valores diferentes
Use a versão mais recente possível do PHP, como tem acontecido nas ultimas releases a cada versão o PHP tem ficado mais performático. Temos um problema na comunidade PHP que as aplicações demoram muito para atualizarem seu PHP, é algo simples de ser feito que pode melhorar drasticamente a performance de suas aplicações. Vamos ver alguns benchmarks de diferentes versões do PHP a seguir
Aqui temos um benchmarking do Drupal rodando com PHP 5.3, a performance do PHP é a que está em azul fraco, como vocês podem ver o tipo dela chega a um pouco mais de 300ms para terminar a resposta. E o tempo médio de resposta de toda aplicação é de 573ms
Aqui temos o mesmo site rodando em um PHP 5.5 como vocês podem ver o tempo de resposta do PHP diminuiu cerca de 40%
Use a versão
Desabilite todas extensões PHP que você não está usando. No startup do processo ou da Thread esses módulos já estão consumindo memória, tudo que você puder ganhar que recursos é bem vindo quando se tem muitos acessos. Então se você não precisa de extensões desabilite-as
Você pode fazer um tunning de algumas variaveis do PHP para consumir menos memória, como o memory_limit. Você pode usar as funções memory_get_usage() para pegar quanto tua aplicação ta consumindo de memoria naquele momento, ou o memory_get_peak_usage() para ver quanto é o pico de consumo da sua aplicação. O ideal é você deixar o memory limit o menos possível para consumir menos memória.
tem o realpath_cache_size também que é o cache que o PHP vai fazer de todos os includes, todas pastas que ele vai ter que visitar durante um request durante a vida da sua requisição. A Função realpath cache get você consegue ver o array com tudo que está sendo cacheado.
No Drupal conseguimos ver quanto suas páginas estão consumindo de memória habilitando o módulo devel. Esse módulo é muito bom para o desenvolvimento e escalar sua aplicação.
PHP Accelerators são extensões do PHP , são responsáveis por salvar o código em bitcode, ao invés de toda vez que entrar uma nova requisição você interpretar todo código novamente, eles pegam do cache e não precisam interpretar o código todo novamente, isso aumenta bastante a performance das aplicações
o APC era muito usado antes da versão 5.4 do PHP sair, na versão 5.4 em diante o PHP já vem com o OPCache nativo. OPCache é desenvolvido pela Zend a mesma que mantem o PHP, outra alternativa é o XCache.
opcache.enable serve para habilitar o cache
opcache.memory_consumption serve para colocar o limite máximo de memória que o opcache deve utilizar
opcache.validate_timestamps serve para invalidar os caches se trocar o timestamp do arquivo, caso desabilitado essa função é preciso reiniciar o php para invalidar os caches
opcache.max_accelarated_files é o limite de arquivos PHP que podem ser salvos em cache
Outra ferramenta que podemos utilizar para otimizar nossa aplicação é um cache em memória. Operações custosas podem ser salvas tanto no memcache quando no Redis e ser recuperado muito rápidamente pois os dados ficam todos em memória. Um diferencial do Redis é que você pode salvar os dados em disco também caso necessário. O Drupal já tem módulos contribuidos que substituiem o cache padrão dele para salvar ou no memcache ou no Redis.
Proxy Reverso é uma camada que colocamos na frente do nosso servidor Web, ele serve principalmente para cachear informações estáticas como por exemplo HTML, assets etc. Para entender como usar um proxy reverso é necessário entender os Headers HTTP