# 通过全量备份文件恢复到自建PostgreSQL数据库
本章节介绍将下载的华为云RDS for PostgreSQL全量备份文件恢复到自建PostgreSQL数据库的操作步骤。
如果您希望在本地重新建立一个同样体量的PostgreSQL数据库，并且将华为云RDS for PostgreSQL数据全部迁移，可以使用本章节操作将下载的.tar.gz文件在本地进行重建。
- [步骤一：在华为云RDS for PostgreSQL下载全量备份文件]
- [步骤二：使用备份文件恢复数据到自建PostgreSQL]
- [常见问题]
#### 操作流程
1. 下载华为云RDS for PostgreSQL实例中对应时间点的全备文件。
2. 将全备文件上传到本地用以重建数据库。
3. 使用tar解压工具将全备文件解压。
4. 保留自建数据库相关配置文件并通过os命令将解压的全备文件覆盖到自建数据库的data目录中。
5. 重启数据库，等待数据库恢复完成。
 
#### 约束限制
- 本章节仅使用从华为云RDS for PostgreSQL所有版本实例下载的全量备份文件在本地恢复到对应版本自建数据库，不包括增量备份的恢复操作。
- **自建** **PostgreSQL** **数据库** **内核小版本需与华为云** **RDS for PostgreSQL** **​** **版本号一致。**
  **​** 通过**psql -V** 或**psql --version**命令，可以查看PostgreSQL内核版本。
  
- 仅支持恢复到本地为Linux操作系统的数据库，系统上需要安装tar解压工具。 通过**sudo yum install tar**命令安装tar解压工具。
  
