Antes de responder a isso, nunca desenvolvi nada popular o suficiente para atingir altas cargas de servidor. Trate-me como (um suspiro) um alienígena que acaba de desembarcar no planeta, apesar de conhecer PHP e algumas técnicas de otimização.
Estou desenvolvendo uma ferramenta em PHP que pode atingir muitos usuários, se funcionar corretamente. No entanto, embora eu seja totalmente capaz de desenvolver o programa, sou praticamente sem noção quando se trata de criar algo que possa lidar com um tráfego enorme. Então, aqui estão algumas perguntas (sinta-se à vontade para transformar essa pergunta também em um encadeamento de recursos).
Bases de dados
No momento, pretendo usar os recursos do MySQLi no PHP5. No entanto, como devo configurar os bancos de dados em relação a usuários e conteúdo? Eu realmente preciso de vários bancos de dados? No momento, tudo se mistura em um banco de dados - embora eu esteja pensando em espalhar dados do usuário para um, conteúdo real para outro e, finalmente, conteúdo principal do site (mestres de modelos etc.) para outro. Meu raciocínio por trás disso é que o envio de consultas para bancos de dados diferentes facilitará a carga neles como um banco de dados = 3 fontes de carregamento. Além disso, isso ainda seria eficaz se todos estivessem no mesmo servidor?
Armazenamento em cache
Eu tenho um sistema de modelo que é usado para criar as páginas e trocar variáveis. Os modelos mestres são armazenados no banco de dados e cada vez que um modelo é chamado, sua cópia em cache (um documento html) é chamada. No momento, tenho dois tipos de variáveis nesses modelos - um var estático e um var dinâmico. Vars estáticos são geralmente coisas como nomes de páginas, o nome do site - coisas que não mudam frequentemente; Vars dinâmicos são coisas que mudam a cada carregamento da página.
Minha pergunta sobre isso:
Digamos que eu tenha comentários sobre diferentes artigos. Qual é uma solução melhor: armazene o modelo de comentário simples e renderize comentários (de uma chamada de banco de dados) toda vez que a página for carregada ou armazene uma cópia em cache da página de comentários como uma página html - sempre que um comentário for adicionado / editado / excluído a página é reconectada.
Finalmente
Alguém tem alguma dica / ponteiro para executar um site de alta carga em PHP. Tenho certeza de que é uma linguagem viável para usar - Facebook e Yahoo! dê uma grande precedência - mas há alguma experiência que eu deveria prestar atenção?
fonte
Respostas:
Não existem dois sites iguais. Você realmente precisa de uma ferramenta como jmeter e benchmark para ver onde estarão os pontos problemáticos. Você pode gastar muito tempo adivinhando e melhorando, mas não verá resultados reais até medir e comparar suas alterações.
Por exemplo, por muitos anos, o cache de consultas do MySQL foi a solução para todos os nossos problemas de desempenho. Se o seu site estiver lento, os especialistas em MySQL sugeriram ativar o cache de consultas. Acontece que, se você tiver uma carga de gravação alta, o cache é realmente prejudicial. Se você o ativasse sem testar, nunca saberia.
E não esqueça que você nunca terminou de dimensionar. Um site que lide com 10req / s precisará de alterações para oferecer suporte a 1000req / s. E se você tiver sorte o suficiente para suportar 10.000req / s, sua arquitetura provavelmente também parecerá completamente diferente.
Bases de dados
Armazenamento em cache
fonte
Sou desenvolvedor líder em um site com mais de 15 milhões de usuários. Tivemos muito poucos problemas de dimensionamento porque planejamos isso com antecedência e dimensionamos cuidadosamente. Aqui estão algumas das estratégias que posso sugerir da minha experiência.
ESQUEMA Primeiramente, desnormalize seus esquemas. Isso significa que, em vez de ter várias tabelas relacionais, você deve optar por ter uma tabela grande. Em geral, as junções são um desperdício de recursos preciosos do banco de dados, porque fazer várias preparações e agrupamento queima as E / Ss do disco. Evite-os quando puder.
A desvantagem aqui é que você armazenará / extrairá dados redundantes, mas isso é aceitável porque os dados e a largura de banda intra-gaiola são muito baratos (discos maiores), enquanto várias E / Ss preparadas são ordens de magnitude mais caras (mais servidores) .
INDEXAÇÃO Certifique-se de que suas consultas utilizem pelo menos um índice. Cuidado, porém, que os índices custarão se você escrever ou atualizar com freqüência. Existem alguns truques experimentais para evitar isso.
Você pode tentar adicionar colunas adicionais não indexadas, que são paralelas às colunas indexadas. Em seguida, você pode ter um processo offline que grava as colunas não indexadas nas colunas indexadas em lotes. Dessa forma, você pode controlar melhor quando o mySQL precisará recalcular o índice.
Evite consultas calculadas como uma praga. Se você precisar calcular uma consulta, tente fazer isso uma vez no momento da gravação.
CACHING Eu recomendo o Memcached. Foi provado pelos maiores players da pilha PHP (Facebook) e é muito flexível. Existem dois métodos para fazer isso: um é o cache da camada de banco de dados, o outro é o cache da camada de lógica de negócios.
A opção da camada do banco de dados exigiria o armazenamento em cache do resultado das consultas recuperadas do banco de dados. Você pode fazer o hash da sua consulta SQL usando md5 () e usá-la como uma chave de pesquisa antes de acessar o banco de dados. A vantagem disso é que é muito fácil de implementar. A desvantagem (dependendo da implementação) é que você perde flexibilidade porque está tratando todos os caches da mesma forma em relação à expiração do cache.
Na loja em que trabalho, usamos o cache da camada de negócios, o que significa que cada classe concreta em nosso sistema controla seu próprio esquema de cache e o tempo limite do cache. Isso funcionou muito bem para nós, mas lembre-se de que os itens recuperados do banco de dados podem não ser os mesmos do cache, portanto, você precisará atualizar o cache e o banco de dados juntos.
SHARDING DE DADOS A replicação apenas leva você até agora. Mais cedo do que o esperado, suas gravações se tornarão um gargalo. Para compensar, certifique-se de oferecer suporte ao compartilhamento de dados o mais cedo possível. Você provavelmente vai querer se matar depois, se não o fizer.
É muito simples de implementar. Basicamente, você deseja separar a autoridade principal do armazenamento de dados. Use um banco de dados global para armazenar um mapeamento entre chaves primárias e IDs de cluster. Você consulta esse mapeamento para obter um cluster e, em seguida, consulta o cluster para obter os dados. Você pode armazenar em cache essa operação de pesquisa, que a tornará insignificante.
A desvantagem disso é que pode ser difícil reunir dados de vários shards. Mas você também pode planejar o seu caminho.
PROCESSAMENTO OFFLINE Não faça o usuário esperar pelo seu back-end, se não for necessário. Crie uma fila de tarefas e mova qualquer processamento que possa ser offline, fazendo-o separado da solicitação do usuário.
fonte
Eu trabalhei em alguns sites que recebem milhões / hits / mês apoiados por PHP e MySQL. Aqui estão alguns princípios básicos:
Eu recomendo a leitura de Construindo sites escaláveis , que foi escrito por um dos engenheiros do Flickr e é uma ótima referência.
Confira também meu post sobre escalabilidade, que possui muitos links para apresentações sobre escalabilidade em vários idiomas e plataformas: http://www.ryandoherty.net/2008/07/13/unicorns-and-scalability/
fonte
Re: DOP / MySQLi / MySQLND
@ gary
Você não pode simplesmente dizer "não use o MySQLi", pois eles têm objetivos diferentes. O PDO é quase como uma camada de abstração (embora não seja realmente) e foi projetado para facilitar o uso de vários produtos de banco de dados, enquanto o MySQLi é específico para conexões do MySQL. É errado dizer que o PDO é a camada de acesso moderna no contexto da comparação com o MySQLi porque sua declaração implica que a progressão foi mysql -> mysqli -> PDO, o que não é o caso.
A escolha entre MySQLi e PDO é simples - se você precisar oferecer suporte a vários produtos de banco de dados, use o PDO. Se você está apenas usando o MySQL, pode escolher entre DOP e MySQLi.
Então, por que você escolheria o MySQLi ao invés do PDO? Ver abaixo...
@ross
Você está certo sobre o MySQLnd, que é a mais nova biblioteca de nível de idioma do MySQL, no entanto, não substitui o MySQLi. O MySQLi (como no PDO) permanece como você interage com o MySQL através do seu código PHP. Ambos usam o libmysql como o cliente C por trás do código PHP. O problema é que o libmysql está fora do mecanismo principal do PHP e é aí que entra o mysqlnd, ou seja, é um driver nativo que faz uso dos principais componentes internos do PHP para maximizar a eficiência, especificamente no que diz respeito ao uso da memória.
O MySQLnd está sendo desenvolvido pelo próprio MySQL e recentemente chegou à filial do PHP 5.3, que está em testes de RC, pronta para ser lançada ainda este ano. Você poderá usar o MySQLnd com o MySQLi ... mas não com o DOP. Isso dará ao MySQLi um aumento de desempenho em muitas áreas (não todas) e a tornará a melhor escolha para a interação do MySQL se você não precisar da abstração, como os recursos do PDO.
Dito isto, o MySQLnd agora está disponível no PHP 5.3 para DOP e, portanto, você pode obter as vantagens dos aprimoramentos de desempenho do ND para o DOP; no entanto, o DOP ainda é uma camada de banco de dados genérica e, portanto, dificilmente poderá se beneficiar tanto as melhorias no ND como o MySQLi pode .
Alguns benchmarks úteis podem ser encontrados aqui, embora sejam de 2006. Você também precisa estar ciente de coisas como esta opção .
Há muitas considerações que precisam ser levadas em consideração ao decidir entre MySQLi e PDO. Na realidade, isso não será importante até que você obtenha números de solicitação rediculamente altos e, nesse caso, faz mais sentido usar uma extensão que foi projetada especificamente para o MySQL, em vez de uma que abstraia as coisas e fornece um driver do MySQL. .
Não é uma questão simples de qual é o melhor, porque cada um tem vantagens e desvantagens. Você precisa ler os links que forneci e ter sua própria decisão, testá-lo e descobrir. Eu usei o PDO em projetos anteriores e é uma boa extensão, mas minha opção pelo desempenho puro seria o MySQLi com a nova opção MySQLND compilada (quando o PHP 5.3 for lançado).
fonte
Geral
Código
Bases de dados
Armazenamento em cache
Diversos
fonte
A APC é uma necessidade absoluta. Não apenas contribui para um ótimo sistema de cache, mas o ganho dos arquivos PHP armazenados em cache automaticamente é uma dádiva de Deus. Quanto à idéia de vários bancos de dados, não acho que você obteria muito com diferentes bancos de dados no mesmo servidor. Isso pode proporcionar um ganho de velocidade durante o tempo de consulta, mas duvido que o esforço necessário para implantar e manter o código para todos os três garanta que eles estejam sincronizados valha a pena.
Também recomendo executar o Xdebug para encontrar gargalos no seu programa. Isso fez da otimização uma brisa para mim.
fonte
Em primeiro lugar, como acho que Knuth disse, "a otimização prematura é a raiz de todo mal". Se você não precisa lidar com esses problemas no momento, não lembre-se de fornecer algo que funcione corretamente primeiro. Dito isto, se as otimizações não puderem esperar.
Tente criar um perfil de suas consultas ao banco de dados, descobrir o que é lento e o que acontece muito e criar uma estratégia de otimização a partir disso.
Eu investigaria o Memcached, pois é o que muitos sites de maior carregamento usam para armazenar em cache de maneira eficiente o conteúdo de todos os tipos, e a interface do objeto PHP a ele é bastante agradável.
Dividir bancos de dados entre servidores e usar algum tipo de técnica de balanceamento de carga (por exemplo, gerar um número aleatório entre 1 e # bancos de dados redundantes com os dados necessários - e usar esse número para determinar a qual servidor de banco de dados se conectar) também pode ser uma excelente maneira de aumentar eficiência.
Tudo isso funcionou muito bem no passado em alguns sites de carga bastante alta. Espero que isso ajude você a começar :-)
fonte
Criar um perfil do seu aplicativo com algo como o Xdebug (como o tj9991 recomendado) definitivamente será obrigatório. Não faz muito sentido apenas otimizar as coisas cegamente. O Xdebug ajudará você a encontrar os gargalos reais em seu código, para que você possa gastar seu tempo de otimização com sabedoria e corrigir trechos de código que estão causando lentidão.
Se você estiver usando o Apache, outro utilitário que pode ajudar nos testes é o Siege . Isso ajudará você a prever como o servidor e o aplicativo reagirão a altas cargas, colocando-o de acordo com o ritmo.
Qualquer tipo de cache de opcode para PHP (como APC ou um dos muitos outros) também ajudará muito.
fonte
Eu administro um site com 7-8 milhões de visualizações de página por mês. Não muito, mas o suficiente para que nosso servidor sentisse a carga. A solução que escolhemos foi simples: o Memcache no nível do banco de dados. Essa solução funciona bem se a carga do banco de dados for o seu principal problema.
Começamos usando o Memcache para armazenar em cache objetos inteiros e os resultados do banco de dados mais usados. Funcionou, mas também introduziu bugs (poderíamos ter evitado alguns deles se tivéssemos sido mais cuidadosos).
Então, mudamos nossa abordagem. Criamos um wrapper de banco de dados (com exatamente os mesmos métodos do nosso banco de dados antigo, para facilitar a troca) e, em seguida, subclassificamos para fornecer métodos de acesso ao banco de dados em cache do memcached.
Agora tudo o que você precisa fazer é decidir se uma consulta pode usar resultados em cache (e possivelmente desatualizados) ou não. A maioria das consultas executadas pelos usuários agora é obtida diretamente do Memcache. As exceções são atualizações e inserções, o que para o site principal acontece apenas por causa do log. Essa medida bastante simples reduziu a carga do servidor em cerca de 80%.
fonte
Pelo que vale a pena, o armazenamento em cache é DIRT SIMPLE no PHP, mesmo sem um pacote de extensão / auxiliar como o memcached.
Tudo que você precisa fazer é criar um buffer de saída usando
ob_start()
.Crie uma função de cache global. Ligar
ob_start
, passe a função como retorno de chamada. Na função, procure uma versão em cache da página. Se existir, sirva e termine.Se não existir, o script continuará o processamento. Quando atingir o ob_end () correspondente, chamará a função que você especificou. Nesse momento, você apenas obtém o conteúdo do buffer de saída, os solta em um arquivo, salva o arquivo e finaliza.
Adicione alguma expiração / coleta de lixo.
E muitas pessoas não percebem que você pode aninhar
ob_start()
/ob_end()
ligar. Portanto, se você já estiver usando um buffer de saída para, digamos, analisar anúncios ou realçar sintaxe ou qualquer outra coisa, basta aninhar outraob_start/ob_end
chamada.fonte
Na verdade, muitos usam APC e memcached juntos ...
fonte
Parece que eu estava errado . O MySQLi ainda está sendo desenvolvido. Mas, de acordo com o artigo, o PDO_MySQL agora está sendo contribuído pela equipe do MySQL. Do artigo:
Para mim, parece que o artigo é tendencioso para o MySQLi. Suponho que sou tendencioso em relação à DOP. Eu realmente gosto de DOP sobre MySQLi. É direto para mim. A API está muito mais próxima de outros idiomas em que eu programei. As interfaces do banco de dados OO parecem funcionar melhor.
Não encontrei nenhum recurso específico do MySQL que não estivesse disponível através do PDO. Eu ficaria surpreso se alguma vez fizesse isso.
fonte
A DOP também é muito lenta e sua API é bastante complicada. Ninguém em sua mente sã deve usá-lo se a portabilidade não for uma preocupação. E vamos ser sinceros, em 99% de todos os aplicativos da web não é. Você apenas segue o MySQL ou o PostrgreSQL, ou o que quer que esteja trabalhando.
Quanto à questão do PHP e o que levar em consideração. Eu acho que a otimização prematura é a raiz de todo mal. ;) Faça seu aplicativo primeiro, tente mantê-lo limpo quando se trata de programação, faça uma pequena documentação e escreva testes de unidade. Com todas as opções acima, você não terá problemas para refatorar o código quando chegar a hora. Mas primeiro você quer fazer e empurre para ver como as pessoas reagem a isso.
fonte
Pdo Claro que é bom, mas não tem sido alguns controvérsia sobre isso de desempenho versus mysql e mysqli, embora pareça corrigido agora.
Você deve usar o pdo se visualizar a portabilidade, mas se não, o mysqli deve ser o caminho. Possui uma interface OO, instruções preparadas e a maior parte do que o pdo oferece (exceto, bem, portabilidade).
Além disso, se o desempenho for realmente necessário, prepare-se para o driver MysqLnd (nativo do mysql) no PHP 5.3, que será muito mais bem integrado ao php, com melhor desempenho e melhor uso da memória (e estatísticas para ajuste de desempenho).
Memcache é bom se você tiver servidores em cluster (e carga semelhante ao YouTube), mas eu testaria a APC primeiro também.
fonte
Muitas respostas boas já foram dadas, mas eu gostaria de apontar para um cache de código de operação alternativo chamado XCache . É criado por um colaborador poderoso.
Além disso, se você precisar balancear a carga do servidor de banco de dados no futuro, o MySQL Proxy poderá muito bem ajudá-lo a conseguir isso.
Ambas as ferramentas devem se conectar a um aplicativo existente com bastante facilidade, para que essa otimização possa ser feita quando você precisar, sem muito trabalho.
fonte
A primeira pergunta é quão grande você realmente espera que seja? E quanto você planeja investir em sua infraestrutura. Como você sente a necessidade de fazer a pergunta aqui, acho que você espera começar pequeno com um orçamento limitado.
O desempenho é irrelevante se o site não estiver disponível. E para disponibilidade, você precisa de escala horizontal. O mínimo que você pode fazer com sensatez é de 2 servidores, ambos rodando apache, php e mysql. Configure um DBMS como escravo do outro. Faça todas as gravações no mestre e todas as leituras no banco de dados local (o que quer que seja) - a menos que, por algum motivo, você precise ler novamente os dados que acabou de ler (use o mestre). Certifique-se de ter as máquinas instaladas para promover automaticamente o escravo e cercar o mestre. Use o DNS round-robin para os endereços do servidor da web para dar mais afinidade ao nó escravo.
Particionar seus dados em diferentes nós do banco de dados neste estágio é uma péssima idéia - no entanto, convém dividi-lo em diferentes bancos de dados no mesmo servidor (o que facilitará o particionamento entre os nós quando você ultrapassar o facebook).
Verifique se você possui as ferramentas de monitoramento e análise de dados para medir o desempenho de seus sites e identificar gargalos. A maioria dos problemas de desempenho pode ser corrigida escrevendo melhor SQL / corrigindo o esquema do banco de dados.
Manter o cache do modelo no banco de dados é uma idéia idiota - o banco de dados deve ser um repositório comum central para dados estruturados. Mantenha o cache do modelo no sistema de arquivos local dos servidores da Web - ele estará disponível mais rapidamente e não diminuirá o acesso ao banco de dados.
Use um cache de código operacional.
Gaste bastante tempo estudando seu site e seus logs para entender por que está indo tão devagar.
Envie o máximo de cache possível para o cliente.
Use mod_gzip para compactar tudo o que puder.
C.
fonte
Meu primeiro conselho é pensar sobre esse problema e mantê-lo em mente ao criar o site, mas não exagere . Muitas vezes, é difícil prever o sucesso de um novo site, e é melhor gastar seu tempo acordando cedo e otimizando-o mais tarde.
Em geral, o Simple é rápido . Modelos atrasam você. Bancos de dados atrasam você. Bibliotecas complexas tornam você lento. Estratificando modelos, recuperando-os de bancos de dados e analisando-os em uma biblioteca complexa -> os atrasos se multiplicam.
Depois de instalar e executar o site básico, faça testes para mostrar onde gastar seus esforços. É difícil ver onde segmentar. Frequentemente, para acelerar as coisas, você terá que desvendar a complexidade do código, o que torna maior e mais difícil a manutenção, portanto, você só deseja fazê-lo quando necessário.
Na minha experiência, o estabelecimento da conexão com o banco de dados era relativamente caro. Se você conseguir se safar, não conecte-se ao banco de dados para visitantes em geral nas páginas com mais tráfego, como a primeira página do site. Criar várias conexões com o banco de dados é loucura, com muito pouco benefício.
fonte
@ Gary
No momento, estou analisando a DOP e parece que você está certo - no entanto, eu sei que o MySQL está desenvolvendo a extensão MySQLd para PHP - acho que para ter sucesso no MySQL ou no MySQLi - o que você acha disso?
@ Ryan , Eric , tj9991
Obrigado pelo conselho sobre as extensões de cache do PHP - você poderia explicar os motivos para usar um sobre o outro? Ouvi ótimas coisas sobre memcached no IRC, mas nunca ouvi falar da APC - quais são suas opiniões sobre eles? Suponho que o uso de vários sistemas de cache seja bastante contra-eficaz.
Definitivamente, estarei escolhendo alguns testadores de perfil - muito obrigado por suas recomendações sobre eles.
fonte
Não me vejo mudando do MySQL tão cedo - então acho que não preciso dos recursos de abstração do PDO. Obrigado por esses artigos DavidM, eles me ajudaram muito.
fonte
Veja mod_cache , um cache de saída para o servidor da web Apache, semelhante ao cache de saída no ASP.NET.
Sim, posso ver que ainda é experimental, mas será final algum dia.
fonte
Não acredito que ninguém já tenha mencionado isso: Modularização e Abstração. Se você acha que seu site terá que crescer para muitas máquinas, você deve projetá-lo para que ele possa! Isso significa coisas estúpidas, como não suponha que o banco de dados esteja no host local. Isso também significa coisas que serão um incômodo no começo, como escrever uma camada de abstração de banco de dados (como DOP, mas muito mais leve porque ela faz apenas o que você precisa).
E isso significa coisas como trabalhar com uma estrutura. Você precisará de camadas no seu código para poder obter desempenho posteriormente, refatorando a camada de abstração de dados, por exemplo, ensinando que alguns objetos estão em um banco de dados diferente - e o código não precisa saber ou se importar .
Por fim, tenha cuidado com operações que consomem muita memória, por exemplo, cópia desnecessária de cadeias. Se você puder manter o uso da memória do PHP baixo, obterá mais desempenho do seu servidor da web e isso é algo que aumentará quando você usar uma solução com balanceamento de carga.
fonte
Se você estiver trabalhando com grandes quantidades de dados e o cache não estiver cortando, consulte o Sphinx. Tivemos ótimos resultados com o uso do SphinxSearch, não apenas para uma melhor pesquisa de texto, mas também como uma substituição de recuperação de dados para o MySQL ao lidar com tabelas maiores. Se você usa o SphinxSE (plug-in MySQL), ele supera nossos ganhos de desempenho que obtivemos com o cache várias vezes, e a implementação de aplicativos é um sinch.
fonte
Os pontos destacados sobre o cache são imediatos; é a parte menos complicada e mais importante da construção de um aplicativo eficiente. Gostaria de acrescentar que, embora o memcached seja ótimo, a APC é cerca de cinco vezes mais rápida se o aplicativo estiver em um único servidor.
A publicação "Comparação de desempenho de cache" no blog de desempenho do MySQL tem alguns benchmarks interessantes sobre o assunto - http://www.mysqlperformanceblog.com/2006/08/09/cache-performance-comparison/ .
fonte