MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

PostgreSQL逻辑复制故障排查与恢复

2022-03-136.1k 阅读

逻辑复制概述

PostgreSQL 的逻辑复制是一种基于发布 - 订阅模型的复制机制。它允许从一个 PostgreSQL 数据库(发布端)向一个或多个其他 PostgreSQL 数据库(订阅端)复制数据更改。与物理复制不同,逻辑复制在逻辑层面工作,基于 WAL(Write - Ahead Log)中的逻辑日志记录,这些记录描述了数据库对象(如表、视图等)的更改。

逻辑复制具有诸多优点,例如可以基于表或行进行过滤,支持多订阅端,并且可以跨不同版本的 PostgreSQL 数据库进行复制。这使得它在数据分发、数据集成以及高可用和灾难恢复场景中具有广泛应用。

逻辑复制的工作原理

  1. 发布端:当发布端的数据库发生数据更改时,这些更改首先被记录到 WAL 日志中。逻辑复制插件(如 pgoutputwal2json)会将 WAL 日志中的逻辑更改提取出来,并转换为逻辑复制消息。这些消息被发送到订阅端。
  2. 订阅端:订阅端接收来自发布端的逻辑复制消息,并将这些消息应用到本地数据库,从而使订阅端数据库与发布端数据库保持数据同步。

故障排查通用方法

1. 检查复制相关配置

在进行故障排查时,首先要确保 PostgreSQL 配置文件(postgresql.conf)中的逻辑复制相关参数正确设置。

  • wal_level:应设置为 logical,以确保 WAL 日志中包含逻辑复制所需的信息。示例配置:
wal_level = logical
  • max_replication_slots:设置最大复制槽数量,需根据实际需求合理配置,例如:
max_replication_slots = 10
  • max_wal_senders:定义最大 WAL 发送进程数,同样要根据系统资源和预期的复制负载调整,如:
max_wal_senders = 10

2. 验证网络连接

逻辑复制依赖于网络连接,确保发布端和订阅端之间的网络畅通至关重要。

  • 可以使用 ping 命令检查主机之间的连通性:
ping <发布端主机地址>
ping <订阅端主机地址>
  • 还需检查 PostgreSQL 服务所使用的端口(默认为 5432)是否开放。在 Linux 系统上,可以使用 netstatss 命令检查端口状态:
netstat -an | grep 5432

如果端口未开放,需配置防火墙规则以允许通过该端口的连接。例如,在 CentOS 系统上,使用 firewalld 开放端口:

sudo firewall - cmd --zone = public --add - port = 5432 / tcp -- permanent
sudo firewall - cmd --reload

3. 检查复制槽状态

复制槽在逻辑复制中起着关键作用,它记录了发布端发送给订阅端的 WAL 位置。通过检查复制槽状态,可以发现潜在问题。

  • 使用 psql 连接到发布端数据库,查询 pg_replication_slots 系统视图:
SELECT slot_name, plugin, slot_type, database, active, restart_lsn
FROM pg_replication_slots;
  • 如果复制槽状态显示为非活动(active = false),可能意味着订阅端与发布端的连接中断。可以尝试重新连接订阅端,或删除并重新创建复制槽。例如,删除名为 my_slot 的复制槽:
SELECT pg_drop_replication_slot('my_slot');

然后重新创建复制槽:

SELECT pg_create_logical_replication_slot('my_slot', 'pgoutput');

4. 查看日志文件

PostgreSQL 的日志文件包含了丰富的信息,对于故障排查非常有帮助。

  • 日志文件位置通常在 postgresql.conf 中的 log_directory 参数指定的目录下。查看日志文件(如 postgresql - <日期>.log),查找与逻辑复制相关的错误信息。常见的错误信息包括连接拒绝、复制槽错误等。
  • 可以通过调整日志级别来获取更详细的信息。在 postgresql.conf 中设置 log_statement = 'all' 可以记录所有 SQL 语句,设置 log_min_messages = 'debug1' 可以获取更详细的调试信息。但请注意,这些设置可能会生成大量日志,对系统性能有一定影响,应在故障排查完成后恢复到正常设置。

常见故障场景及排查

1. 订阅端无法连接到发布端

  • 故障描述:在创建订阅时,订阅端无法连接到发布端,提示连接拒绝或超时错误。
  • 可能原因及排查方法
    • 网络问题:按照前文“验证网络连接”部分的方法,检查网络连通性和端口开放情况。
    • 认证问题:确保发布端的认证配置允许订阅端连接。检查 pg_hba.conf 文件,添加类似以下的配置,允许订阅端主机以合适的认证方式连接:
host    replication     <订阅端用户名>    <订阅端主机地址>/32    md5

重新加载 pg_hba.conf 配置:

pg_ctl reload
- **发布端服务未运行或配置错误**:检查发布端 PostgreSQL 服务是否正在运行。可以使用 `systemctl` 命令查看服务状态:
systemctl status postgresql

如果服务未运行,启动服务:

systemctl start postgresql

同时,再次确认 postgresql.conf 中的逻辑复制相关配置参数正确。

2. 数据同步延迟或停止

  • 故障描述:订阅端的数据同步出现延迟,或者完全停止同步,数据不再更新。
  • 可能原因及排查方法
    • 网络不稳定:虽然网络连接未完全中断,但不稳定的网络可能导致数据传输延迟。可以使用 ping 命令持续监测网络延迟和丢包情况:
ping - c 100 <发布端主机地址>

如果发现网络不稳定,联系网络管理员解决网络问题。 - 复制槽问题:检查复制槽状态,如前文所述,查询 pg_replication_slots 系统视图。如果复制槽出现异常,例如 restart_lsn 长时间未更新,可能需要重新创建复制槽。 - 资源不足:发布端或订阅端的系统资源(如 CPU、内存、磁盘 I/O)不足可能导致数据同步问题。使用系统监控工具(如 topiostat)检查系统资源使用情况。如果资源不足,考虑优化数据库负载或增加系统资源。 - 表结构不一致:如果在复制过程中,发布端的表结构发生了变化(如添加列、修改数据类型等),而订阅端未同步更新,可能导致数据同步停止。确保在发布端进行表结构更改时,按照逻辑复制的规则进行操作,例如使用 ALTER TABLE... REPLICA IDENTITY 语句,以确保订阅端能够正确应用更改。例如,在发布端添加列时:

BEGIN;
ALTER TABLE my_table ADD COLUMN new_column INT;
ALTER TABLE my_table REPLICA IDENTITY FULL;
COMMIT;

3. 逻辑复制错误:“ERROR: could not receive data from WAL stream: FATAL: the replication slot '...' was not found”

  • 故障描述:在订阅端尝试同步数据时,出现此错误,表明订阅端找不到指定的复制槽。
  • 可能原因及排查方法
    • 复制槽被意外删除:在发布端,查询 pg_replication_slots 系统视图,确认指定的复制槽是否存在。如果不存在,需要重新创建复制槽。例如,重新创建名为 my_slot 的复制槽:
SELECT pg_create_logical_replication_slot('my_slot', 'pgoutput');
- **复制槽名称配置错误**:检查订阅端的订阅配置,确保使用的复制槽名称与发布端创建的复制槽名称一致。可以通过查询 `pg_subscription` 系统视图查看订阅配置:
SELECT subname, subslotname
FROM pg_subscription;

如果名称不一致,需要修改订阅配置。首先删除现有订阅:

SELECT pg_drop_subscription('my_subscription');

然后重新创建订阅,指定正确的复制槽名称:

CREATE SUBSCRIPTION my_subscription
CONNECTION 'host = <发布端主机地址> port = 5432 user = <订阅端用户名> password = <订阅端密码> dbname = <发布端数据库名>'
PUBLICATION my_publication
WITH (create_slot = false, slot_name ='my_slot');

故障恢复策略

1. 重新初始化订阅

  • 适用场景:当订阅端出现严重数据不一致,或无法通过常规方法恢复同步时,可以考虑重新初始化订阅。
  • 操作步骤
    • 在订阅端删除现有订阅
SELECT pg_drop_subscription('my_subscription');
- **在发布端删除相关复制槽(可选)**:如果需要重新创建复制槽,可以先删除现有复制槽:
SELECT pg_drop_replication_slot('my_slot');
- **重新创建发布和订阅**:
    - 在发布端创建发布:
CREATE PUBLICATION my_publication FOR TABLE my_table;
    - 在订阅端创建订阅:
CREATE SUBSCRIPTION my_subscription
CONNECTION 'host = <发布端主机地址> port = 5432 user = <订阅端用户名> password = <订阅端密码> dbname = <发布端数据库名>'
PUBLICATION my_publication
WITH (create_slot = true);

此方法会重新从发布端获取数据,并将订阅端的数据更新到与发布端一致的状态。但请注意,此操作可能会导致订阅端数据的短暂丢失,因此在执行前需谨慎评估。

