发布时间:2013 年 4 月 6 日 发布者: OurMySQL

来源:P.Linux Laboratory   
 

前几天看到群里在讨论mysqldump导致锁表的问题,为什么一个表已经dump完了还会被锁住?mysqldump里面到底是怎么处理的,为了解答这些问题,就来看看mysqldump.cc中的实现吧。

重要参数

首先我们把参数和内部变量对应起来,并且看一下它们的注释:

-single-transaction: opt_single_transaction

Creates a consistent snapshot by dumping all tables in a single transaction. Works ONLY for tables stored in storage engines which support multiversioning (currently only InnoDB does); the dump is NOT guaranteed to be consistent for other storage engines. While a -single-transaction dump is in process, to ensure a valid dump file (correct table contents and binary log position), no other connection should use the following statements: ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE, as consistent snapshot is not isolated from them. Option automatically turns off -lock-tables.

通过将导出操作封装在一个事务内来使得导出的数据是一个一致性快照。只有当表使用支持MVCC的存储引擎(目前只有InnoDB)时才可以工作;其他引擎不能保证导出是一致的。当导出开启了-single-transaction选项时,要确保导出文件有效(正确的表数据和二进制日志位置),就要保证没有其他连接会执行如下语句:ALTER TABLE, DROP TABLE, RENAME TABLE, TRUNCATE TABLE,这会导致一致性快照失效。这个选项开启后会自动关闭lock-tables。

-master-data: opt_master_data

This causes the binary log position and filename to be appended to the output. If equal to 1, will print it as a CHANGE MASTER command; if equal to 2, that command will be prefixed with a comment symbol. This option will turn -lock-all-tables on, unless -single-transaction is specified too (in which case a global read lock is only taken a short time at the beginning of the dump; don’t forget to read about -single-transaction below). In all cases, any action on logs will happen at the exact moment of the dump. Option automatically turns -lock-tables off.

这个选项可以把binlog的位置和文件名添加到输出中,如果等于1,将会打印成一个CHANGE MASTER命令;如果等于2,会加上注释前缀。并且这个选项会自动打开-lock-all-tables,除非同时设置了-single-transaction(这种情况下,全局读锁只会在开始dump的时候加上一小段时间,不要忘了阅读-single-transaction的部分)。在任何情况下,所有日志中的操作都会发生在导出的准确时刻。这个选项会自动关闭-lock-tables。

-lock-all-tables: opt_lock_all_tables

Locks all tables across all databases. This is achieved by taking a global read lock for the duration of the whole dump. Automatically turns -single-transaction and -lock-tables off.

锁定所有库中所有的表。这是通过在整个dump的过程中持有全局读锁来实现的。会自动关闭-single-transaction 和 -lock-tables。

-lock-tables: lock_tables

Lock all tables for read. (Defaults to on; use -skip-lock-tables to disable.)

对所有表加读锁。(默认是打开的;用-skip-lock-tables来关闭)

-flush-logs: flush_logs

Flush logs file in server before starting dump. Note that if you dump many databases at once (using the option -databases= or -all-databases), the logs will be flushed for each database dumped. The exception is when using -lock-all-tables or -master-data: in this case the logs will be flushed only once, corresponding to the moment all tables are locked. So if you want your dump and the log flush to happen at the same exact moment you should use -lock-all-tables or -master-data with -flush-logs。

在开始导出前刷新服务器的日志文件。注意,如果你一次性导出很多数据库(使用 -databases= 或 -all-databases 选项),导出每个库时都会触发日志刷新。例外是当使用了 -lock-all-tables 或 -master-data 时:日志只会被刷新一次,那个时候所有表都会被锁住。所以如果你希望你的导出和日志刷新发生在同一个确定的时刻,你需要使用-lock-all-tables,或者 -master-data 配合 -flush-logs。

-delete-master-logs: opt_delete_master_logs

Delete logs on master after backup. This automatically enables -master-data.

备份完成后删除主库上的日志。这个选项会自动打开 -master-data.

-apply-slave-statements: opt_slave_apply(5.5)

Adds ‘STOP SLAVE’ prior to ‘CHANGE MASTER’ and ‘START SLAVE’ to bottom of dump.

