目录
[1 mydumper参数解释](#1 mydumper参数解释)
[表数据 文件](#表数据 文件)
[表结构 文件](#表结构 文件)
原来一直使用mysqldump 和 xtrabackup对MySQL数据库进行逻辑备份和物理备份,最近在生产环境接触到了一种新的备份恢复工具 mydumper ,这里介绍总结一下自己的使用经验以及遇到的问题。
什么是MyDumper
MyDumper是一个MySQL逻辑备份工具。它有2个工具:
mydumper
负责导出 MySQL 数据库的一致备份myloader
从 mydumper 读取备份,连接到目标数据库并导入备份。
这两个工具都使用多线程功能。
MyDumper优势有哪些
- 速度更快 - 多线程并发备份
- 性能更好 - 避免昂贵的字符集转换,整体代码高效
- 易于管理的输出文件 -(比如每个表都能生成单独的备份文件,备份的元数据信息文件metadata记录位点信息等等,便于查看/解析数据)
- 备份一致性 - 维护所有线程的快照,提供准确的主从日志位置等
- 可管理性高- 支持通过PRRE(正则表达式) 指定或者排除特定的库和表
什么是 PRRE
PCRE 是 "Perl Compatible Regular Expressions"(兼容 Perl 正则表达式)的缩写。它是一个正则表达式库,提供对正则表达式的支持,并且与 Perl 的正则表达式语法高度兼容。
如何安装MyDumper
这里介绍离线安装 ,生产服务器一般没有外网
下载rpm 包地址 Tags · mydumper/mydumper · GitHub
bash
centos 系统
# 下载rpm
wget https://github.com/mydumper/mydumper/releases/download/v0.15.2-6/mydumper-0.15.2-6.el7.x86_64.rpm
# 安装
rpm -ivh mydumper-0.15.2-6.el7.x86_64.rpm
安装完成之后会 mydumper 和 myloader都会被安装
bash
$ mydumper --version
mydumper v0.15.2-6, built against MySQL 5.7.43-47 with SSL support
$ myloader --version
myloader v0.15.2-6, built against MySQL 5.7.43-47 with SSL support
mydumper 与 MySQL版本对应关系?
参数解释
,每个版本的参数略有差异,下面是针对版本 v0.15.2-6 进行的参数解释
1 mydumper参数解释
|------------------------------|-----|------------------------------------------------------------------------------------------------------------------------|
| 长参数 | 短参数 | 参数解释 |
| 连接参数 |||
| --host | -h | 连接的数据库服务器 |
| --user | -u | 需要特性权限的用户 |
| --password | -p | 用户的密码 |
| --ask-password | -a | 提示输入用户的密码 |
| --port | -P | TCP/IP 端口 |
| --socket | -S | 用于连接的 UNIX 域套接字文件 |
| --protocol | | 用于连接的协议(tcp、socket) |
| --compress-protocol | -C | 对 MySQL 连接使用压缩 |
| --ssl | | 使用 SSL 连接 |
| --ssl-mode | | 连接到服务器所需的安全状态:DISABLED、PREFERRED、REQUIRED、VERIFY_CA、VERIFY_IDENTITY |
| --key | | 密钥文件的路径名 |
| --cert | | 证书文件的路径名 |
| --ca | | 证书颁发机构文件的路径名 |
| --capath | | 包含 PEM 格式的受信任 SSL CA 证书的目录的路径名 |
| --cipher | | 用于 SSL 加密的允许密码列表 |
| --tls-version | | 服务器允许哪些协议进行加密连接 |
| 匹配过滤参数 |||
| --regex | -x | 'db.table' 匹配的正则表达式 |
| --database | -B | 需要备份的数据库 |
| --ignore-engines | -i | 要忽略的存储引擎的列表 ,逗号分隔 |
| --where | | 仅转储选定的记录 |
| --updated-since | -U | 使用 Update_time 仅转储最近 U 天内更新的表 |
| --partition-regex | | 按分区名称过滤的正则表达式。 |
| --omit-from-file | -O | 包含要跳过的数据库.表条目列表的文件,每行一个(在应用正则表达式选项之前跳过) |
| --tables-list | -T | 要备份的表列表,以逗号分隔(不排除正则表达式选项)。 表名必须包含数据库名。 例如:test.t1,test.t2 |
| 锁参数 |||
| --tidb-snapshot | -z | 使用 TiDB 快照 |
| --no-locks | -k | 不执行 临时共享读锁 ,警告⚠️:这将会导致非一致性备份 |
| --use-savepoints | | 使用 savepoints 来减少元数据锁的产生,需要 SUPER 权限 |
| --no-backup-locks | | 不使用 Percona 的 backup locks (备份锁) |
| --lock-all-tables | | 对所有的表 LOCK TABLE,而不是使用FTWRL |
| --less-locking | | 对于 InnoDB 存储引擎的表 最少的锁时间 |
| --trx-consistency-only | | 只有事务一致性 |
| PMM参数 |||
| --pmm-path | | 默认值为 /usr/local/percona/pmm2/collectors/textfile-collector/high-resolution |
| --pmm-resolution | | 默认值较高 |
| EXEC参数 |||
| --exec-threads | | 与 --exec 一起使用的线程数量 |
| --exec | | 使用文件作为参数执行命令 |
| --exec-per-thread | | 设置将由 STDIN 接收并将 STDOUT 写入输出文件的命令 |
| --exec-per-thread-extension | | 使用 --exec-per-thread 时设置 STDOUT 文件的扩展名 |
| 长查询参数 |||
| --long-query-retries | | 重新检查长查询 ,默认0 ,不糊重试 |
| --long-query-retry-interval | | 长查询检测的间隔 ,默认60秒 |
| --long-query-guard | -l | 设置长查询的时间阈值 ,默认60秒 |
| --kill-long-queries | -k | kill 长查询 |
| Job参数 |||
| --char-deep | | 定义当主键是字符串时要使用的字符数 |
| --char-chunk | | 定义应将表拆分为多少部分。 默认情况下我们使用线程数量 |
| --rows | | 将表拆分为这么多行的块。 它可以是 MIN:START_AT:MAX。 MAX 可以为 0,表示没有限制。 如果查询时间少于 1 秒,则块大小将加倍;如果查询时间超过 2 秒,则块大小减半 |
| --split-partitions | | 将分区转储到单独的文件中。 此选项会覆盖分区表的 --rows 选项。 |
| 校验参数 |||
| --checksum-all | -M | 转储所有对象的校验和 |
| --data-checksums | | 转储表与数据 校验和 |
| --schema-checksums | | 转储模式表和视图创建校验和 |
| --routine-checksums | | 转储触发器、函数和例程 校验和 |
| 备份对象参数 |||
| --no-schemas | -m | 不备份表的数据库 |
| --all-tablespaces | -Y | 备份所有表空间 |
| --no-data | -d | 不备份表的数据 |
| --triggers | -G | 备份触发器。默认情况下不备份 |
| --events | -E | 备份事件。默认情况下不备份 |
| --routines | -R | 备份存储过程和函数。默认情况下不备份 |
| --views-as-tables | | 将视图作为表导出 |
| --no-views | -W | 不要备份视图 |
| Statement参数 |||
| --load-data | | 不创建 INSERT INTO 语句,而是创建 LOAD DATA 语句和 .dat 文件 |
| --csv | | 自动启用--load-data 并设置变量以 CSV 格式导出 |
| --fields-terminated-by | | 定义分割字段的字符。 |
| --fields-enclosed-by | | 定义包围字段的字符。 默认: " |
| --lines-starting-by | | 在每行的开头添加字符串。 使用 --load-data 时,它会添加到 LOAD DATA 语句中。 当使用它时,它也会影响 INSERT INTO 语句。 |
| --lines-terminated-by | | 在每行末尾添加字符串。 当使用 --load-data 时,它被添加到 LOAD DATA 语句中。 当使用它时,它也会影响 INSERT INTO 语句。 |
| --statement-terminated-by | | 这可能永远不会被使用,除非你知道你在做什么 |
| --insert-ignore | -N | 使用 INSERT IGNORE 备份行 |
| --replace | | 用 REPLACE 替换备份行 |
| --complete-insert | | 使用包含列名的完整 INSERT 语句 |
| --hex-blob | | 使用十六进制表示法转储二进制列 |
| --skip-definer | | 从 CREATE 语句中删除 DEFINER。 默认情况下,语句不被修改 |
| --statement-size | -s | 尝试的 INSERT 语句大小(以字节为单位),默认 1000000 |
| --tz-utc | | SET TIME_ZONE='+00:00' 在转储顶部,允许在服务器具有不同时区的数据或数据在不同时区的服务器之间移动时转储 TIMESTAMP 数据,默认为使用 - -skip-tz-utc 禁用。 |
| --skip-tz-utc | | 不在备份文件上添加 SET TIMEZONE |
| --set-names | | 设置名称,使用它需要您自担风险,默认二进制文件 |
| Extra参数 |||
| --chunk-filesize | -F | 将表分割成此输出文件大小的块。 该值以 MB 为单位 |
| --exit-if-broken-table-found | | 如果发现损坏的表则退出 |
| --success-on-1146 | | 如果表不存在,则不增加错误计数并发出警告而不是错误 |
| --build-empty-files | -e | 即使表中没有可用数据也构建转储文件 |
| --no-check-generated-fields | | 与生成字段相关的查询不会被执行。如果您生成了列,则会导致恢复问题 |
| --order-by-primary | | 如果不存在主键,则按主键或唯一键对数据进行排序 |
| --compress | -c | 使用 /usr/bin/gzip 和 /usr/bin/zstd 压缩输出文件。 选项:GZIP 和 ZSTD。 默认值:GZIP |
| Daemon参数 |||
| --daemon | -D | 后台运行 |
| --snapshot-interval | -I | 每个转储快照之间的间隔(以分钟为单位),需要 --daemon,默认 60 |
| --snapshot-count | -X | 快照数量,默认2 |
| Application参数 |||
| --help | -? | 显示帮助选项 |
| --outputdir | -o | 输出文件的目录 |
| --stream | | 一旦文件被写入,它将通过 STDOUT 流式传输。 自 v0.12.7-1 起,接受 NO_DELETE、NO_STREAM_AND_NO_DELETE 和 TRADITIONAL(默认值),如果未给出参数则使用 |
| --logfile | -L | 要使用的日志文件名,默认情况下使用 stdout |
| --disk-limits | | 如果确定没有足够的磁盘空间,则设置暂停和恢复的限制。接受类似以下值:'<resume>:<pause>'(以 MB 为单位)。例如:100:500 将在只有 100MB 时暂停 免费,如果有 500MB 可用则恢复 |
| --threads | -t | 要使用的线程数,默认 4 |
| --version | -V | 显示程序版本并退出 |
| --identifier-quote-character | | 设置标识符引号字符,仅用于在 mydumper 上插入语句以及在 myloader 上分割语句。 使用 SQL_MODE 更改 CREATE TABLE 语句,可能的值有:BACKTICK 和 DOUBLE_QUOTE。 默认值:反引号 |
| --verbose | -v | 输出的详细程度,0 = silent, 1 = errors, 2 = warnings, 3 = info, default |
| --defaults-file | | 使用特定的默认文件。 默认值:/etc/mydumper.cnf |
| --defaults-extra-file | | 使用额外的默认文件。 这是在 --defaults-file 之后加载的,替换以前定义的值 |
| --fifodir | | 需要时将在其中创建 FIFO 文件的目录。 默认值:与备份相同 |
备份流程
备份过程主要步骤概括:
- 主线程 FLUSH TABLES WITH READ LOCK , 施加全局只读锁,以阻止 DML 语句写入,保证数据的一致性;
- 读取当前时间点的二进制日志文件名和日志写入的位置并记录在 metadata 文件中,以供即时点恢复使用;
- N 个(线程数可以指定,默认是 4个)dump 线程 START TRANSACTION WITH CONSISTENT SNAPSHOT ; 开启读一致的事物;
- dump non-InnoDB tables , 首先导出非事物引擎的表;
- 主线程 UNLOCK TABLES 非事物引擎备份完后,释放全局只读锁;
- dump InnoDB tables , 基于事物导出 InnoDB 表;
- 事物结束。
更详细的流程
1)该工具在--daemo模式下支持以守护进行形式启动,默认每60s进行一次备份。间隔时间由--snapshot-interval控制。
2)首先会创建一个MySQL服务的连接
3)然后在MySQL上执行show processlist,根据参数long-query-guard和kill-long-queries决定退出或杀掉长查询;
4)根据是否有--lock-all-tables,进行锁表:LOCK TABLE tn READ或者FLUSH TABLES WITH READ LOCK;然后执行START TRANSACTION;
5)创建4个备份表的子线程
6)创建1个work thread后,g_async_queue_pop(conf.ready);此时conf.ready为空需要sleep等待。
7)work线程执行:连接mysql;设置隔离级别RR;start transaction;g_async_queue_push(conf->ready,GINT_TO_POINTER(1));然后main函数的g_async_queue_pop挂住的地方可以唤醒了,继续创建线程或者向下走。
8)work线程接着执行:进入死循环,从队列里pop出任务job=(struct job *)g_async_queue_pop(conf->queue);,根据任务类型进行dump。这里的并行是根据表并行的。先备份非事务表,然后备份innodb表
9)最后等所有work线程完成非事务表备份后唤醒g_async_queue_pop(conf.unlock_tables);,执行UNLOCK TABLES解锁
10)事务结束
一致性快照如何工作?
这一切都是按照 MySQL 最佳实践和传统完成的:
- 作为预防措施,服务器上运行长查询要么会中止备份 ,要么被杀死
- 获取全局读锁("FLUSH TABLES WITH READ LOCK")
- 读取各种元数据("SHOW SLAVE STATUS"、"SHOW MASTER STATUS")
- 其他线程连接并建立快照("START TRANSACTION WITH CONSISTENT SNAPSHOT") ** 在 4.1.8 之前的版本中,它创建虚拟 InnoDB 表并从中读取。
- 一旦所有工作线程宣布快照建立,主线程就会执行"UNLOCK TABLES" 并开始排队作业。
FLUSH TABLES WITH READ LOCK; 全局读锁 ,所有的表只能进行读,不能进行写;
START TRANSACTION WITH CONSISTENT SNAPSHOT; 这个语句的目的是在事务开始时创建一个一致性的数据库快照,通过MVCC机制确保在整个事务执行期间,事务看到的数据保持一致性。
如何排除(或包含)数据库?
可以使用--regex功能,例如不转储mysql和测试数据库:
bash
# 可以使用--regex功能,例如不备份 mysql 和 test 数据库:
mydumper --regex '^(?!(mysql\.|test\.))'
# 仅备份 mysql 和 test 数据库:
mydumper --regex '^(mysql\.|test\.)'
# 不备份以 test 开头的所有数据库:
mydumper --regex '^(?!(test))'
# 转储不同数据库中的指定表
mydumper --regex '^(db1\.table1$|db2\.table2$)'
# 如果你想备份几个数据库但丢弃一些表,你可以这样做:
mydumper --regex '^(?=(?:(db1\.|db2\.)))(?!(?:(db1\.table1$|db2\.table2$)))'
输出文件
版本 mydumper 0.10.0
Metadata文件
当备份正在执行的时候会有文件 metadata.partial 生成,当备份顺利完成之后 重命名为 metadata。该文件中包含备份启动与完成的时间 ,主库二进制日志的文件与位点。
表数据 文件
每个表的文件都会写到单独的文件中,文件的命名如下
bash
database.table.sql(.gz|.zst)
如果使用了 --rows 选线,每个表的备份都会被分割成多个文件,文件后会有5个数字填充,格式如下
bash
database.table.chunk.sql(.gz|.zst)
表结构 文件
如果没有使用选项 --no-schemas ,每个表都会生成一个表结构的备份文件 格式如下
bash
database.table-schema.sql(.gz|.zst)
建库文件
database-schema-create.sql(.gz|.zst)
总结
可能各个版本备份出来的文件命名稍有不同,从文件命名可以较为明显的看出该文件的内容,大致总结下文件命名规则如下:
- dbname-schema-create.sql:建库语句。
- dbname-schema-post.sql:包含事件、存储过程及函数创建语句(若存在则有该文件)。
- dbname.tbname.metadata:记录这个表的行数。
- dbname.tbname-schema.sql:此表的创建语句。
- dbname.tbname-schema-triggers.sql:创建触发器语句(若该表存在触发器 则有此文件)。
- dbname.tbname.sql:该表的插入数据语句(若该表为空 则不存在此文件)。
- dbname.viewname-schema.sql:创建视图语句(只列举出视图字段)。
- dbname.viewname-schema-view.sql:创建视图的真正语句。
- metadata:记录开始及结束备份的时间以及二进制日志位置。
使用示例
参考
Github
GitHub - mydumper/mydumper: Official MyDumper Project
输出文件
备份原理图