Como escalar o php5 + MySQL acima de 200 pedidos / segundo?

15

Estou aprimorando minha página inicial para desempenho, atualmente lida com cerca de 200 solicitações / segundo em 3.14.by que consome 6 consultas SQL e 20 req / segundo em 3.14.by/forum, que é o fórum phpBB.

Curiosamente, os números são praticamente os mesmos em alguns servidores VPS e Atom 330 dedicados.

O software do servidor é o seguinte: Apache2 + mod_php prefork 4 childs (tentou números diferentes aqui), php5, APC, nginx, memcached para armazenamento de sessões PHP.

O MySQL está configurado para comer cerca de 30% da RAM disponível (~ 150Mb no VPS, 700Mb no servidor dedicado)

Isso parece que há um gargalo em algum lugar que não me permite ir mais alto, alguma sugestão? (Ou seja, sei que fazer menos de 6 SQLs tornaria mais rápido, mas isso não parece um fator limitante, já que o sqld não consome mais do que alguns% no topo devido a consultas armazenadas em cache)

Alguém já testou o kicking do apache2 e deixando apenas o nginx + php é muito mais rápido?

Mais alguns testes de desempenho

Small 40-byte static file: 1484 r/s via nginx+apache2, 2452 if we talk to apache2 directly. 
Small "Hello world" php script: 458 r/s via ngin+apache2.

Atualização: Parece gargalo é o desempenho do MySQL em dados em cache. Página com SQL único mostra 354req / seg, com 6 SQL's - 180 req / seg. O que você acha que eu posso ajustar aqui? (Eu posso desembolsar 100-200 Mb para o MySQL)

[client]
port        = 3306
socket      = /var/run/mysqld/mysqld.sock

[mysqld_safe]
socket      = /var/run/mysqld/mysqld.sock
nice        = 0

[mysqld]
default-character-set=cp1251
collation-server=cp1251_general_cs

skip-character-set-client-handshake

user        = mysql
pid-file    = /var/run/mysqld/mysqld.pid
socket      = /var/run/mysqld/mysqld.sock
port        = 3306
basedir     = /usr
datadir     = /var/lib/mysql
tmpdir      = /tmp
skip-external-locking

bind-address        = 127.0.0.1

key_buffer      = 16M
max_allowed_packet  = 8M
thread_stack        = 64K
thread_cache_size   = 16
sort_buffer_size    = 8M
read_buffer_size    = 1M

myisam-recover      = BACKUP
max_connections        = 650
table_cache            = 256
thread_concurrency     = 10

query_cache_limit       = 1M
query_cache_size        = 16M

expire_logs_days    = 10
max_binlog_size         = 100M

[mysqldump]
quick
quote-names
max_allowed_packet  = 8M

[mysql]
[isamchk]
key_buffer      = 8M

!includedir /etc/mysql/conf.d/
    
por BarsMonster 16.02.2010 / 01:02

8 respostas

27

Obviamente, há muita coisa que você pode tentar. Sua melhor aposta é perseguir seus logs para consultas que não usam índices (habilitar logs para esses) e outras consultas não otimizadas. Eu compilei uma lista enorme de opções relacionadas ao desempenho ao longo dos anos, então eu incluí um pequeno subconjunto aqui para sua informação - espero que ajude. Aqui estão algumas notas gerais para coisas que você pode experimentar (se você ainda não o fez):

MySQL

  • query_cache_type = 1 - o cache de consultas SQL está ativado. Se definido como 2, as consultas serão armazenadas somente em cache se a dica SQL_CACHE for passada para elas. Da mesma forma com o tipo 1, você pode desativar o cache para uma consulta específica com a dica SQL_NO_CACHE
  • key_buffer_size = 128M (padrão: 8M) - buffer de memória para índices de tabela MyISAM. Em servidores dedicados, tente definir o key_buffer_size para pelo menos um quarto, mas não mais que a metade, da quantidade total de memória no servidor
  • query_cache_size = 64M (padrão: 0) - tamanho do cache de consulta
  • back_log = 100 (padrão: 50, max: 65535) - A fila de solicitações de conexão pendentes. Só importa quando há muitas conexões em pouco tempo
  • join_buffer_size = 1M (padrão: 131072) - um buffer usado quando há varreduras de tabela completas (sem índices)
  • table_cache = 2048 (padrão: 256) - deve ser max_user_connections multiplicado pelo número máximo de JOINs que sua consulta SQL mais pesada contém. Use a variável "open_tables" nos horários de pico como um guia. Veja também a variável "open_tables" - ela deve estar perto de "open_tables"
  • query_prealloc_size = 32K (padrão: 8K) - memória persistente para análise e execução de instruções. Aumente se tiver consultas complexas
  • sort_buffer_size = 16M (padrão: 2M) - ajuda na classificação (operações ORDER BY e GROUP BY)
  • read_buffer_size = 2M (padrão: 128K) - Ajuda com varreduras sequenciais. Aumente se houver muitas varreduras sequenciais.
  • read_rnd_buffer_size = 4M - ajuda a mesa MyISAM a acelerar a leitura após a ordenação
  • max_length_for_sort_data - tamanho da linha a ser armazenada em vez do ponteiro da linha no arquivo de classificação. Pode evitar leituras aleatórias de tabelas
  • key_cache_age_threshold = 3000 (padrão: 300) - hora de manter o cache de chaves na zona quente (antes de ser rebaixado para quente)
  • key_cache_division_limit = 50 (padrão: 100) - ativa um mecanismo de remoção de cache mais sofisticado (dois níveis). Indica a porcentagem a ser mantida no nível inferior. delay_key_write = ALL - o buffer de chaves não é liberado para a tabela em todas as atualizações de índice, mas somente quando a tabela é fechada. Isso acelera muito as gravações nas teclas, mas se você usar esse recurso, você deve adicionar verificação automática de todas as tabelas MyISAM iniciando o servidor com a opção --myisam-recover = BACKUP, FORCE
  • memlock = 1 - bloqueia o processo na memória (para reduzir a troca / saída)

