mysqldump - tek işlem, ancak güncelleme sorguları yedek bekliyor


10

Eğer mysqldump - tek bir işlem kullanırsam, dokümanlara göre tutarlı bir durum elde etmek için okuma kilitli tabloları yıkamalı ve sonra bir işlem başlatmalı ve hiçbir yazar beklememelidir.

Ancak, dün gece şu durumu yakaladım:

tam süreç listesinden alıntı:

bunlardan yüzlerce ...

   Command: Query
   Time: 291
   State: Waiting for table flush
   Info: insert into db_external_notification.....

sonra bu:

Command: Query
Time: 1204
State: Sending data
Info: SELECT /*!40001 SQL_NO_CACHE */ * FROM `db_external_notification`

ve diğer iplikler Uyku durumunda

bu eklerin ne beklediğine dair bir fikri olan var mı? FLUSH tabloları veya DDL veya kılavuzda belirtilen ve sorguların beklemesine neden olabilecek herhangi bir şey görmüyorum.

tam mysqldump komutu

mysqldump --quick --add-drop-table --single-transaction --master-data=2 -uxx -pxx dbname

Sanırım - hızlı burada gereksiz, muhtemelen daha eski zamanlardan kalan, bu komut dosyası çok eski, ama herhangi bir şeye zarar vermemeli


show tam süreç listesini ve show innodb durumunu tam çıktı (anonim) burada: pastebin.com/D7WS3QAE
Aleksandar Ivanisevic

Tam komut satırınız ne için mysqldump? Özellikle, --flush-logsveya --master-data... mı kullanıyorsunuz ? Seçenekler arasında potansiyel etkileşimler vardır.
Michael - sqlbot

tam mysqldump komutu ekledi, baktığın için teşekkürler
Aleksandar Ivanisevic

Yanıtlar:


6

--Single-işlem seçeneği mysqldump yapmaz FLUSH TABLES WITH READ LOCK;. Mysqldump'ın atılan tüm tablolar için tekrarlanabilir bir okuma işlemi ayarlamasına neden olur.

Sorunuzdan, mysqldump'ın db_external_notificationtablo için SELECT öğesinin aynı tabloya yüzlerce INSERT komutu tuttuğunu belirttiniz. Bu neden oluyor ?

En olası şey gen_clust_index üzerinde bir kilittir (Kümelenmiş Dizin olarak bilinir). Bu paradigma, bir tablonun veri ve dizin sayfalarının bir arada var olmasına neden olur. Bu dizin sayfaları, PRIMARY KEY veya ve otomatik olarak oluşturulan RowID dizinini temel alır (PRIMARY KEY olmaması durumunda).

Bunu çalıştırarak tespit edebilir SHOW ENGINE INNODB STATUS\Gve gen_clust_index'ten özel bir kilidi olan herhangi bir sayfayı arayabilirsiniz . Kümelenmiş bir dizine sahip bir tabloya INSERT'lerin yapılması, PRIMARY KEY'in BTREE'sini işlemek için özel bir kilit ve ayrıca auto_increment'in serileştirilmesini gerektirir.

Bu fenomeni daha önce tartıştım

GÜNCELLEME 2014-07-21 15:03 EDT

Lütfen PastBin'inizin 614-617 satırlarına bakın

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. satırın

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

Bu bana ne anlatıyor? Bir auto_increment ile bazı PRIMARY KEY var id.

idTablo için maksimum değeriniz, mysqldump'ın başlatıldığından db_external_notificationdaha azdı 1252538391. Ne zaman çıkarmak 1252538391dan 125253840514 ya da daha fazla INSERT komutları teşebbüs edildiğini bu araçlarla. Dahili olarak, bu tablonun auto_increment'ini en az 14 kez taşıması gerekir. Ancak, bu idboşluğu yönettiği için hiçbir şey kaydedilemez ve Log Buffer'a aktarılamaz.

