mysqldump-단일 트랜잭션이지만 업데이트 쿼리가 백업을 기다리고 있습니다


10

문서에 따르면 mysqldump --single-transaction을 사용하면 읽기 잠금으로 테이블을 플러시하여 일관된 상태를 얻은 다음 트랜잭션을 시작해야하며 작가가 대기하지 않아야합니다.

그러나 나는 어젯밤에 다음과 같은 상황을 겪었습니다.

전체 프로세스 목록 표시에서 발췌 :

그중 수백 ...

   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가 중복되어 있다고 생각합니다. 아마도 이전부터 남은 것입니다.이 스크립트는 매우 오래되었지만 아무 것도 아프지 않아야합니다.


show full processlist 및 show innodb status (익명)의 전체 출력은 다음과 같습니다. pastebin.com/D7WS3QAE
— Aleksandar Ivanisevic

전체 명령 줄은 mysqldump무엇입니까? 특히, --flush-logs또는 --master-data... 을 사용하고 있습니까? 옵션간에 잠재적 인 상호 작용이 있습니다.
— Michael-sqlbot

보고 해 주셔서 감사합니다 전체 mysqldump 명령 추가
— Aleksandar Ivanisevic

답변:


6

mysqldump 의 --single-transaction 옵션은 하지 않습니다 . mysqldump는 덤프되는 모든 테이블에 대해 반복 가능한 읽기 트랜잭션을 설정합니다.FLUSH TABLES WITH READ LOCK;

귀하의 질문에 따르면, db_external_notification테이블에 대한 mysqldump의 SELECT 는 동일한 테이블에 수백 개의 INSERT 명령을 보유하고 있다고 언급했습니다 . 왜 이런 일이 발생합니까?

gen_clust_index 에 대한 잠금이 가장 가능성이 높습니다 (클러스터형 인덱스라고 함). 이 패러다임은 테이블의 데이터 및 인덱스 페이지가 공존하게합니다. 이러한 인덱스 페이지는 PRIMARY KEY 또는 자동 생성 된 RowID 인덱스 (PRIMARY KEY가없는 경우)를 기반으로합니다.

실행 SHOW ENGINE INNODB STATUS\G하여 이를 발견하고 독점 잠금이있는 gen_clust_index 에서 모든 페이지를 찾을 수 있어야합니다 . 클러스터형 인덱스가있는 테이블에 INSERT를 수행하려면 PRIMARY KEY의 BTREE를 처리하고 auto_increment의 직렬화를 처리하기위한 독점 잠금이 필요합니다.

나는이 현상을 전에 논의했다

업데이트 2014-07-21 15:03 EDT

PastBin의 614-617 행을보십시오

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

이것이 무엇을 말해줍니까? auto_increment가 설정된 PRIMARY KEY가 있습니다 id.

id테이블 의 최대 값 은 mysqldump가 시작될 db_external_notification때보 1252538391다 적었습니다 . 1252538391에서 빼면 125253840514 개 이상의 INSERT 명령이 시도되었음을 나타냅니다. 내부적으로 이것은이 테이블의 auto_increment를 최소한 14 번 이동해야합니다. 그러나이 id차이 를 관리하기 때문에 커밋하거나 로그 버퍼로 푸시 할 수있는 것은 없습니다 .

이제 PasteBin의 프로세스 목록을보십시오. 잘못 계산하지 않으면 38 개의 DB 연결이 INSERT를 수행하는 것을 보았습니다 (19 mysqldump 프로세스 이전 (프로세스 id 6155315), 19 이후). auto_increment gap 관리로 인해 14 개 이상의 해당 연결이 고정되어 있다고 확신합니다.


나는 오랫동안 찾고 있었고 독점 잠금 장치를 찾을 수 없었습니다. pastebin.com/D7WS3QAE에 전체 innodb 상태를 붙여 넣었습니다. 나에게 독점 잠금처럼 보이는 것은 없습니다
— Aleksandar Ivanisevic

설명 주셔서 감사합니다. 백업이 절대로 쓰지 않을 것이기 때문에 읽기 전용 트랜잭션을 사용하지 않는 이유가 궁금합니다. 그러나 엔터프라이즈 백업을 위해 해당 기능을 유지하고 있다고 생각합니다.
— Aleksandar Ivanisevic

10

