暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

这些Xtrabackup的问题你遇到过吗?

509

作者简介

追风,多年DBA一线经验,现某互联网大厂高级DBA,熟悉MySQL、Redis,对OceanBase等分布式数据库有一定经验。公众号<DBA修行之路>主理人,马六学专栏《一线DBA数据库实战经典案例30讲》作者。


如果你是从事MySQL数据库运维管理的工作,数据库的备份则会是日常必做的工作之一,备份可以选择逻辑备份和物理备份,其中谈到物理备份,便不可不说Xtrabackup工具。

在平时,也遇到过很多同学和朋友询问Xtrabackup工具的一些问题,所以今天,我想从理论到实战的角度来带你认识一下Xtrabackup工具。

按照侧重点不同,我将接下来的内容划分为四个部分,根据你感兴趣的点,你可以选择从第一部分开始,也可以选择跳过某些部分。

1 Xtrabackup的原理

Xtrabackup工具是Perocna公司开发的开源MySQL热备份工具,其版本跟着MySQL的版本进行升级,因此在实际备份时你需要注意使用对应的版本,大致可以参考如下:

一般生产上推荐的是:

  • 如果你的MySQL版本是8.0以下的,则建议使用xtrabackup2.4版本;

  • 如果你的MySQL大版本为8.0但是小版本是8.0.20以下的,则使用xtrabackup8.0.11版本;

  • 如果你的MySQL版本为8.0.20及以上的,则使用xtrabackup8.0.12及以上版本;

  • 在MySQL8.0.22之后,xtrabackup工具的版本号和MySQL版本号相对应。


因此,如果想了解更详细的兼容程度,你还可以通过官方文档查看:

https://docs.percona.com/percona-xtrabackup/8.0/server-backup-version-comparison.html


确定版本号后,了解Xtrabackup工具的备份原理对我们也是大有裨益的,这里根据备份原理不一样,分为xtrabackup2.4和xtrabackup8.x版本。

对于8.0.x之前的版本,以xtrabackup2.4为例,备份流程为:


对于于8.0.x及之后的版本,备份流程为:

官方社区版版本跟percona server的支持命令稍有差别,MySQL 8 中新增了一个轻量级的备份锁,备份锁由lock instance for backup和unlock instance语法组成。

注意,使用这些语句需要BACKUP_ADMIN权限。这在percona server中对应的命令是lock table for backup,除此,percona还支持通过lock binlog for backup和 unlock binlog命令来对binlog进行加锁和解锁,社区版是不支持这个命令的;


而对于恢复流程来说,简化后则是:

在备份阶段,xtrabackup是会创建两个线程的,就称为线程一和线程二吧,线程一用来监控事务日志,循环复制redo日志文件中的新增日志,线程二用来复制数据库表相关的文件,当线程二完成所有物理文件复制完成后,通知线程一停止事务日志复制,此时会将相应的一致性位点信息,事务日志等信息存放在xtrabackup_logfile,xtrabackup_checkpoints,xtrabackup_info三个文件中,在恢复时,通过物理文件加备份期间的事务日志及位点信息实现最终一致性。

在MySQL社区版8.0中,xtrabackup8.0在查询log_status时,mysql服务器会分别对Redo Log,Binlog加轻量级锁以获取一致性备份点,该过程时间非常短,对实例的运行影响可以忽略,xtrabackup可以从一致性备份点中获取到一致性的Redo Log LSN及Binlog日志的GTID位点,然后备份最后一个binlog,用与恢复时判断事务是否需要回滚,并且Redo Log复制进程会一直复制Redo Log直到读取到的Redo Log的LSN大于一致性备份点中的Redo Log LSN。


2 Xtrabackup的常见问题

日常使用Xtrabackup的过程中,你遇到过哪些xtrabackup问题呢,这里,我列举了之前工作中遇到的关于xtrabackup的一些问题,是否你也曾经遇到过呢?

2.1 备份页损坏场景