Şimdi PasteBin'inizden işlem listesine bakın. Yanlış saymadıkça, bir INSERT (19 mysqldump işleminden önce (işlem kimliği 6155315), 19 Sonra) 38 DB Bağlantıları gördüm . Auto_increment boşluğunu yönettiği için bu bağlantıların 14 veya daha fazlasının donmuş olduğundan eminim.


Uzun zamandır arıyordum ve özel kilitler bulamadım. Tam gösteri innodb durumunu pastebin.com/D7WS3QAE adresine yapıştırdım , hiçbir şey bana özel bir kilit gibi görünmüyor
Aleksandar Ivanisevic

Açıklama için teşekkürler. Yedeklemenin asla yazamayacağı açık olduğu için neden salt okunur bir işlem kullanmadıklarını merak ediyorum, ancak kurumsal yedekleme için bu özelliği koruduklarını tahmin ediyorum.
Aleksandar Ivanisevic

10

--single-transactionSeçeneği mysqldump yapar bir do FLUSH TABLES WITH READ LOCKönceki yedekleme işi başlamadan fakat sadece belirli şartlar altında. Bu koşullardan biri de --master-dataseçeneği belirttiğiniz zamandır.

Kaynak kodunda, mysql-5.6.19/client/mysqldump.c5797 satırından:

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

Tekrarlanabilir okuma işlemine başlamadan önce kesin binlog koordinatlarında sağlam bir kilit --master-dataelde etmek için , seçenek bu kilidin alınmasını tetikler ve binlog koordinatları elde edildikten sonra serbest bırakılır.

Aslında, mysqldumpbir yok FLUSH TABLESbir takip FLUSH TABLES WITH READ LOCKikisini de yapıyor okuma kilidi ilk floş biraz zaman alır durumlarda daha hızlı elde edilmesini sağlar çünkü.

...ancak...

Binlog koordinatlarını alır almaz, mysqldumpbir UNLOCK TABLESifade yayınlar , bu nedenle başlattığınız kızarıklık nedeniyle herhangi bir engelleme olmamalıdır. Bekleyen Waiting for table flushişlem sonucunda hiçbir iş parçacığı da olmamalıdır mysqldump.

Durumda bir iş parçacığı gördüğünüzde Waiting for table flush, bu , deyimin başlatıldığı ve sorgu başlatıldığında çalışmakta olduğu anlamına gelmelidir . Gönderdiğiniz işlem listesinin aynı tablodan okunması durumunda ve sorgu bir süredir çalışıyor olsa da, engelleme sorguları bu kadar uzun süredir engellemiyor.FLUSH TABLES [WITH READ LOCK]mysqldump

Bu, başka bir şeyin olduğunu gösteriyor.

Uzun süredir devam eden sorun var # 44884 Bug açıklanan yolu ile FLUSH TABLESiçten, işlerin. Sorun hala devam ederse şaşırmazdım, bu sorunun "sabit" olması durumunda şaşırırdım çünkü çözülmesi çok karmaşık bir konudur - yüksek eşzamanlılık ortamında gerçekten düzeltmek neredeyse imkansızdır - ve herhangi bir girişimde onu düzeltmek, başka bir şeyi kırma veya yeni, farklı ve hala istenmeyen davranışlar oluşturma konusunda önemli bir risk taşır.

Muhtemelen bu gördüğünüz şeyin açıklaması olacak gibi görünüyor.

özellikle:

  • bir tabloya karşı çalışan uzun bir sorgu varsa ve sorun varsa FLUSH TABLES, FLUSH TABLESuzun süre çalışan sorgu tamamlanana kadar engeller.

  • Ayrıca, FLUSH TABLESyayınlandıktan sonra başlayan tüm sorgular FLUSH TABLEStamamlanana kadar engellenir .

  • Eğer öldürürsen ayrıca, FLUSH TABLESsorgu, engelliyor sorgular olacak hala bloke orijinal sorgu uzun süren engelleme edildi birini FLUSH TABLESöldürse de, çünkü sorgu FLUSH TABLESsorgu bitiremedi, bu tabloyu (birini veya daha fazla, uzun süren sorguyla ilgili) hala boşaltılan bir süreçtir ve uzun süren sorgu biter bitmez bu beklemedeki durulama gerçekleşir - ancak daha önce değil.

