ITPub博客

首页 > 数据库 > 数据库开发技术 > mysql每天一点点笔记(八)

mysql每天一点点笔记(八)

原创 数据库开发技术 作者:DBA修行之路 时间:2022-04-15 08:22:46 0 删除 编辑

文字表述

文字表述

文字表述

左右滑动查看更多



点击上方“蓝字”,发现更多精彩。





mysql每天一点点笔记(八)


今日内容

在mysql中,为了防止数据误操作后无法恢复,我们一般会定期对数据进行备份,根据备份的方式不同可以分为逻辑备份和物理备份,可用的工具有mysqldump,xtrabackup。而今天复习的内容正是xtrabackup。为了便于后期进行温故和理解,哈哈,怕时间久了之前记录的东西连自己都看不懂,将关键部分进行了划分,分为四个模块,版本划分,备份原理,备份异常场景,备份bug场景,虽然备份异常场景和备份bug场景的最终结果都是失败,但是自己感觉本质上还是不同的,所以单独分开了。

从上图可以看出,特别针对8.0之前和8.0之后进行了一个版本划分,是因为8.0前后,无论是mysql还是xtrabckup都有了较大的变化。另外,图中遇到的异常场景,一些是自己遇到的,还有一些是其他小伙伴或同事遇到的,虽然暂时自己没遇到,万一自己以后也遇到了呢,不是就可以站在前人的肩膀上少踩一些坑了嘛。现在,一起来学习吧。



备份版本

xtrabackup的版本最早是1.6版本,其间经历2.0版本,2.1版本等等,详细如下图:

从图中可以看出,xtrabackup的版本是比较多的,但是2.3及之前的版本已经不再维护,因此不建议使用,一般生产上推荐的是:

1.如果你的mysql版本是8.0以下的,则建议使用xtrabackup2.4版本。

2.如果你的mysql大版本为8.0但是小版本是8.0.20以下的,则使用xtrabackup8.0.11版本。

3.如果你的mysql版本为8.0.20及以上的,则使用xtrabackup8.0.12版本。

这里有两方面的原因,一方面,由于mysql8.0载数据字典,redo log及undo log中的更改与之前的版本不兼容,因此xtrabackup8.0版本不支持备份mysql8.0之前的版本,Percona Server for MySQL或Percona XtraDB Cluster中创建的数据库。另外,Xtrabackup8.0直到8.0.11版本与MySQL8.0.20及以上版本或基于它的Percona产品不兼容。另外一方面,在可支持的范围内,建议使用较新的版本,因为新的版本会修复一些历史的bug问题,稳定性更好。


Xtrabackup支持Innodb,XtraDB,MyRocks的非阻塞备份,支持MyISAM,Merge,Archive引擎的备份期间暂停写入备份。以下几点需要注意:

1.Xtrabackup2.4仅支持Percona XtraDB Cluster 5.7,不支持MyRocks或TokuDB存储引擎,与MariaDB10.3及更高版本不兼容。。

2.Xtrabackup8.0从8.0.6版本开始支持MyRocks引擎,不支持TokuDB引擎。

3.Xtrabackup2.4流备份格式支持tar,xbstream,Xtrabackup8.0.*只支持xbstream。



备份原理

这里以社区版为例:

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

对于8.0及之后的版本,以xtrabackup8.0为例,备份流程为:

对于恢复流程,简化来说就是:

这里注意的几点是:

1.在mysql8.0中,还有一种情况会在备份时执行ftwrl操作,即备份从库,且从库没有开启gtid。可参考https://www.percona.com/doc/percona-xtrabackup/8.0/how_xtrabackup_works.html。

2.官方社区版版本跟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进行加锁和解锁,社区版是不支持这个命令的;

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

4.在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。




备份异常

xtrabackup备份异常场景暂时梳理了以下8种场景,后续如果有新的再进行补充吧。


1.备份页损坏场景:

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


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服务。第三,如果前面两者不生效,需要从业务侧进行调整写入策略。