这种场景下一般日志中会有xtrabackup: Database page corruption detected at page xxxx, retrying等报错,这种情况是因为mysql的数据文件发生了损坏,而Xtrabackup在备份innodb表数据文件时,会检查每个页面的checksum,如果checksum值不对,则说明页已经被损坏,此时备份会失败,此时先要修复数据,可以通过myisamchk工具,percona-data-recovery-tool工具,或者设置innodb_force_recovery参数导出数据等几种方法尝试进行恢复后再进行备份,当然,数据页损坏问题后面我们也会单独讲述。


2.2 Redo日志覆盖场景

这种场景下一般日志中会有如下报错:

    xtrabackup: error: log block numbers mismatch:
    xtrabackup: error: expected log block no. 586990567, but got no. 587187167 from the log file.
    xtrabackup: error: it looks like InnoDB log has wrapped around before xtrabackup could process all records due to either log copying being too slow, or  log files being too small.

    这种情况一般是由于业务写入较快导致redo log写入速度很快或者redo log参数设置过小,redo log文件是循环写的,如果xtrabackup的redo log备份线程的速度低于redo log写入速度,导致新写入的日志覆盖之前写入但是还未备份的日志。从而导致备份报错,这种场景有三种解决方法,第一,先尝试调整备份策略,在业务低峰期进行备份。第二,调整redo log相关参数,涉及参数有innodb_log_file_size(设定单个redo日志文件大小),innodb_log_files_in_group(redo日志),修改这两个参数需要重启mysql服务。第三,如果前面两者不生效,需要从业务侧进行调整写入策略。


    2.3 获取mdl锁失败

    这种场景的现象一般是xtrabackup在启动后卡住并且redo log备份线程未启动。原因是xtrabackup在起始阶段兼容性检查表的引擎信息时候会查询information_schema.table插件表,查询对应的表时,需要获取对应表的mdl(元数据锁),如果此时有长时间的dml或者ddl语句或者mdl死锁情况发生,可能会导致查询一直卡住,此时如果只是sql语句导致的等待,则无需处理,如果是存在mdl死锁,则需要解决死锁问题。


    2.4 备份期间ddl操作

    这种场景一般会有如下报错:

      An optimized (without redo logging) DDLoperation has been performed. All modified pages may not have been flushed to the disk yet.PXB will not be able take a consistent backup. Retry the backup operation.

      导致备份失败的原因是备份期间发生了不记录redo log的ddl操作,这操作可能会导致数据不一致问题,因此备份失败,例如备份过程中进行索引创建操作,解决方法是在备份时添加lock-ddl,lock-ddl-timeout,lock-ddl-per-table等参数。


      2.5 rename table操作

      这种场景一般会有如下报错:

        Trying to add tablespace 'xxxx' with id xxx to the tablespace memory cache, but tablespace xxxx already exists in the cache!

        导致这种报错的原因是xtrabackup在打开表空间过程中是没有添加锁的,如果在这个过程中执行rename table操作则可能会重复加载相同的表空间,然后xtrabackup检测到相同的tablespace id,从而备份失败。这种情况发生的可能性较小,即使遇到了重新备份即可。


        2.6 打开文件个数限制报错

        这种场景一般会有如下报错:

          InnoDB: Operating system error number 24 in a file operation.
          InnoDB: Error number 24 means ‘Too many open files’ InnoDB: Some operating system error numbers are described at 

          导致这种报错的原因是xtrabackup在加载表空间时会同时打开所有表文件,如果实例的表个数较多,可能会触发该报错,解决方法是调整操作系统相关参数或者备份时使用lock-ddl,lock-ddl-timeout,lock-ddl-per-table等参数。

          调整方法参考:

          在/etc/security/limits.conf文件中设置,${username}替换为实际的操作系统用户即可。

            ${username} hard nofile 65535
            ${username} soft nofile 65535
            ${username} hard nproc 65535
            ${username} soft nproc 65535


            2.7 io_setup() failed报错

            这种场景一般会有如下报错:

              InnoDBWarningio_setup() failed with EAGAINWill make 5 attempts before giving up.

              造成该报错的原因是mysql启动时默认启用innodb_use_native_aio,使用异步IO操作,如果此时需要的aio slot大于系统设定的值,则会报上面的错,可以通过strace命令查看io_setup调用情况,可参考命令:

                strace -fe trace=io_setup path/to/mysqld --defaults-file=/etc/my.cnf --daemonize 2>&1 |grep io_setup

                解决该问题方法是调整值,可通过编辑/etc/sysctl.conf文件修改fs.aio-max-nr参数值后执行sysctl -p命令刷新或者直接执行sysctl fs.aio-max-nr=修改后的值,注意修改后的值应大于实例的fs.aio-nr值。


                2.8 truncate table/partition操作

                这种场景一般可以在备份期间避免该操作或者添加lock-ddl,lock-ddl-timeout,lock-ddl-per-table等参数。


                3 Xtrabackup之bug

                除了一些参数或者不规范的操作可能会导致xtrabackup工具备份失败,我们在使用xtrabackup时候也会遇到一些其本身的bug导致备份失败,结合之前的工作经历,列举我遇到过的一些bug。

                3.1 undo truncate操作

                这种场景一般会有如下报错:

                  An undo ddl truncation (could be automatic) operation has been performed.

                  导致该报错的原因是在备份期间实例自己触发或人工执行undo truncate操作导致写新undo文件时undo日志丢失而恢复失败,在xtrabackup中针对mysql8.0.21对该问题进行了不完全的修复,即在备份时解析到undo log的truncate操作时自动备份失败。可以通过在备份时关闭undo tablespace的truncate操作并禁止人工创建undo tablespace解决。


                  3.2 版本过低无法识别redo日志

                  这种场景一般会有如下报错:

                    Unknown redo log format (4). Please follow the instructions at http://dev.mysql.com/doc/refman/8.0/en/ upgrading-downgrading.html.

                    导致该报错的原因是因为在mysql8.0中,对redo log的日志格式进行了修改,导致在备份时无法识别,这种情况一般替换xtrabackup包为合适的版本重新备份即可。

                    之前遇到过一次xtrabackup版本过低导致备份失败的问题,报错中还有####CORRUPT LOG RECORD FOUND###报错,这种很容易误判为是由于页损坏导致备份失败。

                    更多的,例如,在用xtrabackup8.0.14来备份mysql8.0.22会触发异常BUG,实际上,mysql8.0.24是一个过渡版本,生产上不建议使用。

                    报错信息参考:

                      stack_bottom = 0 thread_stack 0x46000
                      xtrabackup8(my_print_stacktrace(unsigned char const*, unsigned long)+0x2e) [0x230b55e]
                      xtrabackup8(handle_fatal_signal+0x2eb) [0x11b729b]
                      /lib64/libpthread.so.0(+0xf6d0) [0x7fd7318246d0]
                      xtrabackup8(dd::get_dd_client(THD*)+0x1) [0x16c8061]
                      xtrabackup8(dd_table_open_on_name(THD*, MDL_ticket**, char const*, boolunsigned longint*)+0x53a) [0x137306a]
                      xtrabackup8() [0xcc9f5e]
                      xtrabackup8() [0xccb060]
                      xtrabackup8(main+0xca9) [0xc8ad19]
                      /lib64/libc.so.6(__libc_start_main+0xf5) [0x7fd72f697445]
                      xtrabackup8() [0xcb7bb7]
                      Please report a bug at https://jira.percona.com/projects/PXB


                      3.3 innodb_log_compressed_pages参数问题

                      这也是之前遇到过的一个备份问题,现象为备份能够正常结束,但是在recover恢复的时候失败,报错如下:

                        stack_bottom = 0 thread_stack 0x10000
                        xtrabackup(my_print_stacktrace+0x2c)[0xcef4ac]
                        xtrabackup(handle_fatal_signal+0x262)[0xa06812]
                        /lib64/libpthread.so.0(+0xf5e0)[0x7f4ea976d5e0]
                        /lib64/libc.so.6(gsignal+0x37)[0x7f4ea73f01f7]
                        /lib64/libc.so.6(abort+0x148)[0x7f4ea73f18e8]
                        xtrabackup[0x6f4849]
                        xtrabackup[0x80fb61]
                        xtrabackup(_Z22recv_recover_page_funcmP11buf_block_t+0xacc)[0x810cbc]
                        xtrabackup(_Z20buf_page_io_completeP10buf_page_tb+0x485)[0x8f0225]
                        xtrabackup(_Z12fil_aio_waitm+0x12f)[0x8b5d0f]
                        xtrabackup(io_handler_thread+0x28)[0x7e5788]
                        /lib64/libpthread.so.0(+0x7e25)[0x7f4ea9765e25]
                        /lib64/libc.so.6(clone+0x6d)[0x7f4ea74b334d]

                        Bug地址如下:

                        https://bugs.launchpad.net/percona-xtrabackup/+bug/1736139


                        解决方法是修改innodb_log_compressed_pages值为on重新备份

                        除此之外,之前还听一些朋友反馈过连续ddl操作导致误删ibd文件,8.0分区表交换操作之类的bug。如果你也遇到了,欢迎一起交流。


                        4 Xtrabackup全备多场景实践

                        如果你看过了前面3个小节,相信你对xtrabackup已经有了较深刻的了解,那么本小节就真正的实践一下吧。在使用XtraBackup工具对MySQL 数据库备份恢复时,从恢复时间,负载影响,文件大小三个需求角度考虑,思考如何不同场景完美达成我们的备份目标。

                        如果你本地没有对应的xtrabackup文件,可以在官网进行下载,下载后你就可以尝试进行对你的MySQL数据库进行备份操作了,当然操作之前,下面的一些小知识你可以了解一下。

                        在Percona XtraBackup 8.0之前,Percona XtraBackup工具中,xtrabackup是备份的主程序,在Percona XtraBackup 8.0之前,除了xtrabackup文件,还有innobackupex 文件,不过它只是xtrabackup 的一个软链。

                        Percona XtraBackup工具支持支持流备份,将备份数据以数据流的方式输出,使用 --stream 选项可以实现流备份,Percona xtrabackup支持tar格式的流备份和xbstream格式的流备份两种流备份。

                        结合小知识和需求角度,我们就可以正式进入今天的多场景实践了。

                        根据是否跨机备份,是否压缩,压缩方式及Percona XtraBackup 8.0,我们可以使用不同的备份方式。

                        tar方式备份到本地不压缩:

                          /root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/innobackupex --defaults-file=/opt/mysql/etc/3310/my.cnf --host=localhost --port=3310 --user=root --password='xxx' --socket=/opt/mysql/data/3310/mysqld.sock --stream=tar data >/data/backup/data_xx_xx.tar


                          tar方式备份到本地压缩:

                            /root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/innobackupex --defaults-file=/opt/mysql/etc/3310/my.cnf  --host=localhost  --port=3310 --user=root --password='xxx'  --socket=/opt/mysql/data/3310/mysqld.sock  --stream=tar     data |gzip>/data/backup/data_xx_xx.tar


                            tar方式跨机备份不压缩:

                              /root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/innobackupex --defaults-file=/opt/mysql/etc/3310/my.cnf  --host=localhost  --port=3310 --user=root --password='xxx'  --socket=/opt/mysql/data/3310/mysqld.sock  --stream=tar     data |sshpass -p 'xxx' ssh root@xxx  "cat - > data/backup/data_xx_xx.tar"


                              tar方式跨机备份压缩:

                                /root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/innobackupex --defaults-file=/opt/mysql/etc/3310/my.cnf  --host=localhost  --port=3310 --user=root --password='xxx'  --socket=/opt/mysql/data/3310/mysqld.sock  --stream=tar     data |sshpass -p 'xxx' ssh root@xxx  "gzip > data/backup/data_xx_xx.tar"


                                xbstream方式备份到本地压缩:

                                  /root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/innobackupex --defaults-file=/opt/mysql/etc/3310/my.cnf --host=localhost --port=3310 --user=root --password='xxx' --socket=/opt/mysql/data/3310/mysqld.sock --stream=xbstream --parallel=8 --compress --compress-threads=8 data/ >/data/backup/data_xx_xx.xbstream


                                  xbstream方式备份到本地压缩不释放流文件:

                                    /root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/innobackupex --defaults-file=/opt/mysql/etc/3310/my.cnf --host=localhost --port=3310 --user=root --password='xxx' --socket=/opt/mysql/data/3310/mysqld.sock --stream=xbstream --parallel=8 --compress --compress-threads=8 /data/ | sshpass -p 'xxx' ssh root@xxx "cat - >/data/backup/data_xx_xx.xbstream"


                                    xbstream方式备份到本地压缩同时释放流文件:

                                      /root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/innobackupex --defaults-file=/opt/mysql/etc/3310/my.cnf --host=localhost --port=3310 --user=root --password='xxx' --socket=/opt/mysql/data/3310/mysqld.sock --stream=xbstream --parallel=8 --compress --compress-threads=8 /data/ | sshpass -p 'xxx' ssh root@xxx "/root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/xbstream -x -C /data/restore/"


                                      Xtrabackup8.0.x跨机备份:

                                        /root/backup/percona-xtrabackup-8.0.35-31-Linux-x86_64.glibc2.17/bin/xtrabackup --defaults-file=/opt/mysql/my3310.cnf --host=localhost --port=3310 --user=root --password='xxx' --socket=/opt/mysql/data3310/mysqld.sock --stream=xbstream --parallel=8 --compress --compress-threads=8 --backup --target-dir=/data/backup | sshpass -p 'xxx' ssh root@xxx "/root/backup/percona-xtrabackup-2.4.26-Linux-x86_64.glibc2.12/bin/xbstream --C /data/restore/"


                                        按照上面的命令,你可以自己测试一下不同方式备份所需的时间,备份集文件的大小,如果没有环境,可以参考我之前的测试的结果:

                                        在现场允许配置机器远程免密访问或者对端机器操作系统用户密码的场景下,推荐使用跨机备份,总体耗费时间会更少。

                                        进行备份时 –stream=xbstream 模式下备份文件大小和备份耗费时长两者都用得到较好的兼顾,较为推荐。

                                        如果磁盘空间极为紧张且能容忍备份耗费时间较长,可选择 --stream=tar + gzip 命令组合的压缩备份方式。

                                        还有一点,我想提醒的是在备份时,一个良好的建议是设置 --kill-long-queries-timeout,--ftwrl-wait-timeout,--ftwrl-wait-threshold,--use-memory,--throttle 等参数对长查询,内存,IO 方面进行合理的限制,或者选择对从实例进行备份(如果主从不同步,则备份为无效备份,可以对主从同步进行监控,同步正常情况下在从库进行备份)。


                                        5 总结

                                        本篇到此也就结束了,小结一下,我们从xtrabackup的版本差异,备份原理说起,然后介绍了xtrabackup实践过程中遇到的一些常见问题,以及bug,最后末尾,从实践出发,在时间,文件大小,版本等方面考量,如何在生产环境进行实际备份工作。

                                        相信阅读完该篇,对xtrabackup工具你会有一个深层次的认知。

                                        今日份思考:在使用Xtrabackup进行物理备份时,一般是进行实例级别的备份,你尝试过使用xtrabackup工具对部分数据备份嘛,欢迎留言?


                                        最后但同样重要的是:
                                        作者追风最近在马六学平台上线了图文专栏《一线DBA数据库实战经典案例30讲》。
                                        原价60¥,目前享早鸟价39.9¥
                                        小程序:


                                        网页端:

                                        https://www.maliustudy.com/detail/column/325

                                        或者点击下方阅读原文查看。

                                        文章转载自MySQL数据库联盟,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                        评论