在’CHANGE MASTER’前加上’STOP SLAVE’,在导出文件的末尾加上’START SLAVE’.

主要代码流程

我们分别看一下5.1和5.5的代码,都基于最新的trunk(5.1-rev.3909; 5.5-rev.4148)。

5.1版本主要流程

我们首先看下5.1版本的。

5320   if ((opt_lock_all_tables || opt_master_data) &&
5321 do_flush_tables_read_lock(mysql))
5322 goto err;

如果设置了master-data或lock-all-tables,则做FLUSH TABLES的操作。

来看下do_flush_tables_read_lock()里面是怎么做的,

do_flush_tables_read_lock()
4665 return
4666 ( mysql_query_with_error_report(mysql_con, 0,
4667 ((opt_master_data != 0) ? // 如果设置了--master-data
4668 "FLUSH /*!40101 LOCAL */ TABLES" : // 那么用FLUSH LOCAL TABLES
4669 "FLUSH TABLES")) || // 如果没设置那么使用FLUSH TABLE
4670 mysql_query_with_error_report(mysql_con, 0,
4671 "FLUSH TABLES WITH READ LOCK") ); // 如果上面的语句执行成功了,再执行这个

先FLUSH TABLES,成功后用FLUSH TABLES WITH READ LOCK加全局读锁。

再往下会判断single-transaction,

5323   if (opt_single_transaction && start_transaction(mysql))
5324 goto err;

如果定义了-single-transaction则打开一个事务来读取数据。

我们看下start_transaction()的实现,

start_transaction()
4741 return (mysql_query_with_error_report(mysql_con, 0,
4742 "SET SESSION TRANSACTION ISOLATION "
4743 "LEVEL REPEATABLE READ") || // 先设置会话的隔离级别为RR
4744 mysql_query_with_error_report(mysql_con, 0,
4745 "START TRANSACTION "
4746 "/*!40100 WITH CONSISTENT SNAPSHOT */")); // 再用一致性快照模式(RR)启动事务

会先设置隔离级别为RR,然后START TRANSACTION加上一致性快照的Hint。

接下来是获取Master的状态,

5338   if (opt_master_data && do_show_master_status(mysql))
5339 goto err;

如果设置了-master-data 则把当前的Master status打印出来。

接下来再判断如果启用了-single-transaction,则可以释放表锁的,因为事务已经启动了。

5340   if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
5341 goto err;

do_unlock_tables()里面就发一条UNLOCK TABLES语句释放全局表锁。

do_unlock_tables()
4677 return mysql_query_with_error_report(mysql_con, 0, "UNLOCK TABLES");

然后开始调用dump_*函数根据需要导出整个实例或者一个库或者一个表。

dump_all_databases()->dump_all_tables_in_db()
4307 if (lock_tables)
4308 {
4309 DYNAMIC_STRING query;
4310 init_dynamic_string_checked(&query, "LOCK TABLES ", 256, 1024);
4311 for (numrows= 0 ; (table= getTableName(1)) ; )
4312 {
4313 char *end= strmov(afterdot, table);
4314 if (include_table((uchar*) hash_key,end - hash_key))
4315 {
4316 numrows++;
4317 dynstr_append_checked(&query, quote_name(table, table_buff, 1));
4318 dynstr_append_checked(&query, " READ /*!32311 LOCAL */,");
4319 }
4320 }
4321 if (numrows && mysql_real_query(mysql, query.str, query.length-1))
4322 DB_error(mysql, "when using LOCK TABLES");
4323 /* We shall continue here, if --force was given */
4324 dynstr_free(&query);
4325 }
/* 如果设置了--lock-tables(默认),则导出之前需要LOCK TABLES tables_name READ。*/
...
4332 while ((table= getTableName(0)))
4333 {
4334 char *end= strmov(afterdot, table);
4335 if (include_table((uchar*) hash_key, end - hash_key))
4336 {
4337 dump_table(table,database); // 导出一张表
4338 my_free(order_by, MYF(MY_ALLOW_ZERO_PTR));
4339 order_by= 0;
4340 if (opt_dump_triggers && mysql_get_server_version(mysql) >= 50009)
4341 {
4342 if (dump_triggers_for_table(table, database)) // 导出 trigger
4343 {
4344 if (path)
4345 my_fclose(md_result_file, MYF(MY_WME));
4346 maybe_exit(EX_MYSQLERR);
4347 }
4348 }
4349 }
4350 }
/* 先dump_table来导出表,然后再看是不是配置了--triggers来决定是不是导出Trigger,dump_triggers_for_table。*/
...
4366 if (lock_tables)
4367 VOID(mysql_query_with_error_report(mysql, 0, "UNLOCK TABLES"));
/* 导出完成之后,释放表锁 */

