FGPDU(Full name: FGEDU PostgreSQL Data UnLoader) 是一款面向 PostgreSQL 数据库的离线数据抽取与灾难恢复工具,是 PostgreSQL 生态中少有的、可在数据库实例无法启动的情况下,直接从底层数据文件中恢复数据的"最后防线"型工具。
当前版本:v1.0.7
适用 PostgreSQL:9.2 ~ 19
适用平台:Linux(RHEL/OEL/CentOS/Ubuntu/SUSE/Kylin/UOS 等)+ Windows(XP~11,Server 2003~2022,x86 & x64)
一、程序介绍
1.1 工具概述
在企业级数据库运维场景中,数据丢失和数据库无法启动是最严重、最令人紧张的故障之一。常见诱因包括:
- 硬件故障或文件系统损坏导致数据文件损坏;
- 误操作(误执行
DELETE/DROP TABLE/TRUNCATE TABLE); - PostgreSQL 升级失败、系统表(
pg_class/pg_database/pg_attribute)损坏; - 控制文件
pg_control丢失或不可读,实例启动时直接抛出PANIC; - WAL 日志损坏、回放失败,数据库无法到达一致状态;
- 误删除数据库目录或被加密;
- 备份策略失效,没有可用的物理/逻辑备份。
在上述任何一种情况下,PostgreSQL 自身通常已经无法启动,传统的 pg_dump / pg_basebackup / PITR 等手段都依赖于数据库实例在线或归档日志完整。FGPDU 正是为这种"实例已经死掉、备份又不全"的极端场景而生:它完全绕过 PostgreSQL 服务进程 ,直接读取磁盘上的数据文件(base/<db_oid>/<relfilenode>),解析 PostgreSQL 的 8KB 数据页格式(PageHeaderData、ItemIdData、HeapTupleHeaderData),将页面中的元组(tuple)抽取出来,重建为可读的 SQL(CREATE TABLE + INSERT INTO)、CSV、TXT、DMP、Binary 等多种格式,输出到指定目录后即可在新库中重新导入,完成数据"起死回生"。
1.2 工具定位与设计哲学
FGPDU 的核心设计哲学可以概括为以下五点:
- 离线优先,只读安全 :FGPDU 不需要 PostgreSQL 进程在线,对原始数据目录采取严格只读策略,不会对数据文件做任何写入或修改操作。即使恢复过程出错,原始数据状态保持不变,可以反复尝试不同的恢复策略。
- 最大恢复:默认采用"最大数据恢复"策略------遇到坏块自动跳过继续扫描后续块;遇到页头损坏自动回退到原始元组扫描;遇到系统表损坏自动降级为文件级紧急扫描。一切以"尽可能多恢复一行数据"为目标。
- 零运行时依赖:编译产物为单文件可执行程序(Linux 静态 ELF、Windows 静态 PE),不需要安装任何运行时库(不依赖 glibc 动态库、不需要 VC++ 运行时、不需要 MinGW DLL),拷贝到目标服务器即可运行。这对生产环境中的应急恢复至关重要------故障机器往往无法联网安装依赖。
- 跨平台广覆盖:覆盖 Linux 主流发行版(含 RHEL 5/6/7/8/9/10、麒麟、UOS 等国产系统)与 Windows XP~11 全系列桌面和服务器版本(含 x86 与 x64),尤其对老旧系统做了专门适配。
- 命令简洁直观 :所有操作通过简短的子命令完成(
diagnose/list/scan/recover/scan-file),运维人员无需记忆复杂参数即可上手。
1.3 适用场景
FGPDU 适用于以下任一场景:
| 场景 | 描述 |
|---|---|
| 数据库无法启动 | PostgreSQL 实例启动失败、控制文件损坏、WAL 损坏、系统表损坏等导致无法正常进入 |
| DELETE 数据恢复 | 误执行 DELETE FROM table WHERE ... 后,VACUUM 之前抢救数据 |
| DROP 表恢复 | 误执行 DROP TABLE table,pg_class 条目被删但数据文件仍残留在磁盘 |
| TRUNCATE 表恢复 | 误执行 TRUNCATE TABLE,旧 relfilenode 文件成为孤儿文件 |
| 数据迁移取证 | 需要将数据库数据导出为 SQL/CSV 用于审计、迁移或异地恢复 |
| 跨版本数据迁移 | 老版本 PG 实例无法启动时,抽取数据导入新版本 PG |
| 坏块数据抢救 | 数据文件部分块损坏,常规导入失败,需要尽可能恢复未损坏部分 |
| 国产化环境恢复 | 麒麟、UOS、NeoKylin 等国产 Linux 系统下的 PostgreSQL 数据恢复 |
1.4 工作原理
FGPDU 的工作原理可以分解为以下五个层次:
- 目录诊断层 :扫描 PGDATA 目录结构,读取
PG_VERSION文件确认 PG 版本,读取global/pg_control获取块大小等控制信息,校验base/、global/、pg_wal/、pg_tblspc/等关键目录是否完整。 - 系统目录解析层 :解析
pg_database、pg_class、pg_namespace、pg_attribute、pg_tablespace等系统表,建立"数据库 OID ↔ 数据库名"、"relfilenode OID ↔ 表名 + Schema + 列定义"的映射字典。 - 数据页解析层 :根据 PG 版本对应的页面格式(page version 1~4)解析每个 8KB 数据页:解析页头
PageHeaderData、ItemId数组、HeapTupleHeaderData,提取元组的t_xmin/t_xmax/t_infomask/t_infomask2等事务信息,并定位元组数据区。 - 元组数据提取层 :根据
pg_attribute中记录的列定义(atttypid、attlen、attalign、attstorage、atttypmod、attnotnull)按 PG 内部对齐规则解析每列的值,处理定长/变长类型、NULL 位图、TOAST 外置数据、压缩数据、枚举类型、复合类型、数组类型等。 - 输出层:将解析出的元组按指定格式(SQL/CSV/TXT/DMP/Binary)写入到输出目录,并在 SQL 文件末尾自动追加"恢复步骤说明 + 数据校验 SQL",方便用户直接复制执行完成后续恢复。
1.5 作者信息
| 联系方式 | 信息 |
|---|---|
| 作者 风哥 | |
| 官方网站 : http://www.fgedu.net.cn , http://www.itpux.com | |
| 数据库教程 : https://edu.51cto.com/lecturer/8020378.html |
二、功能特性
2.1 离线数据抽取能力
FGPDU 最核心的能力是完全脱离 PostgreSQL 服务进程完成数据抽取。具体表现为:
- 不需要
postgresql.conf、pg_hba.conf完整可用; - 不需要
pg_control完整可用(缺失时自动使用默认 8192 字节块大小); - 不需要 WAL 日志完整可用;
- 不需要
shared_buffers、work_mem等运行时参数; - 只需要
base/<db_oid>/<relfilenode>数据文件可读即可工作。
这意味着即使数据目录只剩下一个 base/ 子目录的拷贝,FGPDU 也能从中恢复数据。
2.2 强大的数据恢复能力
FGPDU 支持三种 PostgreSQL 数据库中最常见的"误删除"恢复:
-
DELETE 数据恢复:
- 原理:
DELETE FROM操作不会立即物理删除行,而是将行的t_xmax标记为非零,并在t_infomask中设置HEAP_DELETED标志,等待VACUUM清理。 - 实现:FGPDU 扫描每个数据块,检测
t_xmax != 0的行,提取尚未被 VACUUM 物理清除的删除数据。 - 适用条件:必须在 VACUUM 运行之前执行恢复。
- 原理:
-
DROP 表数据恢复:
- 原理:
DROP TABLE会删除pg_class中的元数据条目,但数据文件(relfilenode)仍然保留在磁盘上,直到被文件系统回收或 autovacuum 清理。 - 实现:FGPDU 扫描
base/<dboid>/目录下所有数据文件,与pg_class中已知 OID 对比,找出"孤立文件"(pg_class 中不存在但磁盘上仍存在),从这些文件中提取数据。 - 适用条件:数据文件尚未被文件系统回收。
- 原理:
-
TRUNCATE 表数据恢复:
- 原理:
TRUNCATE TABLE会创建新的 relfilenode 文件替换旧文件,旧文件成为孤儿文件。 - 实现:与 DROP 恢复逻辑相同,扫描孤立 relfilenode 文件。
- 适用条件:旧的 relfilenode 文件尚未被回收。
- 原理:
2.3 精确的多维度过滤
FGPDU 支持三个维度的组合过滤,实现"精确恢复",避免不必要的数据扫描和混乱的输出文件:
| 维度 | 选项 | 说明 |
|---|---|---|
| 用户名/数据库名 | -u 或 --user 或 -D / --database |
限定只导出某个数据库(PG 中用户名通常与数据库名一致) |
| Schema | -s 或 --schema |
限定只导出某个 Schema 下的所有表 |
| 表对象 | -t 或 --table |
限定只导出某张表,支持 schema.table 格式或纯表名(自动跨 Schema 匹配) |
三个维度可以任意组合,例如:
bash
# 用户 + Schema + 表 全组合精确导出
fgpdu scan -d /postgresql/data -u mydb -s public -t orders -o /tmp/export
2.4 多种输出格式
FGPDU 支持五种输出格式,覆盖不同的恢复与迁移需求:
| 格式 | 选项值 | 文件后缀 | 用途 | 可读性 | 导入方式 |
|---|---|---|---|---|---|
| SQL | sql(默认) |
.sql |
包含 CREATE TABLE + INSERT INTO 语句,可直接用 psql -f 导入新库 |
高 | psql -d newdb -f table.sql |
| CSV | csv |
.csv |
第一行为列名,适合 Excel/BI 工具导入或异构数据库迁移 | 高 | \copy 或 COPY ... FROM |
| TXT | txt |
.txt |
文本格式,字段用分隔符分隔,便于脚本处理 | 中 | 自定义脚本 |
| DMP | dmp |
.dmp |
FGPDU 专用二进制格式,包含表结构元数据和原始数据,用于大规模快速恢复 | 低 | FGPDU 工具自身 |
| Binary | binary |
.bin |
原始二进制数据导出,不做转换,适合取证分析 | 低 | 二进制工具 |
2.5 损坏弹性扫描(自适应扫描)
这是 FGPDU 区别于简单 pg_dump 类工具的关键能力之一。当数据文件部分损坏时,FGPDU 仍能最大程度恢复数据:
- 正常扫描模式:通过页头和 item pointer 读取元组(最快、最准确,适用于健康数据页)。
- 原始扫描模式(Raw Scan):当页头损坏或 item pointer 失效时,不依赖页头结构,直接在整个 8KB 页面中按元组模式搜索,尽可能捞出残留数据。
- 自由空间扫描(Free Space Scan) :扫描页面空闲空间(
pd_lower与pd_upper之间)中残留的已删除/覆盖元组数据,能恢复一些"看起来已经被覆盖"的数据。
启用 --continue-on-error 选项(默认启用)即可激活自适应扫描。遇到坏块时自动跳过继续扫描后续块,不会因为单个坏块中断整个恢复流程。
2.6 紧急全库扫描(EMERGENCY 模式)
当 pg_class / pg_database 等系统目录损坏或数据库完全无法启动时,FGPDU 会自动降级为文件级紧急扫描:
- 直接遍历
base/目录下所有数据库子目录; - 对每个数据库目录下的所有数据文件执行扫描;
- 自动识别真正的 PG 数据文件,跳过
_fsm(free space map)、_vm(visibility map)、_init、PG_VERSION等辅助文件; - 恢复的表数据按数据库名(或
db_<OID>)分子目录导出。
无需人工干预,是数据库完全崩溃时的最后一道防线。
2.7 多段文件支持
PostgreSQL 大表(超过 1GB 默认 RELSEG_SIZE)会被自动分割为多个段文件:
- 第一段:
<oid>(如16385) - 第二段:
<oid>.1(如16385.1) - 第三段:
<oid>.2(如16385.2)
FGPDU 自动计算段号和偏移量,无需手动指定,正确处理大表的所有段文件,确保大表数据完整恢复。
2.8 数据完整性校验
FGPDU 对每个提取的元组进行多重完整性校验,过滤无效元组,提高恢复数据质量:
- 字段数匹配 :元组实际列数与
pg_attribute中记录的列数一致; - 数据类型最小长度检查:每个字段的实际长度符合该类型的最小要求;
- NULL bitmap 一致性:NULL 标记位与字段实际内容一致;
- xmin/xmax 合理性 :
t_xmin在合理范围(1~10 亿),t_xmax与t_infomask组合合理; - 元组数据区非全零、非重复模式:排除全零元组、重复模式元组;
- 页内边界检查:防止 item pointer 越界导致读取越界内存。
统计 valid / partial / invalid 三类元组数量,便于评估恢复数据质量。
2.9 恢复步骤说明与数据校验 SQL
每个 SQL 输出文件末尾自动追加完整的恢复指南和数据校验 SQL:
- 建库 → 建 Schema → 导入 → 验证 → 重建索引 → ANALYZE 的完整步骤说明;
- 行数验证 SQL(
SELECT COUNT(*) FROM schema.table); - NOT NULL 约束检查 SQL;
- 数值列范围检查 SQL(MIN/MAX/DISTINCT);
- 日期列范围检查 SQL;
- 重复行检测 SQL(
GROUP BY ... HAVING COUNT(*) > 1)。
用户无需自行编写验证 SQL,直接复制执行即可。
2.10 稳定性与安全加固
FGPDU 针对生产环境做了大量稳定性加固:
- 信号处理(Linux) :捕获
SIGSEGV/SIGBUS/SIGABRT/SIGFPE/SIGILL,遇到损坏文件不崩溃,输出提示信息后安全退出; - 异常处理(Windows) :使用
SetUnhandledExceptionFilter+MiniDumpWriteDump做崩溃保护(SEH); - 内存安全:所有扫描函数中的栈上大数组(page_buf8KB、tuples12KB、items2KB)改为动态内存分配,彻底消除栈溢出风险;
- 缓冲区溢出保护 :所有
memcpy/strncpy操作都做了严格的边界检查; - 路径安全 :路径长度检查(
FGPDU_MAX_PATH = 4096),防止超长路径导致的缓冲区溢出; - 忽略 SIGPIPE:输出重定向到管道时不会因为下游进程退出导致 FGPDU 崩溃;
- 磁盘满检测 :输出写入时检测
ferror,遇到磁盘满等错误立即报错。
2.11 跨平台与跨版本能力
- 跨 PostgreSQL 版本 :覆盖 PG 9.2 ~ PG 19,针对每个版本对应的页面格式(page version 1~4)做了精确适配,包括 PG 13+ 引入的
pd_prune_xid字段; - 跨 Linux 发行版:RHEL/OEL/CentOS 5/6/7/8/9/10、Ubuntu 12.04+、Debian 7+、SUSE 11+、Kylin、UOS、NeoKylin 等国产系统;
- 跨 Windows 版本:Windows XP SP3 ~ Windows 11,Server 2003 ~ Server 2022,x86 与 x64 全支持;
- 跨架构:x86_64 与 i686(32 位)双架构支持。
2.12 进度与详细日志
-v/--verbose:详细模式,输出每个表的处理情况(表名、OID、页数、恢复元组数、坏块数等);--progress:进度模式,适合大数据量场景实时查看扫描进度;- 日志可重定向到文件:
fgpdu scan ... -v 2>&1 | tee /tmp/fgpdu.log。
三、支持环境
3.1 操作系统支持
3.1.1 Linux x86_64 / i686
| 发行版家族 | 具体版本 |
|---|---|
| Red Hat 系 | RHEL / OEL / CentOS 5 / 6 / 7 / 8 / 9 / 10、CentOS Stream 8 / 9 |
| Ubuntu | Ubuntu 12.04 LTS ~ 24.04 LTS |
| Debian | Debian 7+ |
| SUSE | SUSE Linux Enterprise Server (SLES) 11 / 12 / 15、openSUSE 12+ |
| 国产系统 | 银河麒麟(Kylin)、统信 UOS、中标麒麟(NeoKylin) |
| 通用 | 任何基于 kernel 2.6.18+(RHEL5)或 2.6.32+(RHEL6+)的 x86 / x86_64 Linux |
重要提示 :在 RHEL 5 / 6 / 7 等老系统上部署时,建议使用对应的 make rhel5 / make rhel6 / make rhel7 编译目标,避免 glibc 版本不匹配导致的 GLIBC_2.x not found 错误。
3.1.2 Microsoft Windows(x86 & x64)
| 版本家族 | 具体版本 |
|---|---|
| 客户端 | Windows XP SP3、Vista、7、8、8.1、10、11 |
| 服务器端 | Windows Server 2003、2008、2008 R2、2012、2012 R2、2016、2019、2022 |
| 架构 | x86(32 位)与 x64(64 位)均原生支持 |
Windows 版本通过 MinGW-w64 交叉编译或 Visual Studio 原生编译生成,输出为全静态单文件 fgpdu.exe,无需任何运行时 DLL 依赖。
3.2 PostgreSQL 版本支持
| 主版本 | 具体版本 | 页面版本 |
|---|---|---|
| PG 9.x | 9.2、9.3、9.4、9.5、9.6 | page version 1 / 2 / 3 |
| PG 10.x | 10 | page version 4 |
| PG 11.x | 11 | page version 4 |
| PG 12.x | 12 | page version 4 |
| PG 13.x | 13(含 pd_prune_xid 字段) |
page version 4 |
| PG 14.x | 14 | page version 4 |
| PG 15.x | 15 | page version 4 |
| PG 16.x | 16 | page version 4 |
| PG 17.x | 17 | page version 4 |
| PG 18.x | 18 | page version 4 |
| PG 19.x | 19 | page version 4 |
3.3 硬件要求
| 项目 | 最低要求 | 推荐 |
|---|---|---|
| CPU | x86 / x86_64,1 核 | x86_64,多核 |
| 架构 | x86(32 位)或 x64(64 位) | x64 |
| 内存 | 256 MB | 1 GB+(大数据量建议 8 GB+) |
| 磁盘剩余空间 | 数据目录大小的 1.5 倍 | 数据目录大小的 2 倍+(输出目录使用 SSD 更佳) |
| 网络 | 无需联网 | 无需联网(完全离线运行) |
3.4 编译依赖
3.4.1 Linux 编译依赖
bash
# RHEL / OEL / CentOS(含 RHEL5/6/7)
yum install gcc make glibc-static
# Ubuntu / Debian
apt-get install gcc make libc6-dev
# SUSE / SLES
zypper install gcc make glibc-devel-static
# 麒麟 / UOS(基于 yum)
yum install gcc make glibc-static
- gcc 版本:最低 gcc 4.1(RHEL5 默认),推荐 gcc 4.8+
- make:GNU make 3.81+
- glibc-static :仅完全静态编译(
make standalone)时必需,半静态编译(make portable)无需此包
3.4.2 Windows 交叉编译依赖(在 Linux 上编译出 fgpdu.exe)
bash
# RHEL / Fedora / CentOS(EPEL 源)
yum install mingw64-gcc mingw32-gcc mingw64-binutils mingw32-binutils
# Ubuntu / Debian
apt-get install gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 binutils-mingw-w64
3.4.3 Windows 原生编译依赖(MSVC)
- Visual Studio 2015 / 2017 / 2019 / 2022 任一版本
- 或 Windows SDK 8.1+ 独立安装包
- 通过 "Developer Command Prompt for VS" 调用
cl.exe
3.5 权限要求
- 对 PostgreSQL 数据目录有读权限 (通常属主是
postgres用户); - 对输出目录有读写权限;
- 不需要 root 权限(但生产环境通常用 root 拷贝/部署,需注意切换用户运行);
- 不需要 PostgreSQL 超级用户密码(FGPDU 直接读文件,不连数据库)。
3.6 网络与外部依赖
- 无需联网:FGPDU 是完全离线工具,运行时不访问任何网络资源;
- 无需 PG 服务在线:FGPDU 直接读文件,PostgreSQL 服务可以处于停止状态;
- 无需 Java / Python / .NET 运行时:静态编译的单文件,零运行时依赖。
四、程序使用
4.1 编译与安装
4.1.1 Linux 编译
bash
cd /path/to/FGPDU
# ============================================================
# 方式 A:现代 Linux 编译(RHEL7+/Ubuntu16+/SUSE12+,推荐)
# ============================================================
make standalone # 全静态单文件(需要 glibc-static)
# 或
make portable # 半静态(仅依赖 libc),无需 glibc-static
# ============================================================
# 方式 B:为 RHEL 5/6/7 老系统专门编译(生产部署时使用)
# ============================================================
make rhel5 # 兼容 RHEL 5.11 / CentOS 5.x / glibc 2.5
make rhel6 # 兼容 RHEL 6.x / CentOS 6.x / glibc 2.12
make rhel7 # 兼容 RHEL 7.x / CentOS 7.x / glibc 2.17
# ============================================================
# 方式 C:调试版本(带 gdb 符号,未优化,便于排错)
# ============================================================
make debug
# ============================================================
# 方式 D:发布版本(带优化)
# ============================================================
make release
编译产物位置:
| 编译目标 | 产物路径 |
|---|---|
make standalone |
build/standalone/fgpdu |
make portable |
build/portable/fgpdu |
make rhel5 |
build/rhel5/fgpdu |
make rhel6 |
build/rhel6/fgpdu |
make rhel7 |
build/rhel7/fgpdu |
make debug |
build/debug/fgpdu |
make release |
build/release/fgpdu |
4.1.2 Windows 编译
方式 A:在 Linux 上交叉编译(推荐)
bash
# 生成 64 位 Windows EXE(PE32+,推荐)
make windows-mingw # 输出:build/win64/fgpdu.exe
# 生成 32 位 Windows EXE(PE32,兼容 XP x86)
make windows-mingw32 # 输出:build/win32/fgpdu_x86.exe
生成的 .exe 为全静态单文件,不需要 VC++ 运行时、不需要 MinGW 运行时、不依赖任何 .dll,直接拷贝到目标 Windows 机器即可运行。
方式 B:在 Windows 上用 MSVC 原生编译
打开 "Developer Command Prompt for VS 2015/2017/2019/2022":
bat
cd \path\to\FGPDU
build\windows-msvc.bat
REM 产物:build\msvc\fgpdu.exe
4.1.3 编译验证
bash
# Linux
./build/standalone/fgpdu -V
./build/standalone/fgpdu -h
# Windows
fgpdu.exe -V
fgpdu.exe -h
# 检查 Linux 二进制依赖(应仅依赖 libc 或零依赖)
make check-deps
预期 -V 输出:
FGPDU - FGEDU PostgreSQL DUL v1.0.0
Supports PostgreSQL: 9.2 - 19
Supports RHEL: 5 - 10
Supports: OEL, Ubuntu, SUSE, CentOS, Kylin, UOS
Supports: Windows XP/Vista/7/8/10/11 x86/x64
License: Educational/Research Use Only
4.1.4 安装到系统路径(可选)
bash
make install # 安装到 /usr/local/bin/fgpdu
# 或手动拷贝
cp build/standalone/fgpdu /usr/local/bin/
chmod +x /usr/local/bin/fgpdu
4.2 命令详解
4.2.1 命令总览
| 命令 | 说明 |
|---|---|
fgpdu diagnose -d PGDATA |
诊断数据目录结构完整性 |
fgpdu list tables -d PGDATA |
列出所有用户表 |
fgpdu list databases -d PGDATA |
列出所有数据库 |
fgpdu list schemas -d PGDATA |
列出所有 Schema |
fgpdu scan -d PGDATA -o OUT |
抽取所有表数据(默认 SQL 格式) |
fgpdu recover delete -d PGDATA -o OUT |
恢复 DELETE 删除行 |
fgpdu recover drop -d PGDATA -o OUT |
恢复 DROP 表数据 |
fgpdu recover truncate -d PGDATA -o OUT |
恢复 TRUNCATE 表数据 |
fgpdu scan-file FILE -o OUT |
扫描单个数据文件 |
4.2.2 命令行选项
| 选项 | 短选项 | 说明 | 示例 |
|---|---|---|---|
--data-dir |
-d |
PostgreSQL 数据目录路径(必需) | -d /postgresql/data |
--output-dir |
-o |
输出目录 | -o /tmp/recover |
--format |
-f |
输出格式:sql/csv/txt/dmp/binary | -f csv |
--user |
-u |
用户名/数据库名 | -u postgres |
--database |
-D |
数据库名(-u 别名) |
-D mydb |
--schema |
-s |
Schema 名称 | -s public |
--table |
-t |
表名(支持 schema.table) |
-t public.orders |
--include-deleted |
--- | 包含已删除行 | --include-deleted |
--include-updated |
--- | 包含已更新行 | --include-updated |
--verbose |
-v |
详细输出 | -v |
--progress |
--- | 显示进度 | --progress |
--continue-on-error |
--- | 遇错继续(默认开启自适应扫描) | --continue-on-error |
--version |
-V |
显示版本信息 | -V |
--help |
-h |
显示帮助 | -h |
4.2.3 诊断命令(diagnose)
诊断命令是恢复操作的第一步,用于检查数据目录结构完整性。
bash
# 基本诊断
fgpdu diagnose -d /postgresql/data
# 详细诊断
fgpdu diagnose -d /postgresql/data -v
诊断输出示例:
=== FGPDU Diagnostics ===
Data Directory: /postgresql/data
PostgreSQL Version: 15.2
pg_control: OK (8192 bytes)
Block size: 8192 bytes
base/ directory: OK
Databases found: 2
- 1
- 16384
global/ directory: OK
pg_wal/ directory: OK
Permission Check:
Read access: OK
System Catalog Check:
IO Engine: OK
pg_class: OK
Page version: 4
Items on page: 128
=== Diagnostics Complete ===
诊断结果解读:
| 检查项 | 含义 | 处理建议 |
|---|---|---|
| PostgreSQL Version | 从 PG_VERSION 文件读取 | 确认版本在 9.2~19 范围内 |
| pg_control | 控制文件状态 | 缺失时块大小使用默认 8192 |
| Block size | 数据块大小 | 自动从 pg_control 识别 |
| base/ directory | 用户数据库目录 | 必须存在 |
| global/ directory | 系统表目录 | 必须存在 |
| pg_wal/ directory | WAL 日志目录 | 检查是否存在 |
| Read access | 读权限检查 | 需要 postgres 用户权限 |
| pg_class | 系统表完整性 | FAILED 时使用 scan-file 直接扫描 |
4.2.4 列表命令(list)
bash
# 列出所有数据库
fgpdu list databases -d /postgresql/data
# 列出所有表
fgpdu list tables -d /postgresql/data
# 列出指定 schema 的表
fgpdu list tables -d /postgresql/data -s public
# 查找指定表名(跨 schema)
fgpdu list tables -d /postgresql/data -t orders
# 列出指定 schema.table
fgpdu list tables -d /postgresql/data -t public.orders
# 列出所有 schema
fgpdu list schemas -d /postgresql/data
4.2.5 数据抽取命令(scan)
scan 命令是最常用的全库导出命令。
bash
# 全库导出为 SQL(默认)
fgpdu scan -d /postgresql/data -o /tmp/export
# 指定格式
fgpdu scan -d /postgresql/data -o /tmp/export -f csv
fgpdu scan -d /postgresql/data -o /tmp/export -f dmp
# 指定表
fgpdu scan -d /postgresql/data -t public.orders -o /tmp/export
# 按 Schema
fgpdu scan -d /postgresql/data -s public -o /tmp/export
# 按用户名/数据库名
fgpdu scan -d /postgresql/data -u postgres -o /tmp/export
# 三维度组合
fgpdu scan -d /postgresql/data -u mydb -s public -t orders -o /tmp/export
# 最大恢复模式(推荐)
fgpdu scan -d /postgresql/data -o /tmp/export -v --progress --continue-on-error
输出目录结构示例(按数据库分目录):
/tmp/fgpdu_export/
├── postgres/ ← postgres 数据库
│ ├── public_orders.sql
│ └── public_customers.sql
├── fgedudb/ ← fgedudb 数据库
│ ├── fgeduschema_fgedu01.sql
│ └── fgeduschema_fgedu02.sql
└── db_16384/ ← 无法解析名称时用 OID
└── recovered_16521.sql
4.2.6 数据恢复命令(recover)
bash
# 恢复 DELETE 数据
fgpdu recover delete -d /postgresql/data -o /tmp/recover
# 恢复 DROP 表数据
fgpdu recover drop -d /postgresql/data -o /tmp/recover
# 恢复 TRUNCATE 表数据
fgpdu recover truncate -d /postgresql/data -o /tmp/recover
# 恢复指定表的 DELETE 数据
fgpdu recover delete -d /postgresql/data -t public.orders -o /tmp/recover
# 恢复指定用户+Schema+表
fgpdu recover delete -d /postgresql/data -u mydb -s public -t orders -o /tmp/recover
# 详细模式
fgpdu recover delete -d /postgresql/data -o /tmp/recover -v
恢复输出示例:
=== DELETE Recovery Mode ===
Data directory: /postgresql/data
Output directory: /tmp/recover
Tables found: 42
Processing: public.orders
Blocks scanned: 128
Deleted tuples found: 56
Data still intact: 48
Successfully recovered: 42
=== DELETE Recovery Complete ===
Tables scanned: 42
Deleted rows found: 156
Rows recovered: 128
Time elapsed: 2.53 seconds
================================
4.2.7 单文件扫描命令(scan-file)
当系统表损坏、无法通过正常方式列出表时,可以直接扫描指定的 relfilenode 文件。
bash
# 基本用法
fgpdu scan-file /postgresql/data/base/16384/1259 -o /tmp/export
# 指定输出格式
fgpdu scan-file /postgresql/data/base/16384/1259 -o /tmp/export -f csv
fgpdu scan-file /postgresql/data/base/16384/1259 -o /tmp/export -f dmp
# 详细模式
fgpdu scan-file /postgresql/data/base/16384/1259 -o /tmp/export -v
文件路径格式:PGDATA/base/<db_oid>/<relfilenode>
输出文件命名规则:
- SQL:
output/<relfilenode>_recovered.sql - CSV:
output/<relfilenode>_recovered.csv - DMP:
output/<relfilenode>_recovered.dmp
4.3 输出格式详解
4.3.1 SQL 格式(默认)
生成标准的 SQL 文件,包含 CREATE TABLE 和 INSERT INTO 语句:
sql
-- FGPDU Recovery Output
-- Table: public.orders
-- OID: 16385
-- Pages: 128
-- Generated: 2026-08-07 10:00:00
-- DROP TABLE IF EXISTS public.orders;
CREATE TABLE public.orders (
id integer,
order_date timestamp,
customer_id integer,
amount numeric(10,2),
status varchar(20)
);
INSERT INTO public.orders VALUES (1, '2024-01-15 10:30:00', 1001, 1500.00, 'completed');
INSERT INTO public.orders VALUES (2, '2024-01-15 11:00:00', 1002, 2300.50, 'pending');
-- ... 文件末尾自动追加恢复步骤说明与验证 SQL ...
导入方式:
bash
psql -d newdb -f /tmp/export/public_orders.sql
4.3.2 CSV 格式
csv
id,order_date,customer_id,amount,status
1,2024-01-15 10:30:00,1001,1500.00,completed
2,2024-01-15 11:00:00,1002,2300.50,pending
导入方式:
sql
\copy public.orders FROM '/tmp/export/public_orders.csv' WITH CSV HEADER;
4.3.3 TXT 格式
文本格式,每行一个元组,字段用分隔符分隔,便于自定义脚本处理。
4.3.4 DMP 格式
FGPDU 专用的二进制格式,包含表结构元数据和原始数据,适合大规模快速恢复。
4.3.5 Binary 格式
原始二进制数据导出,不做任何转换,适合取证分析。
4.4 高级用法
4.4.1 配置文件模式
创建配置文件 fgpdu.conf:
ini
# FGPDU 配置文件
data_dir=/postgresql/data
output_dir=/tmp/recover
format=sql
verbose=true
continue_on_error=true
使用配置文件:
bash
fgpdu -c fgpdu.conf
4.4.2 详细日志与进度
bash
# 详细模式
fgpdu scan -d /postgresql/data -o /tmp/recover -v
# 进度模式
fgpdu scan -d /postgresql/data -o /tmp/recover --progress
# 日志重定向到文件
fgpdu scan -d /postgresql/data -o /tmp/recover -v 2>&1 | tee /tmp/fgpdu.log
4.4.3 大型数据目录恢复
bash
# 组合使用:最大恢复模式
fgpdu scan -d /postgresql/data -o /tmp/recover -v --progress --continue-on-error
4.4.4 并行恢复(脚本示例)
bash
#!/bin/bash
PGDATA=/postgresql/data
OUTPUT=/tmp/parallel_recover
mkdir -p $OUTPUT
# 获取表列表
TABLES=$(fgpdu list tables -d $PGDATA -s public | grep "^public" | awk '{print $1"."$2}')
# 并行恢复(每次最多 4 个)
echo "$TABLES" | xargs -P 4 -I {} bash -c '
table="{}"
fgpdu scan -d '"$PGDATA"' -t "$table" -o '"$OUTPUT"' -f sql
echo "Done: $table"
'
echo "All tables recovered."
五、程序各种案例场景与操作过程
5.1 案例 1:数据库无法启动 --- 全量数据导出
场景描述:PostgreSQL 因数据文件损坏、系统表损坏等原因无法启动,需要将全库数据导出到新库。
关键特性:
- 如果
pg_class/pg_database系统目录损坏导致无法列出表,FGPDU 会自动切换到 EMERGENCY 紧急文件级扫描 ,直接遍历base/下所有数据文件恢复数据,无需系统目录。 - 按数据库分目录导出:FGPDU 自动在输出目录下按数据库名创建子目录,每个数据库的所有表分别导出到各自的子目录中。
- 按用户名 unload :使用
-u <用户名/数据库名>参数可以只导出指定数据库的所有表。
操作步骤:
bash
# ============================================================
# 步骤 1:停止 PostgreSQL 服务
# ============================================================
systemctl stop postgresql
# ============================================================
# 步骤 2:备份原始数据目录(非常重要!避免在原目录上操作)
# ============================================================
cp -a /postgresql/data /backup/pgdata_backup_$(date +%Y%m%d)
# ============================================================
# 步骤 3:诊断数据目录
# ============================================================
fgpdu diagnose -d /postgresql/data -v
# ============================================================
# 步骤 4:列出数据库与表(如果系统表损坏,可能返回 0 表,FGPDU 会自动降级)
# ============================================================
fgpdu list databases -d /postgresql/data
fgpdu list tables -d /postgresql/data > /tmp/tables_list.txt
cat /tmp/tables_list.txt
# ============================================================
# 步骤 5:全量导出所有数据为 SQL 格式(自动按数据库分目录)
# 注意:如果 pg_class/pg_database 损坏,FGPDU 会自动切换到
# EMERGENCY 紧急文件级扫描模式
# ============================================================
mkdir -p /tmp/fgpdu_export
fgpdu scan -d /postgresql/data -o /tmp/fgpdu_export -v --continue-on-error
# ============================================================
# 步骤 5b:按用户名/数据库名精确导出(只导出指定数据库的所有表)
# ============================================================
fgpdu scan -d /postgresql/data -u fgedudb -o /tmp/fgpdu_export_fgedudb -v --continue-on-error
# 也可以导出为 DMP 格式(一表一文件)
fgpdu scan -d /postgresql/data -o /tmp/fgpdu_export -f dmp
# ============================================================
# 步骤 6:检查导出结果(按数据库子目录查看)
# ============================================================
ls -la /tmp/fgpdu_export/
for db_dir in /tmp/fgpdu_export/*/; do
db_name=$(basename "$db_dir")
file_count=$(ls "$db_dir"*.sql 2>/dev/null | wc -l)
dir_size=$(du -sh "$db_dir" | cut -f1)
echo " $db_name: $file_count 个 SQL 文件, 大小 $dir_size"
done
# ============================================================
# 步骤 7:查看 SQL 文件中的恢复步骤说明
# ============================================================
tail -80 /tmp/fgpdu_export/fgedudb/*.sql | head -100
# ============================================================
# 步骤 8:在新服务器上创建新库并导入(遍历所有子目录)
# ============================================================
createdb newdb
for db_dir in /tmp/fgpdu_export/*/; do
db_name=$(basename "$db_dir")
echo "=== Importing database: $db_name ==="
for f in "$db_dir"*.sql; do
[ -f "$f" ] || continue
echo " Importing $(basename "$f")..."
psql -d newdb -f "$f" || echo "WARNING: Failed to import $f"
done
done
# ============================================================
# 步骤 9:验证数据
# ============================================================
psql -d newdb -c "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';"
# ============================================================
# 步骤 10(备选):当所有高层命令都失败时,直接扫描单个数据文件
# ============================================================
fgpdu scan-file /postgresql/data/base/16384/16521 -o /tmp/fgpdu_export -v
SQL 输出文件中的恢复步骤说明示例:
每个 SQL 文件末尾会自动包含以下内容:
sql
-- ============================================================
-- FGPDU Data Recovery Report & Restore Guide
-- ============================================================
-- Recovery Time: 2026-08-07 12:00:00
-- Tool: FGPDU - FGEDU PostgreSQL DUL v1.0.0
-- Table: public.orders (OID: 16385)
-- Rows Recovered: 1256
-- Bad Blocks: 3 (skipped, data partially recovered)
-- ============================================================
--
-- RESTORE STEPS:
-- Step 1: CREATE DATABASE recovered_db;
-- Step 2: CREATE SCHEMA IF NOT EXISTS public;
-- Step 3: psql -d recovered_db -f public_orders.sql
-- Step 4: SELECT COUNT(*) FROM public.orders;
-- Step 5: REINDEX TABLE public.orders;
-- Step 6: ANALYZE public.orders;
--
-- ============================================================
-- Data Verification Queries
-- ============================================================
SELECT COUNT(*) AS total_rows FROM public.orders;
SELECT COUNT(*) AS null_violations FROM public.orders WHERE id IS NULL;
SELECT MIN(id), MAX(id), COUNT(DISTINCT id) FROM public.orders;
SELECT id, COUNT(*) FROM public.orders GROUP BY id HAVING COUNT(*) > 1;
5.2 案例 2:误执行 DELETE --- 恢复删除数据
场景描述 :用户误执行 DELETE FROM orders WHERE status='cancelled',删除了大量订单数据,需要恢复。
前提:尚未执行 VACUUM!如果已执行 VACUUM,数据可能已被物理清除。
操作步骤:
bash
# 步骤 1:立即停止数据库(防止 autovacuum 清除数据)
systemctl stop postgresql
# 或设置 autovacuum=off 后重启
# pg_ctl -D /postgresql/data -o "-c autovacuum=off" start
# 步骤 2:备份数据目录
cp -a /postgresql/data /backup/pgdata_before_recover
# 步骤 3:恢复指定表的删除数据
mkdir -p /tmp/delete_recover
fgpdu recover delete -d /postgresql/data -t public.orders -o /tmp/delete_recover -v
# 步骤 4:检查恢复结果
ls -la /tmp/delete_recover/
cat /tmp/delete_recover/*.sql | head -50
# 步骤 5:恢复所有表的删除数据(如果多张表受影响)
fgpdu recover delete -d /postgresql/data -o /tmp/delete_recover_all -v
# 步骤 6:在新库或原库中导入恢复的数据
# 注意:先检查恢复的数据,确认无误后再导入
psql -d mydb -f /tmp/delete_recover/public_orders_deleted.sql
5.3 案例 3:误执行 DROP TABLE --- 恢复被删除的表
场景描述 :用户误执行 DROP TABLE important_table,需要恢复表数据。
前提:数据文件尚未被文件系统回收。
操作步骤:
bash
# 步骤 1:停止数据库
systemctl stop postgresql
# 步骤 2:备份数据目录
cp -a /postgresql/data /backup/pgdata_before_drop_recover
# 步骤 3:恢复被 DROP 的表数据
mkdir -p /tmp/drop_recover
fgpdu recover drop -d /postgresql/data -o /tmp/drop_recover -v
# 步骤 4:检查恢复结果
ls -la /tmp/drop_recover/
# 恢复的文件名格式: orphan_<oid>_recovered.sql
# 步骤 5:查看恢复的数据
cat /tmp/drop_recover/orphan_*_recovered.sql | head -100
# 步骤 6:如果知道被删除表的 OID,可以直接扫描该文件
ls -la /postgresql/data/base/16384/
fgpdu scan-file /postgresql/data/base/16384/16400 -o /tmp/drop_recover -f sql -v
# 步骤 7:重建表结构并导入恢复的数据
psql -d mydb -c "CREATE TABLE important_table (id int, name text, ...);"
psql -d mydb -f /tmp/drop_recover/orphan_16400_recovered.sql
5.4 案例 4:误执行 TRUNCATE --- 恢复被截断的表
场景描述 :用户误执行 TRUNCATE TABLE large_table,清空了表数据,需要恢复。
前提:旧的 relfilenode 文件尚未被回收(TRUNCATE 会创建新 relfilenode,旧文件成为孤儿文件)。
操作步骤:
bash
# 步骤 1:停止数据库
systemctl stop postgresql
# 步骤 2:备份数据目录
cp -a /postgresql/data /backup/pgdata_before_truncate_recover
# 步骤 3:恢复被 TRUNCATE 的表数据
mkdir -p /tmp/truncate_recover
fgpdu recover truncate -d /postgresql/data -o /tmp/truncate_recover -v
# 步骤 4:检查恢复结果
ls -la /tmp/truncate_recover/
cat /tmp/truncate_recover/*.sql | wc -l # 查看恢复了多少行
# 步骤 5:导入恢复的数据
psql -d mydb -f /tmp/truncate_recover/orphan_*_recovered.sql
TRUNCATE 与 DROP 的区别:
| 操作 | pg_class | 数据文件 | 可恢复性 |
|---|---|---|---|
| DROP TABLE | 条目被删除 | 旧文件保留 | 可恢复(直到文件被回收) |
| TRUNCATE TABLE | 条目保留(新 relfilenode) | 旧文件保留 | 可恢复(直到文件被回收) |
| DELETE | 条目保留 | 文件不变 | 可恢复(直到 VACUUM) |
5.5 案例 5:系统表损坏 --- 直接扫描数据文件
场景描述:pg_class 等系统表损坏,无法通过正常方式列出表,需要直接扫描数据文件。
关键特性 :当 fgpdu scan 发现系统目录无表时,会自动切换到 EMERGENCY 紧急文件级扫描 ,直接遍历 base/ 下所有数据文件,无需手动逐个扫描。
操作步骤:
bash
# 步骤 1:诊断确认系统表损坏
fgpdu diagnose -d /postgresql/data -v
# 如果显示 "pg_class: FAILED",说明系统表损坏
# 步骤 2(推荐):直接执行 scan,FGPDU 会自动降级为紧急扫描
mkdir -p /tmp/raw_recover
fgpdu scan -d /postgresql/data -o /tmp/raw_recover -v --continue-on-error
# 日志中会显示:
# EMERGENCY FULL-DATABASE SCAN
# Catalog is missing or corrupted.
# Scanning every data file under base/ directly...
# 步骤 3(备选):直接浏览 base 目录,手动扫描单个文件
ls -la /postgresql/data/base/16384/
# 文件名就是 relfilenode(OID)
# 扫描单个文件
fgpdu scan-file /postgresql/data/base/16384/16385 -o /tmp/raw_recover -f sql -v
# 批量扫描所有文件(当自动扫描不生效时)
for f in /postgresql/data/base/16384/*; do
if [ -f "$f" ]; then
echo "=== Scanning: $f ==="
fgpdu scan-file "$f" -o /tmp/raw_recover -f sql 2>&1 | grep "rows extracted"
fi
done
# 步骤 4:检查恢复结果
ls -la /tmp/raw_recover/
echo "恢复文件数: $(ls /tmp/raw_recover/*.sql 2>/dev/null | wc -l)"
# 步骤 5:查看恢复的数据,手动识别表结构
for f in /tmp/raw_recover/*.sql; do
echo "=== $(basename $f) ==="
head -20 "$f"
echo ""
done
5.6 案例 6:指定用户 + Schema + 表精确恢复
场景描述:只需要恢复特定用户(数据库)下、特定 Schema 中、特定表的数据。
操作步骤:
bash
# 步骤 1:先列出数据库,确认目标数据库
fgpdu list databases -d /postgresql/data
# 输出:
# OID Name Path
# 5 postgres 5
# 16384 mydb 16384
# 步骤 2:列出指定数据库的表
fgpdu list tables -d /postgresql/data -u mydb -s public
# 步骤 3:精确恢复 --- 指定用户+Schema+表
mkdir -p /tmp/precise_recover
fgpdu scan -d /postgresql/data \
-u mydb \
-s public \
-t orders \
-o /tmp/precise_recover \
-f sql -v
# 步骤 4:恢复指定用户+Schema 下的删除数据
fgpdu recover delete -d /postgresql/data \
-u mydb \
-s public \
-o /tmp/precise_recover
# 步骤 5:恢复指定用户的 DROP 表数据
fgpdu recover drop -d /postgresql/data \
-u mydb \
-o /tmp/precise_recover
# 步骤 6:批量恢复多张表
for table in orders users products employees; do
echo "=== Recovering: public.$table ==="
fgpdu scan -d /postgresql/data \
-u mydb -s public -t $table \
-o /tmp/precise_recover -f sql
done
5.7 案例 7:大表多段文件恢复
场景描述:一张 5GB 的大表被 TRUNCATE,数据分布在 5 个段文件中(每个约 1GB),需要恢复全部数据。
段文件命名规则:
- 第一段:
<oid>(如16385) - 第二段:
<oid>.1(如16385.1) - 第三段:
<oid>.2(如16385.2)
操作步骤:
bash
# 步骤 1:确认段文件存在
ls -la /postgresql/data/base/16384/16400*
# 预期输出:
# 16400 (1GB)
# 16400.1 (1GB)
# 16400.2 (1GB)
# 16400.3 (1GB)
# 16400.4 (512MB)
# 步骤 2:使用 recover truncate 自动处理多段文件
mkdir -p /tmp/large_recover
fgpdu recover truncate -d /postgresql/data -o /tmp/large_recover -v
# 步骤 3:或使用 scan-file 直接扫描(自动处理多段)
fgpdu scan-file /postgresql/data/base/16384/16400 -o /tmp/large_recover -f sql -v
# 步骤 4:检查恢复结果
ls -la /tmp/large_recover/
wc -l /tmp/large_recover/16400_recovered.sql
5.8 案例 8:跨操作系统平台恢复
场景描述:生产服务器是 RHEL 7,需要在 Ubuntu 22.04 的恢复服务器上进行数据恢复。
操作步骤:
bash
# ============================================================
# 在 RHEL 7 生产服务器上(编译 FGPDU 或拷贝预编译版本)
# ============================================================
# 步骤 1:编译 FGPDU(或在其他机器编译后拷贝)
cd /path/to/FGPDU
make standalone
# 或
make portable
# 步骤 2:将 fgpdu 和数据目录拷贝到恢复服务器
scp build/portable/fgpdu recover@ubuntu-server:/tmp/
scp -r /postgresql/data recover@ubuntu-server:/tmp/pgdata_copy
# ============================================================
# 在 Ubuntu 22.04 恢复服务器上执行恢复
# ============================================================
# 步骤 3:赋予执行权限
chmod +x /tmp/fgpdu
# 步骤 4:验证 fgpdu 可运行
/tmp/fgpdu -V
# 步骤 5:诊断数据目录
/tmp/fgpdu diagnose -d /tmp/pgdata_copy
# 步骤 6:执行恢复
mkdir -p /tmp/recover_output
/tmp/fgpdu scan -d /tmp/pgdata_copy -o /tmp/recover_output -v --continue-on-error
# 步骤 7:检查恢复结果
ls -la /tmp/recover_output/
5.9 案例 9:Windows 平台恢复
场景描述:PostgreSQL 部署在 Windows Server 2019 上,数据目录因磁盘故障部分损坏,需要在 Windows 上直接恢复。
操作步骤:
bat
:: 步骤 1:停止 PostgreSQL 服务
net stop postgresql-15
:: 步骤 2:备份数据目录(使用 robocopy)
robocopy "C:\Program Files\PostgreSQL\15\data" "D:\backup\pgdata_backup" /E /COPYALL
:: 步骤 3:诊断数据目录
fgpdu.exe diagnose -d "C:\Program Files\PostgreSQL\15\data" -v
:: 步骤 4:列出数据库
fgpdu.exe list databases -d "C:\Program Files\PostgreSQL\15\data"
:: 步骤 5:全库导出
mkdir D:\fgpdu_export
fgpdu.exe scan -d "C:\Program Files\PostgreSQL\15\data" -o D:\fgpdu_export --continue-on-error
:: 步骤 6:恢复 DELETE 数据
fgpdu.exe recover delete -d "C:\Program Files\PostgreSQL\15\data" -o D:\recover
:: 步骤 7:扫描单个数据文件
fgpdu.exe scan-file "C:\Program Files\PostgreSQL\15\data\base\16384\16521" -o D:\recover_single
:: 步骤 8:查看导出结果
dir D:\fgpdu_export\*.sql
Windows 路径提示:
- FGPDU 自动识别正斜杠
/和反斜杠\,两种写法等价; - 路径含空格或中文时必须用双引号包裹;
- 接受盘符路径(
C:\...)和 UNC 路径(\\server\share)。
5.10 案例 10:RHEL 5 老系统部署
场景描述 :生产环境是 RHEL 5.11(glibc 2.5),FGPDU 在现代 Linux 编译后拷贝过去报 GLIBC_2.x not found 错误。
操作步骤:
bash
# 步骤 1:在任意现代 Linux 上交叉编译出 RHEL5 兼容二进制
make rhel5
# 产物:build/rhel5/fgpdu
# 步骤 2:验证不依赖高版本 glibc
file build/rhel5/fgpdu
readelf -s build/rhel5/fgpdu | grep GLIBC_ | head
# 预期:无 GLIBC_2.4+ 符号
# 步骤 3:拷贝到 RHEL5 服务器运行
scp build/rhel5/fgpdu root@rhel5-server:/usr/local/bin/
ssh root@rhel5-server '/usr/local/bin/fgpdu -V'
# 步骤 4:在 RHEL5 上执行恢复
ssh root@rhel5-server
/usr/local/bin/fgpdu diagnose -d /var/lib/pgsql/data -v
/usr/local/bin/fgpdu scan -d /var/lib/pgsql/data -o /tmp/recover --continue-on-error
如果要在 RHEL5 本机编译,需先安装:
bash
# 挂载 RHEL5 DVD ISO 作为 yum 源
mount -o loop /dev/cdrom /mnt
yum install gcc make glibc-static
make rhel5
5.11 案例 11:国产化系统(麒麟/UOS)部署
场景描述:客户环境是银河麒麟 V10 SP3 / 统信 UOS V20,需要在国产系统上恢复 PostgreSQL 数据。
操作步骤:
bash
# 麒麟/UOS 通常基于 RHEL/CentOS,可直接使用 standalone 编译
cd /path/to/FGPDU
yum install gcc make glibc-static
make standalone
# 如果是 ARM 架构的麒麟系统(如飞腾/鲲鹏),暂不支持(仅支持 x86_64/i686)
# 验证架构
uname -m
# 预期输出:x86_64 或 i686
# 编译完成后拷贝到目标机器
scp build/standalone/fgpdu root@kylin-server:/usr/local/bin/
# 执行恢复
/usr/local/bin/fgpdu diagnose -d /postgresql/data -v
/usr/local/bin/fgpdu scan -d /postgresql/data -o /tmp/recover --continue-on-error
六、常用问题与排查
6.1 常见运行时错误
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
Data directory not found |
数据目录路径错误 | 检查路径是否正确,使用 -d 指定绝对路径 |
Not a valid PG data directory |
目录不是合法的 PG 数据目录 | 确保目录包含 PG_VERSION 文件 |
pg_class not found |
系统表损坏或 PG 版本差异 | 使用 scan-file 直接扫描数据文件 |
Permission denied |
读权限不足 | 使用 postgres 用户运行,或 sudo |
File for OID not found |
数据文件已被 VACUUM 清除 | 尝试 recover drop 扫描孤立文件 |
Out of memory |
系统内存不足 | 增加系统内存,或使用 scan-file 分批处理 |
No such file or directory |
数据文件路径错误 | 使用 ls 确认文件存在 |
Segmentation fault |
数据文件严重损坏 | 已通过信号处理捕获,使用 --continue-on-error |
6.2 跨平台编译与运行排错
Q1: 在 RHEL 5 / CentOS 5 上运行报 GLIBC_2.x not found 或 segmentation fault
原因 :使用 make standalone 编译的二进制可能引用了 RHEL5 glibc 2.5 不支持的符号。
解决:必须使用专用的 RHEL5 编译目标:
bash
# 在任意现代 Linux 上交叉编译出 RHEL5 兼容二进制
make rhel5
# 验证不依赖高版本 glibc
file build/rhel5/fgpdu
readelf -s build/rhel5/fgpdu | grep GLIBC_ | head
# 预期:无 GLIBC_2.4+ 符号
# 拷贝到 RHEL5 服务器运行
scp build/rhel5/fgpdu root@rhel5-server:/usr/local/bin/
ssh root@rhel5-server '/usr/local/bin/fgpdu -V'
make rhel5 已通过编译期检测,在 gcc 4.1 环境下自动回退到 gettimeofday(),无需手动链接 librt。
Q2: 在 RHEL 6 / CentOS 6 上运行报 GLIBC 版本错误
解决:使用专用编译目标,兼顾新 ldflags 与旧 glibc 2.12:
bash
make rhel6
# 产物:build/rhel6/fgpdu
Q3: 在 RHEL 7 / CentOS 7 上编译或运行异常
解决:使用专用编译目标(glibc 2.17,gcc 4.8+):
bash
make rhel7
# 产物:build/rhel7/fgpdu
Q4: 如何在 Linux 上编译出 Windows 版 fgpdu.exe
前提:安装 MinGW-w64 交叉编译工具链。
bash
# RHEL / Fedora / CentOS
yum install mingw64-gcc mingw32-gcc mingw64-binutils mingw32-binutils
# Ubuntu / Debian
apt-get install gcc-mingw-w64-x86-64 gcc-mingw-w64-i686 binutils-mingw-w64
# 编译 64 位 Windows EXE
make windows-mingw
# 产物:build/win64/fgpdu.exe
# 编译 32 位 Windows EXE(兼容 XP x86)
make windows-mingw32
# 产物:build/win32/fgpdu_x86.exe
验证:
bash
file build/win64/fgpdu.exe
# 预期:PE32+ executable (console) x86-64, for MS Windows
# 测试运行(如安装了 Wine)
wine build/win64/fgpdu.exe -V
Q5: 在 Windows 上运行 fgpdu.exe 报「找不到入口」或「缺少 DLL」
原因:如果使用 MSVC 动态编译,可能缺少 VC++ 运行时。
解决:
-
推荐使用
make windows-mingw生成的全静态 EXE(零 DLL 依赖)。 -
如需用 MSVC 编译,使用项目提供的
build\windows-msvc.bat(自动静态链接):batcd \path\to\FGPDU build\windows-msvc.bat
Q6: Windows 路径含空格或中文导致报错
解决 :路径用双引号包裹,FGPDU 自动兼容正斜杠 / 和反斜杠 \:
bat
:: 正确写法
fgpdu.exe diagnose -d "C:\Program Files\PostgreSQL\15\data"
fgpdu.exe scan -d "D:/PG数据/15/data" -o "E:/recover"
:: 错误写法(路径未加引号)
fgpdu.exe diagnose -d C:\Program Files\PostgreSQL\15\data
Q7: make windows-mingw 报 x86_64-w64-mingw32-gcc: command not found
原因:未安装 MinGW-w64 交叉编译器。
解决:
bash
# RHEL / Fedora
yum install mingw64-gcc
# Ubuntu / Debian
apt-get install gcc-mingw-w64-x86-64
# 验证
x86_64-w64-mingw32-gcc --version
Q8: RHEL5 上 make rhel5 报 clock_gettime 链接失败
原因 :RHEL5 的 glibc 2.5 将 clock_gettime 放在 librt 中,静态链接时可能找不到。
解决 :make rhel5 目标已通过编译期检测,在 gcc 4.1 环境下自动回退到 gettimeofday(),无需手动链接 librt。确保使用的是最新代码:
bash
# 确认时间函数已回退
grep -n "gettimeofday" src/utils/pg_platform.c
# 预期输出包含 RHEL5 gcc-4.1 分支
6.3 数据恢复相关常见问题
Q1: 恢复后数据不完整?
- 原因:VACUUM 已运行,物理删除了部分数据。
- 解决 :尽快恢复,在 VACUUM 之前执行。可以禁用 autovacuum:
ALTER TABLE orders SET (autovacuum_enabled = false);
Q2: pg_class 读不到?
- 原因:系统表损坏或 PG 版本不匹配。
- 解决 :使用
scan-file直接扫描数据文件,绕过系统表。或直接执行scan命令,FGPDU 会自动降级为 EMERGENCY 紧急扫描模式。
Q3: 恢复的数据有乱码?
-
原因:字符集不匹配。
-
解决:确保新库的 encoding 与原库一致。查看原库 encoding:
bashpg_controldata /postgresql/data | grep LC_
Q4: 如何确认数据已删除?
- 在 PG 中执行
SELECT count(*) FROM table;,对比 FGPDU 恢复的行数。 - FGPDU 恢复的行数通常大于或等于 SELECT 结果(包含已删除但未 VACUUM 的行)。
Q5: 是否会修改原数据文件?
- 不会。FGPDU 是只读操作,不会修改任何原始数据文件。可以放心反复尝试不同的恢复策略。
Q6: 提示 "File for OID not found" 怎么办?
- 数据文件可能已被 VACUUM 或操作系统回收。
- 尝试使用
recover drop扫描孤立文件。 - 或使用
scan-file直接扫描 base 目录下的文件。
Q7: 诊断时显示 "pg_control file missing"?
- pg_control 文件位于
global/pg_control。 - 如果丢失,FGPDU 将使用默认块大小(8192)。
- 大多数情况下不影响数据恢复。
Q8: 大表恢复很慢怎么办?
- 使用
--progress查看进度。 - 使用
-v查看详细日志,定位慢的表。 - 考虑将数据目录拷贝到本地 SSD 上再恢复。
- 使用
scan-file单独处理大表。 - 使用并行脚本(参见 4.4.4 节)同时处理多张表。
Q9: 恢复的 SQL 文件导入报错?
-
可能是表结构不匹配。
-
先手动创建表结构,再导入数据:
bashpsql -d mydb -c "CREATE TABLE orders (id int, name text, ...);" # 然后只导入 INSERT 语句部分 grep "^INSERT" /tmp/export/public_orders.sql | psql -d mydb -
或修改 SQL 文件中的
CREATE TABLE语句。
Q10: 如何在恢复前预览数据?
bash
# 使用 scan-file 扫描并查看输出
fgpdu scan-file /postgresql/data/base/16384/16385 -o /tmp/preview -f sql
head -50 /tmp/preview/16385_recovered.sql
Q11: 恢复过程中出现 Segmentation fault?
- 这是数据文件严重损坏触发的信号。
- FGPDU 已通过信号处理捕获,会输出提示信息后安全退出。
- 使用
--continue-on-error选项继续扫描。 - 使用
scan-file单独处理有问题的文件。
Q12: 如何处理 TOAST 表数据?
- FGPDU 自动处理 TOAST 元组重组。
- 当主表数据行过大被 TOAST 化时,FGPDU 会自动关联 TOAST 表并重组完整数据。
- 无需手动干预。
6.4 跨平台验证清单
部署到目标平台后,按以下步骤验证 FGPDU 是否正常工作:
| 步骤 | Linux 命令 | Windows 命令 | 预期结果 |
|---|---|---|---|
| 1. 版本检查 | ./fgpdu -V |
fgpdu.exe -V |
显示版本号和平台信息 |
| 2. 帮助信息 | ./fgpdu -h |
fgpdu.exe -h |
显示完整命令列表 |
| 3. 诊断 PG 数据目录 | ./fgpdu diagnose -d $PGDATA -v |
fgpdu.exe diagnose -d "C:\...\data" -v |
输出目录结构检查结果 |
| 4. 列出数据库 | ./fgpdu list databases -d $PGDATA |
fgpdu.exe list databases -d "C:\...\data" |
显示数据库列表 |
| 5. 列出表 | ./fgpdu list tables -d $PGDATA |
fgpdu.exe list tables -d "C:\...\data" |
显示表列表 |
| 6. 全库导出 | ./fgpdu scan -d $PGDATA -o /tmp/out |
fgpdu.exe scan -d "C:\...\data" -o D:\out |
生成 .sql 文件 |
| 7. 恢复 DELETE 数据 | ./fgpdu recover delete -d $PGDATA -o /tmp/r |
fgpdu.exe recover delete -d "C:\...\data" -o D:\r |
生成恢复 SQL |
| 8. 扫描单文件 | ./fgpdu scan-file $PGDATA/base/16384/16521 -o /tmp/r |
fgpdu.exe scan-file "C:\...\data\base\16384\16521" -o D:\r |
输出单表数据 |
提示 :在 RHEL 5/6/7 上部署时,建议先用
make rhel5/make rhel6/make rhel7编译专用二进制,再按上表逐步验证。
6.5 恢复注意事项
- 尽快恢复 :数据删除后请尽快恢复,VACUUM 运行后数据将无法恢复。建议立即停止数据库或设置
autovacuum=off。 - 只读操作:FGPDU 对数据目录是只读的,不会修改原始数据,可以放心反复尝试。
- 关闭数据库:建议在 PostgreSQL 停止状态下使用,避免数据不一致和 autovacuum 干扰。
- 备份优先 :使用前强烈建议备份原始数据目录(
cp -a或rsync),即使在备份上操作。 - 权限要求 :需要对 PG 数据目录有读权限(通常
postgres用户或root)。 - 输出目录空间:确保输出目录有足够空间(至少数据目录大小的 1.5 倍)。
- 字符集一致:新库的字符集和 LC_* 设置应与原库一致,避免乱码。
七、附录
7.1 命令速查表
bash
# 基本命令
fgpdu -V # 查看版本
fgpdu -h # 查看帮助
fgpdu diagnose -d PGDATA # 诊断数据目录
fgpdu diagnose -d PGDATA -v # 诊断(详细模式)
# 列表命令
fgpdu list tables -d PGDATA # 列出所有表
fgpdu list tables -d PGDATA -s public # 列出指定 schema 的表
fgpdu list tables -d PGDATA -t orders # 查找指定表名
fgpdu list databases -d PGDATA # 列出数据库
fgpdu list schemas -d PGDATA # 列出 Schema
# 数据导出
fgpdu scan -d PGDATA -o DIR # 导出全部(SQL)
fgpdu scan -d PGDATA -o DIR -f csv # 导出全部(CSV)
fgpdu scan -d PGDATA -o DIR -f dmp # 导出全部(DMP)
fgpdu scan -d PGDATA -t public.orders -o DIR # 导出指定表
fgpdu scan -d PGDATA -u postgres -o DIR # 按用户名导出
fgpdu scan -d PGDATA -s public -o DIR # 按 schema 导出
fgpdu scan -d PGDATA -u mydb -s public -t orders -o DIR # 精确导出
# 数据恢复
fgpdu recover delete -d PGDATA -o DIR # 恢复 DELETE 数据
fgpdu recover delete -d PGDATA -t public.orders -o DIR # 恢复指定表 DELETE
fgpdu recover delete -d PGDATA -u mydb -s public -o DIR # 恢复指定用户/schema DELETE
fgpdu recover drop -d PGDATA -o DIR # 恢复 DROP 表数据
fgpdu recover drop -d PGDATA -u mydb -o DIR # 恢复指定用户 DROP
fgpdu recover truncate -d PGDATA -o DIR # 恢复 TRUNCATE 表数据
fgpdu recover truncate -d PGDATA -u mydb -o DIR # 恢复指定用户 TRUNCATE
# 文件扫描
fgpdu scan-file FILE -o DIR # 扫描单个文件
fgpdu scan-file FILE -o DIR -f sql # 扫描并输出 SQL
fgpdu scan-file FILE -o DIR -f dmp # 扫描并输出 DMP
fgpdu scan-file FILE -o DIR -v # 详细模式
# 高级选项
fgpdu scan -d PGDATA -o DIR -v # 详细日志
fgpdu scan -d PGDATA -o DIR --progress # 显示进度
fgpdu scan -d PGDATA -o DIR --continue-on-error # 遇错继续(自适应扫描)
7.2 性能建议
- 内存:大数据集建议 8GB+ 内存。
- 存储:输出目录使用 SSD 可大幅提升性能。
- 网络:拷贝到本地磁盘后再恢复,避免网络 I/O 瓶颈。
- 并行:可通过脚本并行处理多个表(参见 4.4.4 节)。
- 过滤 :使用
-t指定表名,避免不必要的全量扫描。 - 格式选择:大规模恢复时优先使用 DMP 格式(速度最快),需要可读性时使用 SQL 格式。
7.3 目录结构
FGPDU/
├── include/ # 头文件
│ ├── fgpdu.h # 主头文件(类型/常量/错误码)
│ ├── page/ # 页面解析
│ ├── tuple/ # 元组解析
│ ├── io/ # IO 引擎
│ ├── dbdict/ # 系统表字典
│ ├── scan/ # 扫描器
│ ├── output/ # 输出器
│ ├── cli/ # 命令行接口
│ ├── utils/ # 工具函数
│ └── version/ # 版本兼容
├── src/ # 源代码
├── build/ # 构建输出
├── docs/ # 文档目录
├── Makefile # 构建脚本
├── build_standalone.sh # 独立编译脚本
├── README.md # 说明文档
├── USAGE.md # 使用手册
└── TESTDOC.md # 测试手册
7.4 作者信息
| 联系方式 | 信息 |
|---|---|
| 作者 风哥 | |
| 官方网站 : http://www.fgedu.net.cn , http://www.itpux.com | |
| 数据库教程 : https://edu.51cto.com/lecturer/8020378.html |
7.5 版本历史
- v1.0.7 (2026-08):跨平台扩展,同时支持 Linux 与 Windows;RHEL 5/6/7 专用编译目标;新增 Windows(XP~11,x86 & x64)原生支持。
- v1.0.6 (2026-08):紧急全库扫描;坏块跳过机制;数据完整性校验;恢复步骤导出;内存安全加固。
- v1.0.5 (2026-08):增强恢复能力,多段文件支持,自适应扫描,元组校验。
- v1.0.4 (2026-08):最大数据恢复策略,原始元组扫描器,所有扫描循环改为 continue 而非 break。
- v1.0.3 (2026-08):稳定性加固,添加信号处理,修复多个指针越界问题。
- v1.0.2 (2026-08):新增按用户名/数据库名精确恢复功能,三维度组合过滤。
- v1.0.1 (2026-08):修复 PG_VERSION 解析错误,添加自动检测数据块大小功能。
- v1.0.0 (2025-08):初始版本发布,支持 PG for RHEL 5~10,实现 DELETE/DROP/TRUNCATE 恢复。