Uma instalação do MySQL 5.6.10 em um Ubuntu 12.04 virtualizado está exibindo uma enorme sobrecarga de memória. O processo mysqld reivindica toda a memória disponível dentro de algumas horas de uptime e força o host a trocar:
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
16229 mysql 20 0 26.8g 21g 8736 S 42 93.4 37:23.22 mysqld
Ele cresceu até 50 GB uma vez e, portanto, superou significativamente o próprio conjunto de dados:
Current InnoDB index space = 5.25 G
Current InnoDB data space = 23.07 G
Normalmente, consigo liberar ~ 3 GB emitindo FLUSH TABLES
, embora seja consideravelmente mais rápido apenas kill -9
o processo mysql, reiniciá-lo e executar a recuperação do InnoDB. As tabelas usadas são quase exclusivamente InnoDB, o innodb_buffer_pool_size foi definido para 5 GB (depois de configurá-lo para 16 GB rapidamente esgotou a memória física disponível e trocou mais de 18 GB dela).
Enquanto o sistema estava trocando, pude observar números bastante altos para contadores de "troca" (vmstat está mostrando ~ 1k páginas/segundo durante rajadas) e quase nada foi trocado de volta (algumas dezenas de páginas por minuto). Suspeitei primeiro de vazamento de memória, mas não encontrei nada que apoiasse essa hipótese até agora.
SHOW INNODB STATUS indica que o buffer pool está apenas parcialmente preenchido:
----------------------
BUFFER POOL AND MEMORY
----------------------
Total memory allocated 5365825536; in additional pool allocated 0
Dictionary memory allocated 2558496
Buffer pool size 320000
Free buffers 173229
Database pages 142239
Old database pages 52663
Modified db pages 344
Pending reads 1
Pending writes: LRU 0, flush list 1 single page 0
Pages made young 34, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 141851, created 387, written 41126
81.16 reads/s, 0.00 creates/s, 0.39 writes/s
Buffer pool hit rate 998 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 142239, unzip_LRU len: 0
I/O sum[0]:cur[464], unzip sum[0]:cur[0]
O servidor tem um total de 80-90 conexões, a maioria das quais relatadas como estando no estado "Sleep" por SHOW PROCESSLIST.
As opções sensíveis à memória definidas são
max_allowed_packet = 16M
thread_stack = 192K
thread_cache_size = 8
max_connections = 1000
innodb_file_format = Barracuda
innodb_buffer_pool_size = 5000M
innodb_log_file_size = 256M
innodb_flush_method = O_DIRECT
query_cache_limit = 1M
query_cache_size = 256M
join_buffer_size = 256k
tmp_table_size = 2M
max_heap_table_size = 64M
O script tuning-primer.sh calcula valores sensatos para uso de memória:
MEMORY USAGE
Max Memory Ever Allocated : 5.27 G
Configured Max Per-thread Buffers : 1.92 G
Configured Max Global Buffers : 5.15 G
Configured Max Memory Limit : 7.07 G
Physical Memory : 22.98 G
Max memory limit seem to be within acceptable norms
Binlog está ativado e o host tem um escravo de replicação anexado a ele (embora os resultados não tenham sido tão diferentes no momento, esse não foi o caso). Innodb_file_per_table é ativado por padrão em 5.6 e os bancos de dados estão hospedando um total de aproximadamente 1.300 tabelas.
Que meios tenho para identificar as possíveis causas do crescimento aparentemente ilimitado?
Depois de ler "Como o MySQL usa a memória" , suspeitei que as tabelas temporárias poderiam ser as culpadas. Se eles não estiverem sendo liberados corretamente por qualquer motivo, eles podem se acumular rapidamente. O aplicativo que consulta o banco de dados emite muitas consultas aninhadas e complicadas, portanto, as tabelas temporárias seriam muito usadas de acordo com os documentos referenciados. Eu tentei verificar se matar / redefinir conexões existentes (ociosas) reduziria significativamente o uso de memória quando o mysqld atingiu ~ 20 GB - não, então isso não está relacionado aos estados de conexão ou a memória está vazando de uma maneira que ser afetado pelo fechamento da conexão.
Como eu verificaria se as tabelas temporárias na memória estão ocupando uma quantidade significativa de memória? As variáveis STATUS e o INFORMATION_SCHEMA parecem não ter essa informação.
O uso de memória do MySQL parece difícil de depurar - os contadores disponíveis parecem não contabilizar a maior parte do uso que estou vendo. Eu posso estar perdendo alguma coisa, no entanto.
Eu também tenho um escravo de replicação baseado em MyISAM anexado ao mestre InnoDB recebendo cargas semelhantes (somente leitura) - ele não mostra nenhum sinal de uso excessivo de memória (mysqld RSS é continuamente < 1 GB), então o problema parece ser específico para a configuração do InnoDB.
Um bug registrado aqui ( http://bugs.mysql.com/bug.php?id=68287 ) parece ser potencialmente relevante - verifique qual table_definition_cache está configurado executando:
Testes com a versão atual do GA MySQL 5.6.19 revelaram que o problema desapareceu.
Lendo as notas de versão de versões intermediárias, observei esta nota específica em 5.6.14 que suspeito estar relacionada ao nosso problema, pois se refere explicitamente a cláusulas de subconsulta que estão em uso excessivo em nosso caso:
Infelizmente, a Oracle não está publicando bugs, portanto, esses são todos os detalhes técnicos que podemos obter sobre o problema.