mysqldump --single-транзакції, але запити на оновлення очікують на резервну копію


10

Якщо я використовую 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

Думаю - тут дуже зайвий, мабуть, залишок з попередніх часів, цей сценарій дуже старий, але не повинен заважати нічого


Повний вихідний показ повного списку процесорів та показу статусу innodb (анонімізований) знаходиться тут: pastebin.com/D7WS3QAE
Aleksandar Ivaiseisevic

Для чого ваш повний командний рядок mysqldump? Зокрема, ви використовуєте --flush-logsчи --master-data...? Серед варіантів можливі взаємодії.
Майкл - sqlbot

додав повну команду mysqldump, дякую, що подивився
Олександр Іванісевич

Відповіді:


6

--Single-угода варіант туздИшпр робить FLUSH TABLES WITH READ LOCK;. Це змушує mysqldump встановлювати повторювані транзакції зчитування для всіх таблиць, що скидаються.

У своєму запитанні ви сказали, що SELECT mysqldump для db_external_notificationтаблиці містить сотні команд INSERT до тієї самої таблиці. Чому це відбувається?

Найімовірніше, що це блокування на gen_clust_index (більш відомий як індекс кластера ). Ця парадигма змушує співіснувати таблиці та сторінки покажчиків для таблиці. Ці індексні сторінки базуються або на PRIMARY KEY, або на автоматично сформованому індексі RowID (у випадку, якщо немає PRIMARY KEY).

Ви маєте змогу помітити це, запустивши SHOW ENGINE INNODB STATUS\Gта шукайте будь-яку сторінку з gen_clust_index, яка має ексклюзивний замок. Введення INSERT в таблицю з кластерним індексом вимагає ексклюзивного блокування для обробки BTREE PRIMARY KEY, а також серіалізації авто-посилення.

Я обговорював це явище раніше

ОНОВЛЕННЯ 2014-07-21 15:03 EDT

Перегляньте рядки 614-617 свого PastBin

mysql tables in use 1, locked 0
MySQL thread id 6155315, OS thread handle 0x85f11b70, query id 367774810 localhost root Sending data
SELECT /*!40001 SQL_NO_CACHE */ * FROM `db_external_notification`
Trx read view will not see trx with id >= 1252538405, sees < 1252538391

Зверніть увагу, що в рядку 617 сказано

Trx read view will not see trx with id >= 1252538405, sees < 1252538391

Що це мені говорить? У вас є якийсь ПЕРВІЙНИЙ КЛЮЧ, у якому ввімкнено автоматичне збільшення id.

Ваш макс. idДля таблиці db_external_notificationбув меншим, ніж 1252538391при запуску mysqldump. При відніманні 1252538391з 1252538405, це означає , що 14 або більше команд INSERT були випробувані. Внутрішньо для цього потрібно було б перемістити автоматичне збільшення цієї таблиці принаймні 14 разів. Тим не менш, нічого не може бути зроблено або навіть натиснуто в буфер журналу через управління цим idпрогалиною.

Тепер подивіться на список процесів зі свого PasteBin. Якщо я не зробив з рахунків, я побачив 38 підключень до БД, які роблять INSERT (19 Перед процесом mysqldump (ідентифікатор процесу 6155315), 19 після). Я впевнений, що 14 або більше таких з'єднань заморожені через керування розривом auto_increment.


Я довго шукав і не міг знайти жодних ексклюзивних замків. я вставив статус повного шоу innodb на pastebin.com/D7WS3QAE , ніщо там не схоже на ексклюзивний замок на що-небудь для мене
Олександр Іванісевич

Дякуємо за роз’яснення. Мені цікаво, чому вони не використовують транзакцію лише для читання, оскільки зрозуміло, що резервне копіювання ніколи не запише, але я здогадуюсь, що вони зберігають цю функцію для їх резервного копіювання на підприємстві.
Олександр Іванисевич

10

--single-transactionВаріант mysqldump робить зробити FLUSH TABLES WITH READ LOCKперед початком завдання резервного копіювання , але тільки за певних умов. Однією з таких умов є те, коли ви також вказуєте --master-dataваріант.

У вихідному коді з mysql-5.6.19/client/mysqldump.cрядка 5797:

if ((opt_lock_all_tables || opt_master_data ||
     (opt_single_transaction && flush_logs)) &&
    do_flush_tables_read_lock(mysql))
  goto err;

Щоб отримати суцільний замок на точних координатах бінолога перед початком транзакції з повторним зчитуванням, --master-dataопція запускає цей замок, щоб отримати, а потім відпустити, як тільки будуть отримані координати бінлога.

Насправді, mysqldumpце FLUSH TABLESсупроводжується тим, 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запит, який не розблокує останній запит. Потім вбити перший запит або дозволити його завершити, і остаточний запит буде успішно запущений.


Як наслідок, це не пов'язано:

Trx read view will not see trx with id >= 1252538405, sees < 1252538391

