pg_basebackup热备如何保证数据一致性
所谓热备就是在数据库不停机的情况下对数据做备份,不影响数据业务,在备份过程中数据不断的改变,PG是如何保证即使数据改变了也能不影响备份呢,这里WAL LOG起了很重要的作用,使用一份基础数据加上一些增量数据能实现这个过程。
PG的备份使用了基础文件加上WAL LOG来保证数据的一致性,基础文件是写入到磁盘的已经固化下来的数据,这通过在备份前做一次checkpoint来保证内存中的脏数据全部刷新到磁盘中,而WAL LOG保存的是在备份过程中改变的数据,这样,利用基础文件+WAL 日志可以将数据库推到一个数据一致的时间点。
1、 开始备份,设置force_page_writes=true
2、 做一次checkpoint将脏数据刷新到磁盘
3、 开始拷贝数据,同时开始用流复制的方式复制备份过程中产生的WAL日志
以上基础文件+WAL文件看似完美,但实际上不是这样的,因为操作系统不能保证PG的数据页完整的写入到磁盘中。
在PG服务器上,内存中的脏页是持续的写入到磁盘中的,写入过程中一般是以页为单位来操作,如果在内存数据刷盘得时候正好去拷贝数据,很有可能拷贝到半页数据,PG默认每个page的大小为8K,一般情况下,PG数据页是以page为单位写入的,但在断电,操作系统崩溃或者热操作(热备)时,极有可能导致部分数据快只写到4K(操作系统一般是以4K为单位写磁盘),这些“部分写”的页面包含新旧数据的混合,在崩溃后的恢复期间,由于页已经是损坏的页,无法恢复,而在WAL日志里面存储的记录变化信息不够完整,也无法恢复该页,导致数据库启动失败。
1、 用户DML操作,比如update数据
2、 数据从磁盘读入到内存,并在内存中做了修改,产生脏数据
3、 内存中脏数据刷新到磁盘文件,同时,用户备份操作开始拷贝数据
4、 由于写文件(刷盘)和读文件(拷贝)同时进行,导致拷贝的文件出现半页写的不完整数据。
PG用force_page_write解决这个问题,它的原理是在checkpoint之后对所有数据页面的第一次写的时候将整个数据页同时写入到xlog中。
备注:设置full_page_writes=on后,checkpoint后对每个页中数据的第一次修改都会将整个页全部保存到WAL日志中,如果修改的数据比较零散,可能导致WAL日志大量增加,给系统磁盘带来很大压力。
在没有半页写的情况下,WAL日志中保存的整页数据是没用的,不会覆盖到数据文件中,例如:
1、 开始恢复
2、 Checksum检查数据页,没有发现半写情况
3、 使用WAL日志恢复备份过程中产生的增量数据
4、 恢复完成
异常出现后,redo操作时通过checksum发现“半写”的数据页,并将xlog中保存的完整页覆盖当前损坏的数据页,然后再继续做redo,就可以恢复整个数据库。
1、 开始恢复
2、 Checksum检查数据页,发现有半页写的坏数据
3、 使用WAL中保存的整页数据来修复半页写数据页
4、 WAL日志恢复半页写坏数据
5、 使用WAL日志恢复备份过程中产生的增量数据
6、 恢复完成
Pg_basebackup过程中应用了full_page_write这项技术,在主要流程中,开始调用了do_pg_start_backup()函数,接着开始拷贝数据,在结束的时候调用了do_pg_stop_backup()函数do_pg_start_backup()函数首先设置了full_page_write=on(对应的参数是XlogCtrl->Insert.forcePageWrites= true)然后做了一次checkpoint,
do_pg_stop_backup()函数是对do_pg_start_backup()函数修改过的一些参数做恢复操作,也就是说在备份过程中保持full_page_write=on。
因为full_page_write需要在xlog中记录数据页,会写更多xlog文件,不仅有数据变化信息,还有数据页本身信息,这样会增加额外的IO和磁盘消耗,把full_page_write这个选项关闭会提高数据库执行速度以及减少xlog数量,但是可能导致系统崩溃或者掉电之后的数据库损坏。 如果有减小部分页面写入风险的硬件支持(比如电池供电的磁盘控制器), 或者文件系统支持(能够保证page写入原子性),可以把风险降低到一个可以接受的范围, 那么可以考虑关闭这个选项,其他情况下建议打开这个选择。
- 点赞
- 收藏
- 关注作者
评论(0)