--single-transaction의 옵션을 사용 mysqldump 하지 DO가 FLUSH TABLES WITH READ LOCK이전에 백업 작업을 시작하기 만 특정 조건 하에서. 이러한 조건 중 하나는 --master-data옵션을 지정할 때 입니다.

mysql-5.6.19/client/mysqldump.c5797 행 의 소스 코드 :

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

반복 가능한 읽기 트랜잭션을 시작하기 전에 정확한 binlog 좌표에 고정 잠금을 설정하려면 --master-data이 잠금을 획득 한 다음 binlog 좌표가 확보되면이 잠금이 트리거됩니다.

사실, mysqldump않는 FLUSH TABLESa로 이어 FLUSH TABLES WITH READ LOCK모두 일을하는 읽기 잠금이 초기 세척 시간이 좀 걸리는 경우 더 빨리 얻을 수 있기 때문이다.

...하나...

binlog 좌표를 얻 자마자 명령문을 mysqldump발행 UNLOCK TABLES하므로 시작한 플러시로 인해 차단되는 것이 없어야합니다. 보류 Waiting for table flush중인 트랜잭션의 결과로 스레드가 없어야합니다 mysqldump.

당신이에 스레드를 볼 때 Waiting for table flush상태, 즉 해야 것을 의미 FLUSH TABLES [WITH READ LOCK]문이 발행 된 여전히 실행중인 쿼리가 테이블 높이 기다려야합니다, 그래서 그것을 실행하기 전에 - 쿼리가 시작했을 때. 게시 한 프로세스 목록의 mysqldump경우이 동일한 테이블을 읽고 쿼리가 잠시 실행되었지만 차단 쿼리는 오랫동안 차단되지 않았습니다.

이것은 모두 다른 일이 일어 났음을 암시합니다.

내부적 으로 작동 하는 방식과 함께 버그 # 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문제가 START TRANSACTION WITH CONSISTENT SNAPSHOT발생하여 덤프가 진행되는 동안 변경된 데이터를 덤프하지 못하도록 하기 때문에 정상 입니다. 그것이 없다면, 시작시 얻은 binlog 좌표는 의미가 없을 것이기 때문에 의미 --single-transaction가 없습니다. 이 Waiting for table flush트랜잭션은 분명히 잠금을 보유하지 않기 때문에 어떤 의미로도 문제 와 관련해서는 안됩니다 .


이 대답은 실제로 맞습니다.
— Boban P.

2

: 나는 기능 요청 제출 https://support.oracle.com/epmos/faces/BugDisplay?id=27103902을 .

또한 5.6.37에 대한 패치를 작성하여 --single-transaction --slave-data와 --single-transaction --master-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)
   {

FK 관계가있는 많은 InnoDB 테이블을 사용하여 매우 바쁜 마스터에 슬레이브로 다음 프로세스로 테스트했습니다.

  1. 슬레이브 A를 중지하십시오.
  2. ~ 15 분 정도 기다립니다.
  3. --single-transaction 및 --dump-slave = 2 옵션을 사용하여 슬레이브 B에서 DB 1을 덤프하십시오.
  4. 3 단계에서 덤프 좌표가 올 때까지 슬레이브 A를 시작하십시오.
  5. 슬레이브 A에서 DB 1과 2를 삭제하십시오.
  6. 슬레이브 A에서 빈 DB 1 및 2를 작성하십시오.
  7. 3 단계에서 덤프를 슬레이브 A로로드하십시오.
  8. 동일한 옵션으로 슬레이브 B에서 DB 2를 덤프하십시오. DB 2는 DB 1과 FK 관계가 있습니다.
  9. DB 2에 replicate_ignore_db를 추가하고 슬레이브 A에 skip_slave_start를 추가하십시오.
  10. 슬레이브 A를 다시 시작하십시오.
  11. 슬레이브 A에서 8 단계의 덤프 좌표가 될 때까지 슬레이브를 시작하십시오.
  12. 8 단계에서 덤프를 슬레이브 A로로드하십시오.
  13. 슬레이브 A에서 replicate_ignore_db 및 skip_slave_start 옵션을 제거하십시오.
  14. 슬레이브 A를 다시 시작하십시오.
  15. ~ 1 주간 기다리십시오.
  16. pt-checksum을 사용하여 데이터 무결성을 확인하십시오.

오라클의 패치 제출 프로세스는 다소 집중적이므로이 경로를 선택한 이유는 무엇입니까? Percona 및 / 또는 MariaDB를 사용하여 통합하려고 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.