Це нормально, тому що mysqldump --single-transactionвидає a START TRANSACTION WITH CONSISTENT SNAPSHOT, що не дозволяє йому скидати дані, які були змінені під час роботи дампа. Без цього координати бінлог, отримані на початку, були б безглуздими, оскільки --single-transactionне були б такими, якими вона претендує. Це жодним чином не повинно бути пов’язане з Waiting for table flushпроблемою, оскільки ця транзакція, очевидно, не має жодних блокувань.


Ця відповідь насправді правильна.
Бобан П.

2

Я подав запит на функцію: https://support.oracle.com/epmos/faces/BugDisplay?id=27103902 .

Я також написав виправлення проти 5.6.37, який використовує той самий метод, що і --single-транзакція - майстер-комбінація даних із --single-транзакцією --slave-data, який надається як -без гарантії. Використовуйте на свій страх і ризик.

--- mysql-5.6.37/client/mysqldump.c.bak 2017-11-14 12:24:41.846647514 -0600
+++ mysql-5.6.37/client/mysqldump.c 2017-11-14 14:17:51.187050091 -0600
@@ -4900,10 +4900,10 @@
   return 0;
 }

+/*
 static int do_stop_slave_sql(MYSQL *mysql_con)
 {
   MYSQL_RES *slave;
-  /* We need to check if the slave sql is running in the first place */
   if (mysql_query_with_error_report(mysql_con, &slave, "SHOW SLAVE STATUS"))
     return(1);
   else
@@ -4911,23 +4911,21 @@
     MYSQL_ROW row= mysql_fetch_row(slave);
     if (row && row[11])
     {
-      /* if SLAVE SQL is not running, we don't stop it */
       if (!strcmp(row[11],"No"))
       {
         mysql_free_result(slave);
-        /* Silently assume that they don't have the slave running */
         return(0);
       }
     }
   }
   mysql_free_result(slave);

-  /* now, stop slave if running */
   if (mysql_query_with_error_report(mysql_con, 0, "STOP SLAVE SQL_THREAD"))
     return(1);

   return(0);
 }
+*/

 static int add_stop_slave(void)
 {
@@ -5841,10 +5839,12 @@
   if (!path)
     write_header(md_result_file, *argv);

+  /*
   if (opt_slave_data && do_stop_slave_sql(mysql))
     goto err;
+  */

-  if ((opt_lock_all_tables || opt_master_data ||
+  if ((opt_lock_all_tables || opt_master_data || opt_slave_data ||
        (opt_single_transaction && flush_logs)) &&
       do_flush_tables_read_lock(mysql))
     goto err;
@@ -5853,7 +5853,7 @@
     Flush logs before starting transaction since
     this causes implicit commit starting mysql-5.5.
   */
-  if (opt_lock_all_tables || opt_master_data ||
+  if (opt_lock_all_tables || opt_master_data || opt_slave_data ||
       (opt_single_transaction && flush_logs) ||
       opt_delete_master_logs)
   {
 static int add_stop_slave(void)
 {
@@ -5841,10 +5839,12 @@
   if (!path)
     write_header(md_result_file, *argv);

+  /*
   if (opt_slave_data && do_stop_slave_sql(mysql))
     goto err;
+  */

-  if ((opt_lock_all_tables || opt_master_data ||
+  if ((opt_lock_all_tables || opt_master_data || opt_slave_data ||
        (opt_single_transaction && flush_logs)) &&
       do_flush_tables_read_lock(mysql))
     goto err;
@@ -5853,7 +5853,7 @@
     Flush logs before starting transaction since
     this causes implicit commit starting mysql-5.5.
   */
-  if (opt_lock_all_tables || opt_master_data ||
+  if (opt_lock_all_tables || opt_master_data || opt_slave_data ||
       (opt_single_transaction && flush_logs) ||
       opt_delete_master_logs)
   {

Я перевірив це за допомогою наступного процесу з рабами для дуже зайнятого майстра, використовуючи безліч таблиць InnoDB з відносинами FK:

  1. Стоп раб А.
  2. Зачекайте ~ 15 хвилин.
  3. Дамп DB 1 з підлеглого B з опцією --single-транзакція та --dump-slave = 2
  4. Запустіть підлеглий A до тих пір, поки координати не будуть виконуватись із кроку 3.
  5. Відкиньте DB 1 і 2 з підлеглого А.
  6. Створіть порожні DB 1 та 2 на підлеглому А.
  7. Завантажте дамп із кроку 3 в підлеглий А.
  8. Дамп DB 2 з підлеглого B з тими ж параметрами. DB 2 має відношення FK до DB 1.
  9. Додайте replicate_ignore_db для DB 2 та skip_slave_start на підлеглому A.
  10. Перезапустити раба А.
  11. Запустіть ведений до тих пір, поки координати з дампа не будуть виконані на кроці 8 на підлеглому А.
  12. Завантажте дамп із кроку 8 в підлеглий А.
  13. Видаліть параметри replicate_ignore_db та skip_slave_start з підлеглого А.
  14. Перезапустити раба А.
  15. Зачекайте ~ 1 тиждень.
  16. Використовуйте pt-контрольну суму для перевірки цілісності даних.

Процес подання патчів Oracle є досить інтенсивним, тому я пішов цим шляхом. Я можу спробувати з Percona та / або MariaDB інтегрувати його.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.