所以我们可以知道,如果用-master-data和-single-transaction来导出数据,因为-lock-tables被自动关闭,所以导出过程中只会对当前正在做导出操作的表有IS锁,已经完成或没有开始的表,则不会加锁。

如果用的是默认-lock-tables打开的选项,则会先把所有库的锁加上,再进行导出操作,最后一次性释放所有锁。

5.5版本主要流程

接下来我们再比较一下,5.5的mysqldump有哪些变化。

5464   if ((opt_lock_all_tables || opt_master_data ||
5465 (opt_single_transaction && flush_logs)) &&
5466 do_flush_tables_read_lock(mysql))
5467 goto err;

这里有所不同,增加了flush_logs的判断,如果只是单纯的-single-transaction,不会调用do_flush_tables_read_lock(),必须同时制定-flush-logs。

5469   /*
5470 Flush logs before starting transaction since
5471 this causes implicit commit starting mysql-5.5.
5472 */
5473 if (opt_lock_all_tables || opt_master_data ||
5474 (opt_single_transaction && flush_logs) ||
5475 opt_delete_master_logs)
5476 {
5477 if (flush_logs || opt_delete_master_logs)
5478 {
5479 if (mysql_refresh(mysql, REFRESH_LOG))
5480 goto err;
5481 verbose_msg("-- main : logs flushed successfully!\n");
5482 }
5483
5484 /* Not anymore! That would not be sensible. */
5485 flush_logs= 0;
5486 }

5.5里面会尝试FLUSH LOGS。

5488   if (opt_delete_master_logs)
5489 {
5490 if (get_bin_log_name(mysql, bin_log_name, sizeof(bin_log_name)))
5491 goto err;
5492 }

5.5新增的变量,删除master上的log,这里先获取binlog的文件名。

5494   if (opt_single_transaction && start_transaction(mysql))
5495 goto err;

这一段没有变化

5497   /* Add 'STOP SLAVE to beginning of dump */
5498 if (opt_slave_apply && add_stop_slave())
5499 goto err;
5500 if (opt_master_data && do_show_master_status(mysql))
5501 goto err;
5502 if (opt_slave_data && do_show_slave_status(mysql))
5503 goto err;
5504 if (opt_single_transaction && do_unlock_tables(mysql)) /* unlock but no commit! */
5505 goto err;

这里有新加的opt_slave_apply和opt_slave_data部分,添加STOP SLAVE语句和显示SHOW SALVE STATUS的结果。

之后也是调用dump_*来导出数据。

但是因为5.5有了MDL(Meta data lock),所以-single-transaction时,事务内操作过的表都会持有MDL,因此不会被DDL破坏。