Buradaki muhtemel sonuç, başka bir sürecin - belki de başka bir mysqldump, ya da tavsiye edilmeyen bir sorgu ya da kötü yazılmış bir izleme sürecinin bir tabloyu temizlemeye çalıştığıdır.

Bu sorgu daha sonra bilinmeyen bir mekanizma tarafından öldürüldü veya zaman aşımına uğradı, ancak sonraki etkileri mysqldumpsöz konusu tablodan okuma bitene kadar devam etti .

FLUSH TABLESUzun süredir devam eden bir sorgu devam ederken bunu deneyerek bu koşulu çoğaltabilirsiniz . Ardından, engellenecek başka bir sorgu başlatın. Ardından FLUSH TABLES, en son sorgunun engellemesini kaldırmayacak olan sorguyu öldürün . Sonra ilk sorguyu öldürün ya da bitmesine izin verin, son sorgu başarıyla çalışacaktır.


Sonradan düşünüldüğünde, bu ilgisizdir:

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

Bu normaldir, çünkü mysqldump --single-transactiona START TRANSACTION WITH CONSISTENT SNAPSHOTdökümü, döküm devam ederken değiştirilen verileri dökmesini önler. Bu olmadan, başlangıçta elde edilen binlog koordinatları anlamsız olurdu, çünkü --single-transactioniddia ettiği gibi olmazdı. Bu Waiting for table flushişlemin hiçbir şekilde sorunla ilgili olmaması gerekir , çünkü bu işlemin kesinlikle kilitleri yoktur.


Bu cevap aslında doğrudur.
Boban P.

2

Bir özellik isteği gönderdim: https://support.oracle.com/epmos/faces/BugDisplay?id=27103902 .

5.6.37'e karşı --single-transaction --master-data kombinasyonu ile --single-transaction --slave-data gibi aynı yöntemi kullanan ve yama olmadan sağlanan bir yama yazdım. Kendi sorumluluğunuzdadır kullanın.

--- 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)
   {

FK ilişkileri olan çok sayıda InnoDB tablosu kullanarak çok yoğun bir master'a köle ile aşağıdaki işlemi test ettim:

  1. Köle A'yı durdurun.
  2. ~ 15 dakika bekleyin.
  3. Slave B'den DB 1'i --single-transaction ve --dump-slave = 2 seçeneği ile dökün
  4. Adım 3'teki çöplükte koordinatlar oluncaya kadar köle A'yı başlatın.
  5. Bağımlı A'dan DB 1 ve 2'yi bırakın.
  6. Slave A'da boş DB 1 ve 2 oluşturun.
  7. Adım 3'ten köle A'ya dökümü yükleyin.
  8. Aynı seçenekle DB 2'yi bağımlı B'den boşaltın. DB 2'nin DB 1 ile FK ilişkileri vardır.
  9. DB 2 için replicate_ignore_db ve A köle üzerinde skip_slave_start ekleyin.
  10. Slave A'yı yeniden başlatın.
  11. Köle A'da 8. adımda dökümünden koordinatlar alınana kadar köle başlatın.
  12. Adım 8'den köle A'ya dökümü yükleyin.
  13. A bağımlılığından replicate_ignore_db ve skip_slave_start seçeneklerini kaldırın.
  14. Slave A'yı yeniden başlatın.
  15. ~ 1 hafta bekleyin.
  16. Veri bütünlüğünü doğrulamak için pt-checksum kullanın.

Oracle'ın yama gönderme süreci oldukça yoğundur, bu yüzden neden bu rotaya gittim. Entegre olabilmek için Percona ve / veya MariaDB ile deneyebilirim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.