Если я использую mysqldump --single-транзакции, в соответствии с документацией он должен выполнить очистку таблиц с блокировкой чтения, чтобы получить согласованное состояние, а затем начать транзакцию, и никаких авторов не должно ждать.
Однако вчера вечером я обнаружил следующую ситуацию:
выдержка из показа полного списка процессов:
сотни таких ...
Command: Query
Time: 291
State: Waiting for table flush
Info: insert into db_external_notification.....
тогда это:
Command: Query
Time: 1204
State: Sending data
Info: SELECT /*!40001 SQL_NO_CACHE */ * FROM `db_external_notification`
а остальные темы спят
Кто-нибудь есть идеи, чего ждут эти вставки? Я не вижу ни таблиц FLUSH, ни DDL, ни чего-либо, упомянутого в руководстве, которое может заставить запросы ждать.
полная команда mysqldump
mysqldump --quick --add-drop-table --single-transaction --master-data=2 -uxx -pxx dbname
Я полагаю, --quick здесь избыточен, вероятно, пережиток прошлого, этот скрипт очень старый, но не должен причинять вреда.
mysqldump
? В частности, вы используете--flush-logs
или--master-data
...? Есть потенциальные взаимодействия между вариантами.Ответы:
Опция --single -action для mysqldump не подходит
FLUSH TABLES WITH READ LOCK;
. Это приводит к тому, что mysqldump устанавливает повторяемую транзакцию чтения для всех дампируемых таблиц.От вашего вопроса вы заявили, что SELECT mysqldump для
db_external_notification
таблицы содержит сотни команд INSERT для этой же таблицы. Почему это происходит ?Наиболее вероятная вещь - блокировка на gen_clust_index (более известный как Clustered Index). Эта парадигма заставляет сосуществовать данные и страницы индекса для таблицы. Эти индексные страницы основаны либо на PRIMARY KEY, либо на автоматически сгенерированном индексе RowID (в случае, если PRIMARY KEY нет).
Вы должны быть в состоянии определить это, запустив
SHOW ENGINE INNODB STATUS\G
и ища любую страницу из gen_clust_index, которая имеет эксклюзивную блокировку. Выполнение INSERT в таблице с кластеризованным индексом требует монопольной блокировки для обработки BTREE PRIMARY KEY, а также сериализации auto_increment.Я обсуждал это явление раньше
Aug 08, 2011
: Блокировки InnoDB являются исключительными для INSERT / UPDATE / DELETE?Dec 22, 2011
: Тупик MySQL - не может нормально перезапустить?Dec 13, 2012
: MySQL InnoDB блокирует первичный ключ при удалении даже в READ COMMITTEDОБНОВЛЕНИЕ 2014-07-21 15:03 ПО ВОСТОЧНОМУ ВРЕМЕНИ
Пожалуйста, посмотрите на строки 614-617 вашей PastBin
Обратите внимание, что строка 617 говорит
Что это говорит мне? У вас есть ПЕРВИЧНЫЙ КЛЮЧ с включенным auto_increment
id
.Ваш максимум
id
для таблицыdb_external_notification
был меньше, чем1252538391
при запуске mysqldump. Когда вы вычитаете1252538391
из1252538405
, это означает, что было предпринято 14 или более команд INSERT. Внутренне это должно было бы переместить auto_increment этой таблицы по крайней мере 14 раз. Тем не менее, ничто не может быть зафиксировано или даже помещено в Log Buffer из-за управления этимid
разрывом.Теперь посмотрите на список процессов из вашего PasteBin. Если я не учел ошибки, я увидел, что 38 соединений с БД выполняли INSERT (19 до процесса mysqldump (идентификатор процесса
6155315
), 19 после). Я уверен, что 14 или более из этих соединений заморожены из-за разрыва auto_increment.источник
--single-transaction
Вариантmysqldump
делает сделатьFLUSH TABLES WITH READ LOCK
перед началом задания резервного копирования , но только при определенных условиях. Одно из таких условий - когда вы также указываете--master-data
опцию.В исходном коде из
mysql-5.6.19/client/mysqldump.c
строки 5797:Чтобы получить надежную блокировку точных координат бинлога до начала транзакции повторяемого чтения, эта
--master-data
опция вызывает получение этой блокировки, а затем освобождение после получения координат бинлога.На самом деле, следует
mysqldump
лиFLUSH TABLES
после a,FLUSH TABLES WITH READ LOCK
потому что выполнение обеих вещей позволяет быстрее получить блокировку чтения в случаях, когда первоначальная очистка занимает некоторое время....Однако...
Как только он получит координаты бинлога,
mysqldump
выдаетUNLOCK TABLES
инструкцию, поэтому в результате начавшегося сброса не должно быть ничего блокирующего. Ни один из потоков не должен бытьWaiting for table flush
результатом транзакции, котораяmysqldump
удерживается.Когда вы видите поток в
Waiting for table flush
состоянии, это должно означать, чтоFLUSH TABLES [WITH READ LOCK]
инструкция была выполнена и все еще выполнялась, когда запрос начинался - поэтому запрос должен ждать сброса таблицы, прежде чем он сможет выполнить. В случае списка процессов, который вы опубликовали,mysqldump
он читает из этой же таблицы, и запрос выполнялся какое-то время, но блокирующие запросы не блокировали все это время.Все это говорит о том, что произошло что-то еще.
В Bug # 44884 есть давняя проблема, объясняющая, как
FLUSH TABLES
работает внутренне.Я не был бы удивлен, если проблема все еще сохраняется,я был бы удивлен, если бы эта проблема когда-либо была «исправлена», потому что это очень сложная проблема, которую практически невозможно решить - практически невозможно действительно решить в среде с высоким уровнем параллелизма - и любая попытка исправление этого влечет за собой значительный риск поломки чего-либо другого или создания нового, другого и все еще нежелательного поведения.Кажется вероятным, что это будет объяснением того, что вы видите.
В частности:
если у вас есть долгосрочный запрос, работающий с таблицей, и вы
FLUSH TABLES
выполняете команду, то онFLUSH TABLES
будет блокироваться до тех пор, пока не будет выполнен длительный запрос.Кроме того, любые запросы, которые начинаются после
FLUSH TABLES
выдачи, будут блокироваться доFLUSH TABLES
завершения.Кроме того, если вы убьете
FLUSH TABLES
запрос, блокирующие запросы все равно будут блокировать исходный длительный запрос, который блокировалFLUSH TABLES
запрос, потому что, даже если завершенныйFLUSH TABLES
запрос не завершился, эта таблица (та, или более того, связанный с долгосрочным запросом) все еще находится в процессе сброса, и эта ожидающая очистка произойдет, как только закончится длительный запрос - но не раньше.Вероятный вывод здесь состоит в том, что другой процесс - возможно, другой mysqldump, или опрометчивый запрос, или плохо написанный процесс мониторинга попытался очистить таблицу.
Впоследствии этот запрос был прерван или заблокирован тайм-аутом неизвестного механизма, но его последствия оставались до
mysqldump
завершения чтения из рассматриваемой таблицы.Вы можете повторить это условие, пытаясь сделать так, чтобы в
FLUSH TABLES
течение длительного времени выполнялся запрос. Затем запустите другой запрос, который заблокирует. Затем убейтеFLUSH TABLES
запрос, который не разблокирует последний запрос. Затем убейте первый запрос или дайте ему закончить, и последний запрос будет успешно выполнен.Как запоздалая мысль, это не связано:
Это нормально, потому что
mysqldump --single-transaction
выдает сообщение aSTART TRANSACTION WITH CONSISTENT SNAPSHOT
, которое не позволяет создавать дамп данных, которые были изменены во время выполнения дампа. Без этого координаты бинлога, полученные в начале, были бы бессмысленными, поскольку--single-transaction
они не были бы такими, какими они себя называют . Это ни в коем случае не должно быть связано сWaiting for table flush
проблемой, поскольку эта транзакция, очевидно, не содержит блокировок.источник
Я отправил запрос на добавление функции: https://support.oracle.com/epmos/faces/BugDisplay?id=27103902 .
Я также написал патч для 5.6.37, который использует тот же метод, что и комбинация --single-транзакции - master-data с --single-транзакции --slave-data, которая предоставляется без каких-либо гарантий. Используйте на свой риск.
Я проверил это с помощью следующего процесса с ведомыми устройствами для очень занятого мастера, использующего множество таблиц InnoDB с отношениями FK:
Процесс отправки патчей Oracle довольно интенсивный, поэтому я выбрал этот путь. Я могу попробовать с Percona и / или MariaDB, чтобы интегрировать его.
источник