- 在进行恢复阶段请勿在本地自建数据库运行其他业务或保留业务数据。
- RDS for PostgreSQL有部分增强特性（如Failover Slot等），使用云上的物理备份恢复到开源自建数据库时执行部分SQL报错，需要将用到的增强特性删除，详见[常见问题]。
- 本地自建数据库的操作系统与云数据库的操作系统可能不一致，而PostgreSQL数据库部分索引的排序规则依赖操作系统，恢复到自建数据库后需要重建索引，需要重建的索引排查方法见++[官方文档](https://wiki.postgresql.org/wiki/Locale_data_changes)++。
 
 #### 步骤一：在华为云RDS for PostgreSQL下载全量备份文件
RDS for PostgreSQL实例会在固定时间进行自动全备任务，也可以由您指定时间进行手动全备任务，其生成的.tar.gz文件支持下载以及在本地进行恢复自建数据库。
1. 您可以在RDS界面单击实例名称，选择"备份恢复 \> 全量备份 \> 下载"，详见[下载实例级备份文件](https://support.huaweicloud.com/usermanual-rds-pg/rds_09_0031.html)。
2. 通过文件传输工具（例如WinSCP）将全备文件上传到本地PostgreSQL库所在的Linux设备。
 
 #### 步骤二：使用备份文件恢复数据到自建PostgreSQL
**使用说明**
以下步骤请根据实际情况修改：
1. RDS for PostgreSQL备份文件解压前后建议存放在不同目录下。
   - 解压前文件：/home/postgres/*全备文件*.tar.gz
   
   - 解压后目录：/home/postgres/backuprds
    
2. "/home/postgres/backuplocal"目录存放本地PostgreSQL数据库"data"目录下的两个配置文件"postgresql.conf"和"pg_hba.conf"。
3. 使用**postgres**用户作为本地PostgreSQL数据库的安装用户。
4. 使用*$PGDATA* 代替本地PostgreSQL数据库"data"目录，执行以下命令获取本地PostgreSQL数据库"data"目录。
   **su - postgres**
   **psql --host=localhost --port=** *\<DB_PORT\>* **--dbname=postgres --username=postgres -c "show data_directory;"**
   DB_PORT为本地自建数据库实例的端口，默认值为5432，请以实际配置为准。
   
**操作步骤**
1. 切换至**postgres** 用户并创建一个临时目录"backuprds"，以下所有步骤使用**postgres** 用户执行。
   **su - postgres**
   **mkdir /home/postgres/backuprds**
   
2. 停止本地PostgreSQL数据库服务。 **pg_ctl** **stop -D** *$PGDATA*
   
3. 创建临时目录保存本地PostgreSQL数据库data目录下的两个配置文件（"postgresql.conf"、"pg_hba.conf"）。
   **mkdir /home/postgres/backuplocal**
   **cp** *$PGDATA* **/pg_hba.conf** *$PGDATA* **/postgresql.conf /home/postgres/backuplocal**
   
4. 清空本地数据库的"data"目录。
   ![](https://support.huaweicloud.com/usermanual-rds-pg/public_sys-resources/notice_3.0-zh-cn.png)
   操作前请确保"*$PGDATA*/"目录下的数据已经不再需要，请谨慎操作。
   执行**ls -l** *$PGDATA* 查看"*$PGDATA*/"目录下的文件。
   **rm -rf** *$PGDATA* ***/\****
   
5. 执行如下命令，将备份解压到[1]中准备的目录。
   ![](https://support.huaweicloud.com/usermanual-rds-pg/public_sys-resources/note_3.0-zh-cn.png)
   若使用root用户上传RDS for PostgreSQL备份文件到"/home/postgres/*全备文件*.tar.gz"，该文件会存在权限问题，需要修改该文件属主。
   1. 执行**sudo su** 切换至**root**用户。
   
   2. 执行**chown -R postgres:postgres /home/postgres/** *全备文件* **.tar.gz** 修改该文件属主为**postgres**用户。
   
   3. 执行**su - postgres** 切换回**postgres**用户。
    
   **tar -zxf /home/postgres/** *全备文件* **.tar.gz -C /home/postgres/backuprds**
   解压后会在"/home/postgres/backuprds"目录下产生以下目录：
   - 一个"base"目录，存放全量文件。
   
   - 一个"pg_wal"目录，为增量文件目录。如果PostgreSQL版本为9.x，则为"pg_xlog"目录。
   
   - N个以数字命名的表空间目录（如果原备份存在表空间文件）。
    
6. 将[5]和[3]中的文件按顺序拷贝到本地数据库指定目录下。
   1. 将解压出来的"base"目录下的文件，全部拷贝到本地数据库"data"目录，然后用[3]中保存的配置文件，覆盖本地数据库"data"目录下的两个文件。
      **cp -r /home/postgres/backuprds/base/\*** *$PGDATA*
      **cp -r /home/postgres/backuplocal/\*** *$PGDATA*
      
   
   2. 将解压出来的"pg_wal"目录（如果PostgreSQL版本为9.x，则为"pg_xlog"目录）下的文件，拷贝到本地数据库"data"下的"pg_wal"目录（如果PostgreSQL版本为9.x，则为"pg_xlog"目录）。
      **cp -r /home/postgres/backuprds/pg_wal/\*** *$PGDATA* **/pg_wal**
      
   
   3. （可选）如果原备份存在表空间文件，修改"data/tablespace_map"文件中对应的表空间软链接信息：
      - 复制表空间文件到"/tmp/tblspc/"目录下。 若解压文件中存在多个表空间目录，请多次执行**cp -r /home/postgres/backuprds/$table_space /tmp/tblspc**命令，确保所有表空间复制到"/tmp/tblspc"目录。
        **mkdir /tmp/tblspc**
        **cp -r /home/postgres/backuprds/** *$table_space* **/tmp/tblspc**
        $table_space为[5]中解压出的以数字命名的表空间名称。
        
      
      - 删除本地数据库"data"目录"/tablespace_map"文件。 **rm -rf** *$PGDATA* **/tablespace_map**
        
      
      - 添加本地数据库"data"目录"/tablespace_map"文件的配置信息，若解压文件中存在多个表空间目录请多次执行以下命令，确保表空间软链接信息配置完整。 **echo "** *$table_space* **/tmp/tblspc/** *$table_space* **" \>\>** *$PGDATA* **/tablespace_map**
        
       
    
7. 重新启动数据库，等待数据库恢复完成。 **pg_ctl start -D** *$PGDATA*
   ![](https://support.huaweicloud.com/usermanual-rds-pg/public_sys-resources/note_3.0-zh-cn.png)
   如果备份期间云数据库有较大的写业务，"pg_wal"目录下会有较多的WAL日志，数据库启动时回放WAL的时间可能较长，启动命令可能会超时失败。
   执行**ps uxwwf \| grep 'startup'**命令查看startup进程的状态来判断当前恢复的进度。
   
 
 #### 常见问题
**恢复数据**
Q：如果没有备份该如何恢复数据？
A：通过DRS迁移数据，详见[将PostgreSQL同步到PostgreSQL](https://support.huaweicloud.com/realtimesyn-drs/drs_04_0508.html)。
**备份恢复操作**
- Q1：使用云数据库备份文件恢复自建数据库，数据库启动失败，报错信息"replication slot file xxx has corrupted length xxx"，如何处理？ A：手动删除"pg_replslot"目录下的所有文件和文件夹，删除完成后启动数据库。
  
- Q2：常见报错"could not locate a valid checkpoint record"的原因，以及如何处理？ A：该错误通常表示数据库中的检查点记录已损坏或丢失，导致无法恢复数据库。一般情况下是wal日志没有被正常加载，建议参考[6.b]中的处理重新执行该命令。
  
**RDS for PostgreSQL11** **版本恢复数据**
- Q1：RDS for PostgreSQL 11恢复到本地PostgreSQL 11时，int4到text的类型转换出现报错信息 "ERROR: internal function "int4_text" is not in internal lookup table"，如何处理？ A：使用postgres用户连接本地PostgreSQL 11数据库执行如下命令删除该类型转换规则，需要super user执行。
  ```
  delete from pg_cast where castsource = 'int4'::regtype and casttarget = 'text':: regtype;
  ```
  
- Q2：RDS for PostgreSQL 11恢复到本地PostgreSQL 11时多个类型转换函数报错，如何排查和处理？ A：分别在本地PostgreSQL 11和RDS for PostgreSQL 11执行如下SQL，并对比结果。
  ```
  select oid, * from pg_cast order by 1;
  ```
  对于RDS for PostgreSQL 11新增的类型转换规则，在本地PostgreSQL 11执行如下SQL全部删除。
  ```
  delete from pg_cast where castsource = xxx and casttarget = xxx;
  ```
  
 