Apache

  • altera o método de desova (para mpm por exemplo)
  • desativar registros, se possível
  • AllowOverride Nenhum - sempre que possível desative o .htaccess. Ele pára o apache para procurar por arquivos .htaccess se eles não forem usados, então salva uma solicitação de pesquisa de arquivo
  • SendBufferSize - Defina como padrão do sistema operacional. Em redes congestionadas, você deve definir esse parâmetro próximo ao tamanho do maior arquivo normalmente baixado
  • Manter ativo desativado (padrão ativado) - e instalar permanentemente para fechar adequadamente as conexões de rede e é mais rápido
  • DirectoryIndex index.php - Mantenha a lista de arquivos o mais curta e absoluta possível.
  • Opções FollowSymLinks - para simplificar o processo de acesso a arquivos no Apache
  • Evite usar mod_rewrite ou pelo menos regexs complexos
  • ServerToken = prod

PHP

  • variables_order="GPCS" (Se você não precisa de variáveis de ambiente)
  • register_globals = Off - além de ser um risco de segurança, também tem um impacto no desempenho
  • Mantenha o include_path o mais minimalista possível (evita consultas extras ao sistema de arquivos)
  • display_errors = Off - Desativa a exibição de erros. strongmente recomendado para todos os servidores de produção (não exibe mensagens de erro feias em caso de problemas).
  • magic_quotes_gpc = Desligado
  • magic_quotes _ * = desativado
  • output_buffering = Ativado
  • Desativar o registro, se possível
  • expose_php = desativado
  • register_argc_argv = desativado
  • always_populate_raw_post_data = desativado
  • coloque o arquivo php.ini onde o php o procuraria primeiro.
  • session.gc_divisor = 1000 ou 10000
  • session.save_path="N; / path" - Para sites grandes, considere usá-lo. Divide arquivos de sessão em subdiretórios

OS Tweaks

  • Monte discos rígidos usados com a opção -o noatime (sem tempo de acesso). Adicione também esta opção ao arquivo / etc / fstab.
  • Ajuste o / proc / sys / vm / swappiness (de 0 a 100) para ver o que tem melhores resultados
  • Use Discos RAM - mount --bind -ttmpfs / tmp / tmp
por 22.02.2010 / 22:58
1

Se o gargalo não é CPU, então seu IO - seja rede ou disco. Então, você precisa ver quanto IO está acontecendo. Eu não teria pensado que é a rede (a menos que você esteja em um link half-duplex de 10mbps, mas vale a pena verificar o switch em caso de detecção automática não está fazendo o seu trabalho direito).

Isso deixa o disco IO, o que pode ser um grande fator, especialmente em VPSs. Use o sar ou o iostat para dar uma olhada nos discos e, em seguida, procure no Google como encontrar mais detalhes se o seu disco estiver sendo muito usado.

    
por 16.02.2010 / 01:10
1

Eu procuraria no cache com Nginx ( memcached ) ou Verniz .

No mínimo, você deve armazenar arquivos estáticos no servidor com Nginx como o SaveTheRbtz.

    
por 17.02.2010 / 09:02
1

Como o servidor não parece ser problema, talvez o gerador de carga seja. Tente executá-lo em várias máquinas.

    
por 17.02.2010 / 09:18
1

Parece-me que você pode estar atingindo a quantidade máxima de conexões que o Apache permite. Dê uma olhada em sua configuração do Apache. Aumentar o limite do servidor e o máximo de clientes deve ajudar se você ainda não estiver limitado por algum outro limite, como E / S ou memória. Veja os valores presentes para mpm_prefork_module ou mpm_worker_module e ajuste de acordo para atender às suas necessidades.

ServerLimit 512
MaxClients 512
    
por 17.02.2010 / 23:03
0

Esta carga é gerada por uma ferramenta ou por cargas do mundo real?

Você pode querer verificar o memcached. Eu vi problemas em altas taxas de conexão causando latência no aplicativo.

Se estiver usando um gerador de carga, o que você ganha ao acessar uma pequena página estática?

Durante as cargas, você pode querer verificar a pilha da rede para as condições de TIME_WAIT. Talvez você esteja preenchendo sua fila de conexão.

Há mais de 100 motivos e itens que você pode ver, mas sem mais informações. Estou apenas jogando suposições neste momento.

    
por 18.02.2010 / 04:56
-1

99% por cento dos problemas de tempo como este serão rastreados até o banco de dados. Certifique-se de que seus índices de acerto são os primeiros de todos. Se isso não funcionar, comece a colocar em cache tudo o que puder.

    
por 22.02.2010 / 20:45
-1

Eu recomendo que você use (se possível) um pool de conexão para manter o banco de dados conectado às suas aplicações web (não precisa se reconectar a cada requisição). Isso pode fazer uma enorme diferença de velocidade.

Além disso, tente analisar todas as suas consultas com o EXPLAIN (e por que não analisar suas consultas com o SHOW PROFILE?).

    
por 22.02.2010 / 20:55