A utilização elevada da CPU numa instância pode ser causada por vários motivos, como um aumento nas cargas de trabalho, transações pesadas, consultas lentas e transações de longa duração.
O recomendador de instâncias com aprovisionamento insuficiente analisa a utilização da CPU. Se os níveis de utilização da CPU estiverem iguais ou superiores a 95% durante um período significativo nos últimos 30 dias, o motor de recomendações envia-lhe um alerta e fornece estatísticas adicionais para ajudar a resolver o problema.
Este documento explica como rever e otimizar uma instância do Cloud SQL para MySQL se essa instância for identificada pelo recomendador de instâncias com aprovisionamento insuficiente como tendo uma utilização elevada da CPU.
Use as estatísticas de consultas para identificar consultas com um elevado consumo da CPU
As estatísticas de consultas ajudam a detetar, diagnosticar e evitar problemas de desempenho das consultas que possam causar um elevado consumo de CPU para bases de dados do Cloud SQL.
Use a auditoria da base de dados MySQL
Use a auditoria da base de dados MySQL para ver a memória e o consumo da sua instância.
Recomendações
A utilização da CPU aumenta proporcionalmente com a carga de trabalho. Para reduzir a utilização da CPU, verifique as consultas em execução e otimize-as. Seguem-se alguns passos para verificar o consumo da CPU.
Consulte
Threads_running
eThreads_connected
Use a seguinte consulta para ver o número de discussões ativas:
> SHOW STATUS like 'Threads_%';
Threads_running
é um subconjunto deThreads_connected
. Os restantes threads estão inativos. Um aumento noThreads_running
contribui para um aumento na utilização da CPU. É recomendável verificar o que está a ser executado nesses threads.Verifique os estados das consultas
Execute o comando
SHOW PROCESSLIST
para ver as consultas em curso. Devolve todas as threads ligadas por ordem e a respetiva declaração SQL em execução ativa.mysql> SHOW [FULL] PROCESSLIST;
Preste atenção às colunas de estado e duração. Verifique se existem muitas consultas bloqueadas no mesmo estado.
- Se muitos threads apresentarem
Updating
, pode haver contenção de bloqueio de registo. Consulte o passo seguinte. - Se muitos threads apresentarem
Waiting
para o bloqueio de metadados da tabela, verifique a consulta para saber a tabela e, em seguida, procure um DDL (comoALTER TABLE
) que possa manter o bloqueio de metadados. Uma DDL também pode estar à espera de um bloqueio de metadados da tabela se uma consulta inicial, como umSELECT query
de execução prolongada, a estiver a reter.
- Se muitos threads apresentarem
Verifique a existência de contestações de bloqueio de registos
Quando as transações retêm bloqueios em registos de índice populares, bloqueiam outras transações que pedem os mesmos bloqueios. Isto pode gerar um efeito em cadeia e fazer com que vários pedidos fiquem bloqueados, bem como aumentar o valor de
Threads_running
. Para diagnosticar a contenção de bloqueios, use a tabelainformation_schema.innodb_lock_waits
.A consulta seguinte lista cada transação de bloqueio e os números de transações bloqueadas associadas.
SELECT t.trx_id, t.trx_state, t.trx_started, COUNT(distinct w.requesting_trx_id) AS blocked_trxs FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx t ON t.trx_id = w.blocking_trx_id GROUP BY t.trx_id,t.trx_state, t.trx_started ORDER BY t.trx_id;
Tanto um único DML grande como muitos DMLs pequenos simultâneos podem causar contestações de bloqueio de linhas. Pode otimizar esta situação do lado da aplicação através dos seguintes passos:
- Evite transações longas, uma vez que os bloqueios de linhas são mantidos até ao fim da transação.
- Divida um único DML grande em DMLs mais pequenos.
- Agrupe uma única linha DML em pequenos blocos.
- Minimize a contenção entre threads; por exemplo, se o código da aplicação usar um conjunto de ligações, atribua um intervalo de IDs ao mesmo thread.
Encontre transações de longa duração
Usar
SHOW ENGINE INNODB STATUS
Na secção TRANSAÇÕES, pode ver todas as transações em aberto ordenadas da mais antiga para a mais recente.
mysql> SHOW ENGINE INNODB STATUS\G …… ------------ TRANSACTIONS ------------ … ---TRANSACTION 245762, ACTIVE 262 sec 2 lock struct(s), heap size 1136, 1 row lock(s), undo log entries 1 MySQL thread id 9210, OS thread handle 140262286128896, query id 202218 localhost root
Comece pelas transações mais antigas e encontre respostas às seguintes perguntas:
- Há quanto tempo é que estas transações estão em execução?
- Quantas estruturas de bloqueio e bloqueios de linhas estão presentes?
- Quantas entradas de registo de anulação existem?
- Quais são os anfitriões e os utilizadores que estão a estabelecer ligação?
- Qual é a declaração SQL em curso?
Usar
information_schema.innodb_trx
Se
SHOW ENGINE INNODB STATUS
tiver sido truncado, uma forma alternativa de examinar todas as transações abertas é usar a tabelainformation_schema.innodb_trx
:SELECT trx_id, trx_state, timestampdiff(second, trx_started, now()) AS active_secs, timestampdiff(second, trx_wait_started, now()) AS wait_secs, trx_tables_in_use, trx_tables_locked, trx_lock_structs, trx_rows_locked, trx_rows_modified, trx_query FROM information_schema.innodb_trx
Se as transações mostrarem as declarações de execução prolongada atuais, pode decidir parar estas transações para reduzir a pressão sobre o servidor ou aguardar que as transações críticas sejam concluídas. Se as transações mais antigas não apresentarem atividades, avance para o passo seguinte para encontrar o histórico de transações.
Verifique as declarações SQL das transações de execução prolongada
Usar
performance_schema
Para usar o
performance_schema
, tem de o ativar primeiro. É uma alteração que requer o reinício de uma instância. Depois deperformance_schema
estar ativado, verifique se os instrumentos e os consumidores estão ativados:SELECT * FROM setup_consumers where name like 'events_statements_history'; SELECT * FROM setup_instruments where name like 'statement/sql/%';
Se não estiverem ativadas, ative-as:
UPDATE setup_instruments SET ENABLED = 'YES', timed = 'YES' WHERE NAME LIKE 'statement/%'; UPDATE setup_consumers SET ENABLED = 'YES' WHERE NAME LIKE 'events_statements%';
Por predefinição, cada thread mantém os últimos 10 eventos definidos por
performance_schema_events_statements_history_size
. Geralmente, são suficientes para localizar a transação no código da aplicação. Este parâmetro não é dinâmico.Com o
mysql thread id
, que éprocesslist_id
, consulte os eventos do histórico:SELECT t.thread_id, event_name, sql_text, rows_affected, rows_examined, processlist_id, processlist_time, processlist_state FROM events_statements_history h INNER JOIN threads t ON h.thread_id = t.thread_id WHERE processlist_id = <mysql thread id> ORDER BY event_id;
Use o registo de consultas lentas
Para a depuração, pode capturar todas as consultas que demoraram mais de
N
segundos no registo de consultas lentas. Pode ativar os registos de consultas lentas editando as definições da instância na página da instância daGoogle Cloud consola ougcloud CLI
e, em seguida, ver os registos através do visualizador de registos naGoogle Cloud consola ougloud CLI
.
Verifique a contenção de semáforos
Num ambiente concorrente, o mutex e o bloqueio de leitura/escrita em recursos partilhados podem ser o ponto de contenção, o que abranda o desempenho do servidor. Além disso, se o tempo de espera do semáforo for superior a 600 segundos, o sistema pode falhar para sair do impasse.
Para ver a contenção de semáforos, use o seguinte comando:
mysql> SHOW ENGINE INNODB STATUS\G ---------- SEMAPHORES ---------- ... --Thread 140396021667584 has waited at row0purge.cc line 862 for 241.00 seconds the semaphore: S-lock on RW-latch at 0x30c03e8 created in file dict0dict.cc line 1183 a writer (thread id 140395996489472) has reserved it in mode exclusive number of readers 0, waiters flag 1, lock_word: 0 Last time read locked in file row0purge.cc line 862 Last time write locked in file /build/mysql-5.7-FFKPr6/mysql-5.7-5.7.22/storage/innobase/dict/dict0stats.cc line 2376 ...
Com cada espera de semáforo, a primeira linha mostra a thread que está à espera, o semáforo específico e o tempo que esperou. Se houver esperas de semáforo frequentes quando executa repetidamente
SHOW ENGINE INNODB STATUS
, especialmente esperas de mais de alguns segundos, significa que o sistema está a deparar-se com gargalos de concorrência.Existem diferentes pontos de contenção em diferentes cargas de trabalho e configurações.
Quando os semáforos estão frequentemente em btr0sea.c, a indexação hash adaptativa pode ser a origem da contenção. Experimente desativá-lo através da Google Cloud consola ou
gcloud CLI
.Otimize as consultas longas
SELECT
Primeiro, reveja a consulta. Identificar o objetivo da consulta e a melhor forma de obter os resultados. O melhor plano de consulta é o que minimiza o acesso aos dados.
- Verifique o plano de execução da consulta:
mysql> EXPLAIN <the query>;
Consulte a documentação do MySQL para saber como interpretar o resultado e avaliar a eficiência da consulta.
- Use o índice certo
Verifique a coluna da chave para ver se é usado o índice esperado. Caso contrário, atualize as estatísticas do índice:
mysql> analyze table <table_name>
Aumentar o número de páginas de amostra usadas para calcular as estatísticas do índice. Para saber mais, consulte a documentação do MySQL.
- Tire o máximo partido do índice
Quando usar um índice de várias colunas, verifique as colunas
key_len
para ver se o índice é totalmente usado para filtrar os registos. As colunas mais à esquerda têm de ser comparações iguais, e o índice pode ser usado até à primeira condição de intervalo, inclusive.- Use sugestões do otimizador
Outra forma de garantir que é usado o índice correto é aplicar a sugestão de índice e a sugestão para a ordem de junção de tabelas.
Evite uma longa lista de histórico com READ COMMITTED
A lista de histórico é a lista de transações não anuladas no espaço de tabelas de anulação. O nível de isolamento predefinido de uma transação é
REPEATABLE READ
, que requer que uma transação leia a mesma imagem instantânea durante toda a sua duração. Assim, uma consultaSELECT
bloqueia a limpeza dos registos do histórico de anulação feitos desde que a consulta (ou a transação) foi iniciada. Uma lista de histórico longa retarda o desempenho das consultas. Uma forma de evitar a criação de uma longa lista de histórico é alterar o nível de isolamento da transação paraREAD COMMITTED
. Com oREAD COMMITTED
, já não é necessário manter a lista de histórico para uma vista de leitura consistente. Pode alterar o nível de isolamento da transação globalmente para todas as sessões, para uma única sessão ou para a próxima transação única. Para saber mais, consulte a documentação do MySQL.Ajuste a configuração do servidor
Há muito a dizer sobre a configuração do servidor. Embora a história completa esteja fora do âmbito deste documento, vale a pena mencionar que o servidor também comunica várias variáveis de estado que dão indicações sobre o desempenho das configurações relacionadas. Por exemplo:
- Ajuste
thread_cache_size
seThreads_created/Connections
for grande. Uma cache de threads adequada reduz o tempo de criação de threads e ajuda a carga de trabalho altamente concorrente. - Ajuste
table_open_cache
seTable_open_cache_misses/Table_open_cache_hits
não for trivial. Ter tabelas na cache de tabelas poupa tempo de execução de consultas e pode fazer a diferença num ambiente altamente concorrencial.
- Ajuste
Termine uma associação indesejada
Pode parar a consulta se esta parecer inválida ou já não for necessária. Para saber como identificar e terminar a discussão do MySQL, consulte o artigo Faça a gestão das ligações à base de dados.
Por último, se a utilização da CPU continuar elevada e as consultas formarem tráfego necessário, considere aumentar os recursos da CPU na sua instância para evitar falhas ou indisponibilidade da base de dados.