mysqldump 作为 MySQL 源生支持的逻辑复制工具自从上古时代就已经被DBA广泛使用,时至今日,很多人都依然在用他作为轻量级数据库的备份工具。
虽然在 MySQL 复制工具中 mysqldump 具有 OG 地位,但是不可否认在当代社会,单线程复制,逻辑导出完全无法 cover 大部分的备份需求场景,比如对于近TB级别的数据如果用mysqldump导出并不落盘的直接写入到其他节点中,可能要以天为时间计量单位去计算一次恢复耗时。试问,谁能忍受我们常用的网站突然某一天弹出一个提示框:今天网站数据迁移,请后天进行访问。
MY_INIT("mysqldump"); if (get_options(&argc, &argv)) ... if (dbConnect(current_host, current_user, opt_password)) exit(EX_MYSQLERR); ...
if ((opt_lock_all_tables || opt_master_data) && do_flush_tables_read_lock(sock)) goto err; if (opt_single_transaction && start_transaction(sock, test(opt_master_data))) goto err; ... if (opt_lock_all_tables || opt_master_data) { if (flush_logs && mysql_refresh(sock, REFRESH_LOG)) goto err; flush_logs= 0; /* not anymore; that would not be sensible */ } if (opt_master_data && do_show_master_status(sock)) goto err; if (opt_single_transaction && do_unlock_tables(sock)) /* unlock but no commit! */ goto err;
if (opt_alldbs) dump_all_databases(); else if (argc > 1 && !opt_databases) { /* Only one database and selected table(s) */ dump_selected_tables(*argv, (argv + 1), (argc - 1)); } else { /* One or more databases, all tables */ dump_databases(argv); } #ifdef HAVE_SMEM my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif /* No reason to explicitely COMMIT the transaction, neither to explicitely UNLOCK TABLES: these will be automatically be done by the server when we disconnect now. Saves some code here, some network trips, adds nothing to server. */ err: dbDisconnect(current_host); if (!path) write_footer(md_result_file); if (md_result_file != stdout) my_fclose(md_result_file, MYF(0)); my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR)); if (hash_inited(&ignore_table)) hash_free(&ignore_table); if (extended_insert) dynstr_free(&extended_row); if (insert_pat_inited) dynstr_free(&insert_pat); my_end(0); return(first_error); } /* main */
–lock-all-tables Locks all tables across all databases. This is achieved by taking a global read lock for the duration of the whole
–single-transaction 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.dump.
–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.
直接加 FTWRL 其实就可以获得当前 Server 的一致位点,但是,为了防止当前有 long query运行,导致长时间锁住 Server,先通过 Flush tables 等待 long query 结束,然后快速对整个 DB 加锁。但是,如果刚好在两个查询执行期间有 long query,就无能为力了。
if (opt_lock_all_tables || opt_master_data) { if (flush_logs && mysql_refresh(sock, REFRESH_LOG)) goto err; flush_logs= 0; /* not anymore; that would not be sensible */ }
if (opt_master_data && do_show_master_status(sock)) goto err;
在上一步中,我们给了server全局锁并且拿到了一致性事务视图,为了降低难度更是刷新了binlog文件,就可以放心的获取当前位点状态了。直接执行 SHOW MASTER STATUS 获取位点。
2.3.7. UNLOCK TABLES
1 2
if (opt_single_transaction && do_unlock_tables(sock)) /* unlock but no commit! */ goto err;
拿到了位点之后,需要将锁释放掉,让 Server 恢复读写,也因此,需要执行 SQL UNLOCCK TABLES。而接下来,我们就是要分情况去 dump 数据了。
2.3.8. DUMP
1 2 3 4 5 6 7 8 9 10 11 12
if (opt_alldbs) dump_all_databases(); elseif (argc > 1 && !opt_databases) { /* Only one database and selected table(s) */ dump_selected_tables(*argv, (argv + 1), (argc - 1)); } else { /* One or more databases, all tables */ dump_databases(argv); }
根据命令行传入的参数不同,决定是 dump 全量 DB 还是某个 DB 下的一些表还是某些 DB 下的所有表。