2. 手动修复数据不一致

  • 适用场景:当数据不一致情况较为局部,且通过分析可以确定具体的差异时,可以手动修复数据。
  • 操作步骤
    • 分析数据差异:使用工具或 SQL 查询,找出发布端和订阅端数据不一致的部分。例如,可以使用 EXCEPT 操作符在两个数据库之间比较数据。假设我们有一个 my_table 表,在发布端和订阅端分别查询:
-- 在发布端查询
SELECT * FROM my_table
EXCEPT
SELECT * FROM my_table;

-- 在订阅端查询
SELECT * FROM my_table
EXCEPT
SELECT * FROM my_table;

通过对比两个查询的结果,确定需要插入、更新或删除的数据。 - 手动执行数据操作:根据分析结果,在订阅端手动执行相应的 INSERTUPDATEDELETE 操作,以使数据与发布端一致。例如,如果发现订阅端缺少某条记录,可以在订阅端执行插入操作:

INSERT INTO my_table (column1, column2) VALUES ('value1', 'value2');

手动修复数据需要对数据库结构和数据有深入了解,操作时需格外小心,以免引入新的错误。

3. 利用备份恢复

  • 适用场景:当逻辑复制故障导致订阅端数据丢失或严重损坏,且无法通过其他方法快速恢复时,可以利用备份进行恢复。
  • 操作步骤
    • 获取备份:如果之前对订阅端数据库进行了备份(如使用 pg_dump 或物理备份工具),获取最新的备份文件。
    • 恢复备份:根据备份类型,使用相应的恢复工具。例如,如果是 pg_dump 备份,可以使用 pg_restore 命令恢复:
pg_restore - d <订阅端数据库名> <备份文件路径>

恢复备份后,重新配置逻辑复制,确保订阅端能够继续从发布端同步数据。这种方法相对复杂,且可能需要停机操作,但能保证数据的完整性。

预防故障的最佳实践

1. 定期监控和维护

  • 监控复制状态:定期查询 pg_replication_slotspg_subscription 系统视图,监控复制槽和订阅的状态。可以使用自动化工具(如 Nagios、Zabbix)设置监控报警,当复制状态出现异常时及时通知管理员。
  • 清理无用复制槽:定期检查并删除不再使用的复制槽,以避免占用系统资源。例如,查询 pg_replication_slots 系统视图,找出非活动且无用的复制槽并删除:
SELECT pg_drop_replication_slot(slot_name)
FROM pg_replication_slots
WHERE active = false AND slot_name NOT LIKE 'pg_physical_%';

2. 合理配置资源

  • 硬件资源:根据数据库负载和预期的逻辑复制流量,合理分配服务器的 CPU、内存和磁盘 I/O 资源。确保服务器有足够的资源来处理逻辑复制过程中的数据传输和处理。
  • 数据库参数:仔细调整 PostgreSQL 配置文件中的参数,如 wal_levelmax_replication_slotsmax_wal_senders 等,以优化逻辑复制性能。同时,根据实际情况调整 shared_bufferswork_mem 等其他参数,以提高数据库整体性能。

3. 版本兼容性

  • 发布端和订阅端版本:确保发布端和订阅端的 PostgreSQL 版本兼容。虽然逻辑复制支持跨版本复制,但某些版本之间可能存在已知的兼容性问题。在进行版本升级或部署新的逻辑复制环境时,查阅 PostgreSQL 官方文档,了解版本兼容性要求。
  • 插件版本:如果使用了逻辑复制插件(如 pgoutputwal2json),确保插件版本与 PostgreSQL 版本兼容。插件的不兼容可能导致逻辑复制故障。

4. 变更管理

  • 表结构变更:在发布端进行表结构变更时,遵循逻辑复制的规则。例如,在添加或修改列时,使用 ALTER TABLE... REPLICA IDENTITY 语句,确保订阅端能够正确应用更改。同时,在变更前进行充分的测试,确保逻辑复制不受影响。
  • 数据库配置变更:对发布端或订阅端的数据库配置(如 postgresql.confpg_hba.conf)进行变更时,提前备份配置文件,并在变更后仔细检查逻辑复制是否正常运行。可以在测试环境中先进行配置变更测试,验证无误后再应用到生产环境。

通过遵循这些最佳实践,可以有效预防逻辑复制故障的发生,提高逻辑复制系统的稳定性和可靠性。在实际应用中,应根据具体的业务需求和系统环境,灵活运用这些方法和策略,确保 PostgreSQL 逻辑复制的高效运行。