PostgreSQL的备份与恢复
防止数据丢失的第一道防线就是备份。数据丢失有的是硬件损坏,还有人为的误删之类的,也有其他的原因导致误删数据。
正常备份和恢复,如果公司有DBA,开发一般不用参与,但作为架构师还是要了解。
在PostgreSQL中,有三种备份方式:
SQL备份(逻辑备份) :其实就是利用数据库自带的类似dump的命令,或者是你用图形化界面执行导入导出时,底层就是基于这个dump命令实现的。
优点:简单,操作方便还可靠。
缺点:数据数据量比较大的时候,这种方式巨慢,可能导出一天,都无法导出所有数据。
文件系统备份(物理备份) :其实就是找到当前数据库,数据文件在磁盘存储的位置,将数据文件直接复制一份或多份,存储在不同的物理机上,即便物理机故障,还有其他物理机。
优点:相比逻辑备份,恢复的速度快。
缺点:在备份数据时,可能数据还正在写入,一定程度上会丢失数据。 在恢复数据时,也需要注意数据库的版本和环境必须保持高度的一致。如果是线上正在运行的数据库,这种复制的方式无法在生产环境实现。
如果说要做数据的迁移,这种方式还不错滴。
归档备份:(也属于物理备份)
先了解几个概念,在PostgreSQL有多个子进程来辅助一些操作:
- BgWriter进程:BgWriter是将内存中的数据写到磁盘中的一个辅助进程。当向数据库中执行写操作后,数据不会马上持久化到磁盘里。这个主要是为了提升性能。BgWriter会周期性的将内存中的数据写入到磁盘。
- 如果快了,IO操作频繁,效率慢;
- 如果慢了,有查询操作需要内存中的数据时,需要BgWriter现把数据从内存写到磁盘中,再提供给查询操作作为返回结果,会导致查询操作效率变低;
- 考虑一个问题: 事务提交了,数据没落到磁盘,这时,服务器宕机了怎么办?
- WalWriter进程:WAL就是write ahead log的缩写,说人话就是预写日志(redo log)。其实数据还在内存中时,其实已经写入到WAL日志中一份,这样一来,即便BgWriter进程没写入到磁盘中时,数据也不会丢失。
- WAL能单独做备份么?单独不行!
- 但是WAL日志有个问题,这个日志会循环使用,WAL日志有大小的线程,只能保存指定时间的日志信息,如果超过了,会覆盖之前的日志。
- PgArch进程:WAL日志会循环使用,数据会丢失。没关系,还有一个归档的进程,会在切换wal日志前,将WAL日志备份出来。PostgreSQL也提供了一个全量备份的操作。可以根据WAL日志,选择一个事件点,进行恢复。
查看WAL日志:
这些就是归档日志。
wal日志的名称,是三块内容组成,
没8个字符分成一组,用16进制标识的
00000001 00000000 0000000A
时间线 逻辑id 物理id
查询当前库用的是哪个wal日志:
1 | -- 查看当前使用的wal日志 查询到的lsn:0/47233270 |
归档默认不是开启的,需要手动开启归档操作,才能保证wal日志的完整性
修改postgresql.conf文件
1 | # 开启wal日志的内容,注释去掉即可 |
1 | # 开启归档操作 |
修改完上述配置文件后,记得重启postgreSQL进程,才会生效!
归档操作执行时,需要保证/archive存在,并且postgres用户有权限进行w操作
构建/archive路径
1 | # postgres没有权限在/目录下构建目录 |
在当前库中做大量写操作,接入到wal日志,重置切换wal日志,再查看归档情况。
发现,将当前的正在使用的wal日志和最新的上一个wal日志归档过来了,但是之前的没归档。
这个不是问题,后期备份时,会执行命令,这个命令会直接要求wal日志立即归档,然后最全量备份。
逻辑备份&恢复
PostgreSQL提供了pg_dump以及pg_dumpall的命令来实现逻辑备份。
这两命令差不多,看名字猜!
pg_dump这种备份,不会造成用户对数据的操作出现阻塞。
数据库不是很大的时候,pg_dump也不是不成!
查看命令使用帮助:
这个命令从三块去看:http://postgres.cn/docs/12/app-pgdump.html
- 连接的信息,指定连接哪个库,用哪个用户~
- option的信息有就点多,查看官网。
- 备份的数据库!
备份库中的全部数据。
删除当前数据库中的表等信息,然后恢复数据
除此之外,也可以通过图形化界面备份,在库的位置点击备份就成,导出一个文本文件。
物理备份(归档+物理)
这里需要基于前面的文件系统的备份和归档备份实现最终的操作
单独使用文件系统的方式不推荐,因为数据会丢失。
这里直接使用PostgreSQL提供的pg_basebackup命令来实现。
pg_basebackup会做两个事情:
- 将内存中的脏数据落到磁盘中,然后将数据全部备份;
- 将wal日志直接做归档,然后将归档也备走。
查看pg_basebackup命令使用帮助:
1 | # -D 指定备份文件的存储位置 |
- 提前准备出/pg_basebackup目录(将拥有者赋予postgres用户)
1
2mkdir /pg_basebackup
chown -R postgres. /pg_basebackup/ - 给postgres用户提供replication的权限,修改pg_hba.conf,记得重启生效
- 执行备份
1
pg_basebackup -D /pg_basebackup -Ft -Pv -Upostgres -h 192.168.11.32 -p 5432 -R
- 需要输入postgres的密码,这里可以设置,重新备份。
- 执行备份
物理恢复(归档+物理)
模拟数据库崩盘,先停止postgresql服务,然后直接删掉data目录下的全部内容
将之前备份的两个文件准备好,一个base.tar,一个pg_wal.tar
第一步:将base.tar中的内容,全部解压到 12/data 目录下
第二步:将pg_wal.tar中的内容,全部解压到 /archive 目录下
第三步:在postgresql.auto.conf文件中,指定归档文件的存储位置,以及恢复数据的方式
第四步:启动postgresql服务
1 | systemctl start postgresql-12 |
第五步:启动后,发现查询没问题,但是执行写操作时发现不让写。需要执行一个函数,取消这种恢复数据后的状态,才允许正常的执行写操作。
1 | select pg_wal_replay_resume(); |
物理备份&恢复(PITR-Point in time Recovery)
模拟场景
场景:每天凌晨02:00,开始做全备(PBK),到了第二天,如果有人14:00分将数据做了误删,希望将数据恢复到14:00分误删之前的状态?
1、恢复全备数据,使用PBK的全备数据恢复到凌晨02:00的数据。(数据会丢失很多)
2、归档恢复:备份中的归档,有02:00~14:00之间的额数据信息,可以基于归档日志将数据恢复到指定的事务id或者是指定时间点,从而实现数据的完整恢复。
准备场景和具体操作
1、构建一张t3表查询一些数据
1 | -- 构建一张表 |
2、模拟凌晨2点开始做全备操作
1 | pg_basebackup -D /pg_basebackup -Ft -Pv -Upostgres -h 192.168.11.32 -p 5432 -R |
3、再次做一些写操作,然后误删数据
1 | -- 凌晨2点已经全备完毕 |
4、恢复数据(确认有归档日志)
将当前服务的数据全部干掉,按照之前的全备恢复的套路先走着
然后将全备的内容中的base.tar扔data目录下,归档日志也扔到/archive位置。
5、查看归档日志,找到指定的事务id
查看归档日志,需要基于postgresql提供的一个命令
1 | # 如果命令未找到,说明两种情况,要么没有这个可执行文件,要么是文件在,没设置环境变量 |
6、修改data目录下的恢复数据的方式
修改postgresql.auto.conf文件
将之前的最大恢复,更换为指定的事务id恢复
基于提供的配置例子,如何指定事务id
修改postgresql.auto.conf文件指定好事务ID
7、启动postgreSQL服务,查看是否恢复到指定事务ID
8、记得执行会后的函数,避免无法执行写操作
1 | select pg_wal_replay_resume(); |