Se eu usar o mysqldump --single-transaction, de acordo com os documentos, ele deve liberar tabelas com bloqueio de leitura para obter um estado consistente e iniciar uma transação e nenhum gravador deve estar esperando.
No entanto, eu peguei a seguinte situação ontem à noite:
trecho de show full processlist:
centenas desses ...
Command: Query
Time: 291
State: Waiting for table flush
Info: insert into db_external_notification.....
então isso:
Command: Query
Time: 1204
State: Sending data
Info: SELECT /*!40001 SQL_NO_CACHE */ * FROM `db_external_notification`
e o restante dos threads estão no modo de suspensão
alguém tem alguma idéia do que essas inserções estão esperando? Não vejo nenhuma tabela FLUSH ou DDL ou qualquer coisa mencionada no manual que possa causar a espera das consultas.
comando completo do mysqldump
mysqldump --quick --add-drop-table --single-transaction --master-data=2 -uxx -pxx dbname
Eu acho que - rápido é redundante aqui, provavelmente sobra de épocas anteriores, esse script é muito antigo, mas não deve prejudicar nada
mysqldump
? Em particular, você está usando--flush-logs
ou--master-data
...? Existem possíveis interações entre as opções.Respostas:
A opção --single-transaction do mysqldump não funciona
FLUSH TABLES WITH READ LOCK;
. Isso faz com que o mysqldump configure uma transação de leitura repetível para todas as tabelas que estão sendo despejadas.Na sua pergunta, você declarou que o SELECT do mysqldump para a
db_external_notification
tabela está mantendo centenas de comandos INSERT na mesma tabela. Por que isso está acontecendo ?A coisa mais provável é um bloqueio no gen_clust_index (mais conhecido como Índice Clusterizado). Esse paradigma faz com que dados e páginas de índice coexistam. Essas páginas de índice são baseadas no índice PRIMARY KEY ou no RowID gerado automaticamente (no caso de não haver PRIMARY KEY).
Você poderá identificar isso executando
SHOW ENGINE INNODB STATUS\G
e procurar por qualquer página do gen_clust_index que possua um bloqueio exclusivo. A inserção de INSERTs em uma tabela com um Índice de Cluster exige um bloqueio exclusivo para manipular o BTREE da PRIMARY KEY, bem como a serialização do incremento automático.Eu já discuti esse fenômeno antes
Aug 08, 2011
: Os InnoDB Deadlocks são exclusivos para INSERT / UPDATE / DELETE?Dec 22, 2011
: Impasse no MySQL - não é possível reiniciar normalmente?Dec 13, 2012
: MySQL InnoDB bloqueia chave primária na exclusão mesmo em READ COMMITTEDUPDATE 2014-07-21 15:03 EDT
Veja as linhas 614-617 do seu PastBin
Observe que a linha 617 diz
O que isso me diz? Você tem uma PRIMARY KEY com um auto_increment ativado
id
.Seu máximo
id
para a tabeladb_external_notification
era menor do que1252538391
quando o mysqldump foi lançado. Quando você subtrai1252538391
de1252538405
, isso significa que 14 ou mais comandos INSERT foram tentados. Internamente, isso precisaria mover o incremento automático desta tabela pelo menos 14 vezes. No entanto, nada pode ser confirmado ou empurrado para o Log Buffer por causa do gerenciamento dessaid
lacuna.Agora, veja a lista de processos do seu PasteBin. A menos que eu tenha errado, vi 38 Conexões de Banco de Dados executando um INSERT (19 Antes do processo do mysqldump (identificação do processo
6155315
), 19 Depois). Tenho certeza de que 14 ou mais dessas conexões estão congeladas por causa do gerenciamento da lacuna auto_increment.fonte
A
--single-transaction
opção demysqldump
faz umFLUSH TABLES WITH READ LOCK
antes de iniciar a tarefa de backup, mas apenas sob certas condições. Uma dessas condições é quando você também especifica a--master-data
opção.No código-fonte,
mysql-5.6.19/client/mysqldump.c
na linha 5797:Para obter um bloqueio sólido nas coordenadas precisas do binlog antes de iniciar a transação de leitura repetível, a
--master-data
opção aciona esse bloqueio para ser obtido e liberado depois que as coordenadas do log de bin são obtidas.De fato,
mysqldump
faz umFLUSH TABLES
seguido de umFLUSH TABLES WITH READ LOCK
porque fazer as duas coisas permite que o bloqueio de leitura seja obtido mais rapidamente nos casos em que a liberação inicial leva algum tempo....Contudo...
Assim que ele obtém as coordenadas do binlog,
mysqldump
emite umaUNLOCK TABLES
instrução, portanto não deve haver nada bloqueando como resultado do flush iniciado. Nenhum encadeamento deve ser oWaiting for table flush
resultado da transação quemysqldump
está retendo.Quando você vê um segmento no
Waiting for table flush
estado, que deve significar que aFLUSH TABLES [WITH READ LOCK]
declaração foi emitida e ainda estava correndo quando a consulta começou - para que a consulta tem que esperar para o flush mesa, antes que ele possa executar. No caso da lista de processos que você postou,mysqldump
está lendo essa mesma tabela e a consulta está em execução há um tempo, mas as consultas de bloqueio não estão bloqueando há tanto tempo.Tudo isso sugere que algo mais aconteceu.
Há um problema de longa data explicado no Bug # 44884 com a maneira como
FLUSH TABLES
funciona internamente.Eu não ficaria surpreso se o problema ainda persistir,ficaria surpreso se esse problema for "corrigido" porque é um problema muito complexo de resolver - praticamente impossível de ser corrigido em um ambiente de alta simultaneidade - e qualquer tentativa de corrigi-lo acarreta um risco significativo de quebrar outra coisa ou criar um comportamento novo, diferente e ainda indesejável.Parece provável que esta seja a explicação para o que você está vendo.
Especificamente:
se você tiver uma consulta de longa execução em uma tabela e emitir um
FLUSH TABLES
, oFLUSH TABLES
bloco será bloqueado até que a consulta de longa duração seja concluída.Além disso, todas as consultas iniciadas após a
FLUSH TABLES
emissão serão bloqueadas até aFLUSH TABLES
conclusão.Além disso, se você matar a
FLUSH TABLES
consulta, as consultas que estão bloqueando ainda serão bloqueadas na consulta de longa execução original, aquela que estava bloqueando aFLUSH TABLES
consulta, porque, embora aFLUSH TABLES
consulta finalizada não tenha terminado, essa tabela (a única ou mais, envolvido com a consulta de execução longa) ainda está em processo de liberação, e essa liberação pendente acontecerá assim que a consulta de execução longa terminar - mas não antes.A provável conclusão aqui é que outro processo - talvez outro mysqldump, ou uma consulta não recomendada, ou um processo de monitoramento mal escrito tentou liberar uma tabela.
Essa consulta foi posteriormente eliminada ou expirada por um mecanismo desconhecido, mas seus efeitos posteriores permaneceram até
mysqldump
terminar a leitura da tabela em questão.Você pode replicar essa condição tentando
FLUSH TABLES
enquanto uma consulta de longa execução está em processo. Em seguida, inicie outra consulta, que bloqueará. Em seguida, mate aFLUSH TABLES
consulta, que não desbloqueará a consulta mais recente. Em seguida, elimine a primeira consulta ou deixe-a terminar, e a consulta final será executada com êxito.Como uma reflexão tardia, isso não tem relação:
Isso é normal, porque
mysqldump --single-transaction
emite aSTART TRANSACTION WITH CONSISTENT SNAPSHOT
, o que impede que ele despeje dados que foram alterados enquanto o despejo estava em andamento. Sem isso, as coordenadas de binlog obtidas no início não teriam sentido, pois--single-transaction
não seria o que afirma ser. Em nenhum sentido, isso não deve estar relacionado aoWaiting for table flush
problema, pois essa transação obviamente não possui bloqueios.fonte
Enviei uma solicitação de recurso: https://support.oracle.com/epmos/faces/BugDisplay?id=27103902 .
Também escrevi um patch contra a 5.6.37 que usa o mesmo método que - única transação - combinação de dados mestre com - única transação - escravo de dados, que é fornecido como está sem garantia. Use por sua conta e risco.
Testei-o com o seguinte processo com escravos para um mestre muito ocupado, usando muitas tabelas do InnoDB com relacionamentos FK:
O processo de envio de patches da Oracle é bastante intenso, portanto, por que eu segui esse caminho. Eu posso tentar com Percona e / ou MariaDB para integrá-lo.
fonte