mysqldump的流程的更多相关文章

  1. MySQL Backup mysqldump备份流程学习

    我们都知道MySQL逻辑备份工具mysqldump可以保证备份数据的一致性,但是它是怎么保持一致性的? 本文不讨论mysqldump具体的选项和用法,一直对mysqldump的工作机制梳理的不太清楚, ...

  2. mysqldump和xtrabackup备份原理实现说明

    背景: MySQL数据库备份分为逻辑备份和物理备份两大类,犹豫到底用那种备份方式的时候先了解下它们的差异: 逻辑备份的特点是:直接生成SQL语句,在恢复的时候执行备份的SQL语句实现数据库数据的重现. ...

  3. Metadata Lock原理4

     http://blog.chinaunix.net/uid-28212952-id-3400571.html    Alibaba  今天发生一个故障,MM复制结构(主备库),备库slave del ...

  4. mysqldump+mydumper+xtrabackup备份原理流程

    mysqldump备份原理 备份的基本流程如下: 1.调用FTWRL(flush tables with read lock),全局禁止读写 2.开启快照读,获取此时的快照(仅对innodb表起作用) ...

  5. mysqldump流程

    前几天看到群里在讨论mysqldump导致锁表的问题,为什么一个表已经dump完了还会被锁住?mysqldump里面到底是怎么处理的,为了解答这些问题,就来看看mysqldump.cc中的实现吧. 目 ...

  6. CentOS安装gitlab,gerrit,jenkins并配置ci流程

    CentOS安装gitlab,gerrit,jenkins并配置ci流程 By Wenbin juandx@163.com 2016/4/9 这是我参考了网上很多的文档,配置了这三个软件在一个机器上, ...

  7. Mysqldump源码分析

    版权声明:本文由王珏原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/261 来源:腾云阁 https://www.qclou ...

  8. 【转载】mysqldump的single-transaction和master-data

    原文地址:mysqldump的single-transaction和master-data 作者:myownstars 先看一下--lock-tables和--lock-all-tables --lo ...

  9. mysql备份工具 :mysqldump mydumper Xtrabackup 原理

    备份是数据安全的最后一道防线,对于任何数据丢失的场景,备份虽然不一定能恢复百分之百的数据(取决于备份周期),但至少能将损失降到最低.衡量备份恢复有两个重要的指标:恢复点目标(RPO)和恢复时间目标(R ...

随机推荐

  1. 程序破解之 API HOOK技术 z

    API HOOK,就是截获API调用的技术,在程序对一个API调用之前先执行你的函数,然后根据你的需要可以执行缺省的API调用或者进行其他处理,假设如果想截获一个进程对网络的访问,一般是几个socke ...

  2. C# 邮件发送系统

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. 《Python基础教程(第二版)》学习笔记 -> 第十章 充电时刻 之 标准库

    SYS sys这个模块让你能够访问与Python解释器联系紧密的变量和函数,下面是一些sys模块中重要的函数和变量: 函数和变量 描述 argv 命令行参数,包括脚本和名称 exit([arg])   ...

  4. [原创]从Confluence获取html table并将其序列化为C#类文件的工具

    公司项目的游戏数据模型文档写在Confluence上,由于在项目初期模型变动比较频繁,手工去将文档中最新的模型结构同步到代码中比较费时费力,而且还很容易出错,于是写了一个小工具来自动化这个同步更新模型 ...

  5. LeetCode题解——3Sum

    题目: 给定一个数组,找出其中和为0的所有3个数的组合.每个组合的3个数都是非递降的. 解法: 先排序再遍历,设置3个指针,第一个依次遍历,第二三个在第一个指针后面的部分里,左右夹逼查找和为第一个数的 ...

  6. 大话细说ORM

    什么是ORM? ORM,即对象关系映射(Object Relational Mapping)表示一种技术,用来把(对象模型)表示的对象映射到基于SQL的(关系模型)数据结构中去. 说得通俗点,就是在对 ...

  7. Directory.GetCurrentDirectory

    1.一个应用程序中,Directory.GetCurrentDirectory获得的当前工作目录是C:\Windows\System32,这是为什么呢?是如何设置的? 2.在WinXP下:System ...

  8. Cocos2dx游戏源码合集(BY懒骨头+持续更新+2014.02.21)

    转自:http://blog.csdn.net/iamlazybone/article/details/19612941 声明: <萝莉快跑><喵汪大战>两个demo的原作者b ...

  9. bzoj 2190 仪仗队(欧拉函数)

    2190: [SDOI2008]仪仗队 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2245  Solved: 1413[Submit][Statu ...

  10. [C语言 - 3] 字符串

    字符数组 char * 看做一个特殊的字符数组, 在字符串结束为止添加'\0'结束符 (ASCII码0), 没有\0结尾的是普通的字符数组. 使用双引号定义的字符串自动在尾部加上\0 puts(s)函 ...