3.获取mdl锁失败:

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


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等参数。


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,从而备份失败。这种情况发生的可能性较小,即使遇到了重新备份即可。


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


7.io_setup() failed报错:

这种场景一般会有如下报错InnoDB: Warning: io_setup() failed with EAGAIN. Will 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值。


8.truncate table/partition操作:

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





备份bug

xtrabackup备份bug场景暂时梳理了以下5种场景,有2种是自己遇到的,其他是其他小伙伴或同事遇到的,看到了便也记录下来了,是后续如果有新的再进行补充吧。


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解决。


2.8.0分区表交换操作:

这个bug也不是太清楚,先记录一下占个坑位吧,以后遇到了再回来补充。


3.版本过低无法识别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*, bool, unsigned long, int*)+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


4.连续ddl操作导致误删ibd文件

这种场景不是很清楚,是之前一个小伙伴遇到过的,我这边也没有实际验证过,解决方法就是在备份期间禁止ddl操作或者备份时添加lock-ddl,lock-ddl-timeout,lock-ddl-per-table等参数。


5.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重新备份,有空的时候再细分析下这个bug吧。


自问自答

Q:
1.备份时日志位点问题?

无论是社区版8.0之前通过ftwrl阻塞写操作,还是社区版8.0以后通过查询performance.log_status表获取一致性位点,或是percona server通过加binlog锁防止新事务提交,另外,备份完成后redo位点一般是比binlog位点多的,以保证复制的 redo log该提交的都有commit log的信息,多余的redo log在apply过程中奔溃恢复时回滚就行,而这一切都是为了保证恢复时获得一致性数据。

Q:
全局读锁VS备份锁?

在社区版中,8.0之前使用xtrabackup备份过程中都会有ftwrl加全局读锁的阶段,此时会刷新表,存储引擎会强制关闭表,将表从缓存中排出,所有表的更新操作及ddl都会阻塞。8.0之后新增了轻量级的备份锁,支持备份时innodb表进行dml操作及很多8.0之前不支持的操作,少量的禁止的操作有文件的创建,删除,重命名,账户的管理以及repair table,truncate table,optimize table这些操作。

Q:
备份时ddl不记录redo log问题?

在mysql5.7之前,mysql创建索引会调用insert apis单条进行b+树的插入,可能会导致大量页分裂与合并操作,还需要查找插入位置,导致开销比较大,5.7后使用Sorted Index方式创建索引的时候会关闭掉Redo Logging,但是这可能会导致备份报错。创建索引详细流程暂时不深究,一点一点学,慢慢来,比较快。xtrabackup引入了--lock-ddl选项来解决这个问题。但是--lock-ddl不是所有mysql分支都支持,例如mariadb,更建议使用通用的--lock-ddl-per-table参数。另外,如果想避免在备份时导致阻塞,可以打开old_alter_table参数。lock-ddl-timeout参数的作用是如果规定时间内无法获取备份锁,则本次备份自动失败。


结尾小结

好几周没更新日记了,最近在看xtrabackup备份这一块的知识点,一方面是感觉对xtrabackup备份流程这一块还有很多困惑,这几天也在向认识的一些大佬在请教。另外一方面,最近自己在新学习mongo数据库的课程。之前对mongo没咋接触,学习起来还是要花些精力的。就一直这么拖着了。哈哈,初学了一遍mongo,感觉mongo跟mysql,redis相比,也有很多亮点,等二刷课程的时候再献上笔记吧,哈哈,偏题了,回到主题吧,本次笔记主要是梳理了下xtrabackup的版本问题,8.0前后备份的原理差异,以及我和认识的一些小伙伴们踩到的一些坑,希望对你有帮助。也不枉费大早上跑起来写昨晚没搞完的笔记了。




END



扫码关注我
每天进步一点点,未来才可期。如果你也渴望成长,可以添加微信xuwl_1234,我们一起学习,一起探讨。
赞一下你最美!

原文作者:DBA修行之路;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2021-05-25

  • 博文量
    64
  • 访问量
    23943