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

PostgreSQL Hot Standby模式解析与应用

2024-08-147.6k 阅读

1. PostgreSQL Hot Standby 模式基础概念

PostgreSQL 的 Hot Standby 模式是一种重要的高可用性解决方案。在这种模式下,一个或多个备用服务器(standby server)与主服务器(primary server)保持数据同步,通过持续接收主服务器的 WAL(Write - Ahead Log,预写式日志)日志并进行应用,备用服务器能保持与主服务器数据的一致性。

与其他数据库高可用方案相比,Hot Standby 模式的优势在于备用服务器不仅可以在主服务器故障时迅速接管服务,在主服务器正常运行时,还能分担读负载,提高系统整体的读性能。

1.1 工作原理概述

主服务器在处理事务时,会将 WAL 日志写入磁盘,并通过流复制(streaming replication)机制将 WAL 日志发送给备用服务器。备用服务器接收到 WAL 日志后,先将其存储在本地,然后按照日志顺序进行回放(replay),从而使备用服务器上的数据状态与主服务器尽可能接近。

具体来说,主服务器有一个称为“wal sender”的进程,负责将 WAL 日志发送给备用服务器的“wal receiver”进程。备用服务器的“wal receiver”进程接收到日志后,将其存储在本地的 WAL 存档目录中。之后,备用服务器的“standby start”进程会读取这些 WAL 日志并应用到数据库实例上。

2. 配置 PostgreSQL Hot Standby 模式

2.1 主服务器配置

首先,需要在主服务器上进行一系列配置。

  1. 修改 postgresql.conf 文件

    • 开启 WAL 日志归档功能,找到并修改 archive_mode 参数为 on
    archive_mode = on
    
    • 设置 WAL 日志归档的目标路径,例如:
    archive_command = 'cp %p /var/lib/postgresql/13/archivedir/%f'
    

    这里假设 PostgreSQL 版本为 13,归档目录为 /var/lib/postgresql/13/archivedir%p 是源 WAL 文件路径,%f 是 WAL 文件名称。

    • 配置流复制相关参数,增加或修改以下参数:
    listen_addresses = '*'
    max_wal_senders = 10
    wal_level = replica
    

    listen_addresses = '*' 表示监听所有可用的网络接口;max_wal_senders 定义了允许同时存在的 WAL 发送进程数量;wal_level = replica 确保 WAL 日志包含足够的信息用于复制。

  2. 修改 pg_hba.conf 文件: 为备用服务器添加认证信息,允许备用服务器连接主服务器进行流复制。例如:

    host    replication     replica_user    192.168.1.100/32    md5
    

    这里 replication 表示连接类型为复制,replica_user 是备用服务器连接主服务器使用的用户名,192.168.1.100 是备用服务器的 IP 地址,md5 表示使用 MD5 加密认证。

  3. 创建复制用户: 在主服务器上使用 psql 命令行工具创建一个用于复制的用户:

    CREATE USER replica_user WITH REPLICATION LOGIN CONNECTION LIMIT 10 ENCRYPTED PASSWORD 'password';
    

    该用户具有 REPLICATION 权限,允许其进行流复制操作,CONNECTION LIMIT 10 限制了该用户的最大连接数,ENCRYPTED PASSWORD 设置了加密后的密码。

  4. 重启 PostgreSQL 服务: 在完成上述配置后,重启 PostgreSQL 服务使配置生效。在基于 systemd 的系统上,可以使用以下命令:

    sudo systemctl restart postgresql
    

2.2 备用服务器配置

  1. 初始化备用服务器数据目录: 可以使用 pg_basebackup 工具从主服务器复制基础数据到备用服务器。例如:

    pg_basebackup -h 192.168.1.10 -U replica_user -D /var/lib/postgresql/13/main -P -X stream
    

    其中,-h 是主服务器的 IP 地址,-U 是复制用户,-D 是备用服务器的数据目录,-P 显示进度,-X stream 表示使用流复制模式获取 WAL 日志。

  2. 修改 recovery.conf 文件(PostgreSQL 12 及之前版本)或 postgresql.auto.conf 文件(PostgreSQL 13 及之后版本)

    • 在 PostgreSQL 12 及之前版本,创建或修改 recovery.conf 文件,添加以下内容:
    standby_mode = 'on'
    primary_conninfo = 'host=192.168.1.10 port=5432 user=replica_user password=password'
    restore_command = 'cp /var/lib/postgresql/13/archivedir/%f %p'
    

    standby_mode = 'on' 表示该服务器处于备用模式;primary_conninfo 配置了连接主服务器的信息;restore_command 用于从归档目录中恢复 WAL 日志。

    • 在 PostgreSQL 13 及之后版本,修改 postgresql.auto.conf 文件:
    standby_mode = 'on'
    primary_conninfo = 'host=192.168.1.10 port=5432 user=replica_user password=password'
    restore_command = 'cp /var/lib/postgresql/13/archivedir/%f %p'
    

    同样的配置,只是文件名称和管理方式略有不同。

  3. 修改 postgresql.conf 文件: 在备用服务器上,需要修改 postgresql.conf 文件,设置 wal_level = replica,确保备用服务器能正确处理接收到的 WAL 日志。

  4. 启动备用服务器: 在完成上述配置后,启动备用服务器的 PostgreSQL 服务:

    sudo systemctl start postgresql
    

3. Hot Standby 模式下的读写操作

3.1 读操作

在 Hot Standby 模式下,备用服务器可以用于分担读负载。由于备用服务器与主服务器保持数据同步,因此可以在备用服务器上执行只读查询,减轻主服务器的压力。

例如,在备用服务器上可以使用 psql 工具连接数据库并执行查询:

psql -U your_user -d your_database
SELECT * FROM your_table;

在应用程序层面,也可以通过配置连接字符串,将读请求导向备用服务器。例如,在 Java 应用中使用 JDBC 连接备用服务器:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class StandbyReadExample {
    public static void main(String[] args) {
        try {
            Connection conn = DriverManager.getConnection("jdbc:postgresql://192.168.1.101:5432/your_database", "your_user", "your_password");
            Statement stmt = conn.createStatement();
            ResultSet rs = stmt.executeQuery("SELECT * FROM your_table");
            while (rs.next()) {
                System.out.println(rs.getString(1));
            }
            rs.close();
            stmt.close();
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这里假设备用服务器的 IP 地址为 192.168.1.101

3.2 写操作

写操作主要在主服务器上执行。当主服务器接收到写事务时,它会将 WAL 日志记录下来,并通过流复制发送给备用服务器。备用服务器接收到 WAL 日志后,会在本地应用这些日志,从而保持数据同步。

例如,在主服务器上使用 psql 执行插入操作:

psql -U your_user -d your_database
INSERT INTO your_table (column1, column2) VALUES ('value1', 'value2');

主服务器会将这个插入操作的 WAL 日志发送给备用服务器,备用服务器应用该日志后,your_table 表在主备服务器上的数据就保持一致了。

4. 故障切换与自动故障恢复

4.1 手动故障切换

当主服务器出现故障时,可以手动将备用服务器提升为新的主服务器。在备用服务器上,使用以下命令进行提升:

pg_ctl promote

执行该命令后,备用服务器会停止接收主服务器的 WAL 日志,并开始作为独立的主服务器运行。此时,需要更新其他备用服务器以及应用程序的连接配置,使其连接到新的主服务器。

4.2 自动故障恢复

为了实现自动故障恢复,可以使用第三方工具,如 Patroni、Repmgr 等。以 Patroni 为例,它是一个用于 PostgreSQL 的高可用性解决方案,能够自动检测主服务器故障并进行故障切换。

  1. 安装 Patroni: 在所有参与高可用集群的服务器上安装 Patroni,可以通过包管理器(如 pip)进行安装:
    pip install patroni
    
  2. 配置 Patroni: 编辑 Patroni 的配置文件,通常为 patroni.yml。以下是一个简单的示例配置:
    scope: my_cluster
    name: standby1
    restapi:
      listen: 192.168.1.101:8008
      connect_address: 192.168.1.101:8008
    postgresql:
      listen: 192.168.1.101:5432
      connect_address: 192.168.1.101:5432
      data_dir: /var/lib/postgresql/13/main
      pg_hba:
        - host replication replica_user 0.0.0.0/0 md5
        - host all all 0.0.0.0/0 md5
      parameters:
        wal_level: replica
        max_wal_senders: 10
        shared_buffers: 2GB
    etcd:
      host: 192.168.1.103:2379,192.168.1.104:2379,192.168.1.105:2379
      username: etcd_user
      password: etcd_password
    
    scope 定义了集群名称,name 是当前节点的名称,restapi 配置了 Patroni 的 REST API 监听地址,postgresql 部分配置了 PostgreSQL 的相关参数,etcd 部分配置了 etcd 集群的信息。
  3. 启动 Patroni: 在每台服务器上启动 Patroni 服务:
    patronictl start
    
    Patroni 会自动检测主服务器状态,当主服务器故障时,它会选择一个备用服务器提升为新的主服务器,并更新集群中其他节点的配置。

5. 性能优化与监控

5.1 性能优化

  1. 网络优化: 主备服务器之间的网络带宽和延迟对复制性能有很大影响。确保主备服务器之间的网络连接稳定,并且具有足够的带宽。可以通过调整网络设备的配置、使用高速网络接口等方式来优化网络性能。
  2. WAL 日志管理: 合理配置 WAL 日志的归档和清理策略。如果 WAL 日志归档目录空间不足,可能会导致主服务器停止工作。可以定期清理过期的 WAL 日志,同时确保备用服务器能够及时应用 WAL 日志,避免日志积压。
  3. 参数调优: 调整 PostgreSQL 的相关参数,如 shared_bufferswork_mem 等。shared_buffers 用于设置共享内存缓冲区的大小,适当增大该值可以提高数据库的读写性能。但需要注意不要设置过大,以免影响系统的整体性能。

5.2 监控

  1. 使用 pg_stat_activity 视图pg_stat_activity 视图可以查看当前数据库中正在执行的活动查询。在主备服务器上都可以使用以下查询来查看:
    SELECT * FROM pg_stat_activity;
    
    通过该视图,可以了解查询的执行状态、执行时间等信息,有助于发现性能瓶颈。
  2. 监控 WAL 复制状态: 可以使用 pg_stat_replication 视图来监控主服务器上的 WAL 复制状态。在主服务器上执行以下查询:
    SELECT * FROM pg_stat_replication;
    
    该视图会显示当前连接的备用服务器信息,包括 WAL 发送位置、备用服务器接收位置等,通过这些信息可以判断复制是否正常进行。
  3. 使用外部监控工具: 可以使用如 Prometheus + Grafana 等外部监控工具来对 PostgreSQL 进行全面监控。通过配置 Prometheus 的 PostgreSQL 导出器(exporter),可以收集 PostgreSQL 的各种指标,如 CPU 使用率、内存使用率、查询执行时间等。然后,使用 Grafana 进行可视化展示,方便管理员实时了解数据库的运行状态。

6. 常见问题及解决方法

6.1 复制延迟问题

  1. 原因分析
    • 网络问题:主备服务器之间网络不稳定或带宽不足,导致 WAL 日志传输延迟。
    • 备用服务器性能问题:备用服务器的 CPU、内存或磁盘 I/O 性能不足,无法及时应用 WAL 日志。
    • WAL 日志积压:主服务器产生 WAL 日志的速度过快,备用服务器来不及应用。
  2. 解决方法
    • 检查网络连接,确保主备服务器之间网络稳定,增加网络带宽。
    • 优化备用服务器性能,如增加 CPU、内存资源,优化磁盘 I/O 配置。
    • 调整主服务器的事务处理速度,避免 WAL 日志过快产生。可以通过调整应用程序的事务大小、优化查询等方式实现。

6.2 备用服务器无法启动问题

  1. 原因分析
    • 配置错误:如 recovery.confpostgresql.auto.conf 文件配置错误,导致备用服务器无法正确连接主服务器或应用 WAL 日志。
    • 数据损坏:在数据复制过程中,可能由于磁盘故障等原因导致备用服务器的数据损坏。
  2. 解决方法
    • 仔细检查配置文件,确保连接主服务器的信息、WAL 日志恢复命令等配置正确。
    • 如果怀疑数据损坏,可以重新使用 pg_basebackup 工具从主服务器复制基础数据,然后重新启动备用服务器。

6.3 故障切换后应用程序连接问题

  1. 原因分析: 故障切换后,应用程序的连接字符串可能仍然指向旧的主服务器,导致无法连接数据库。
  2. 解决方法: 及时更新应用程序的连接字符串,使其指向新的主服务器。可以通过配置中心等方式集中管理应用程序的连接配置,以便在故障切换后快速更新。

通过深入理解和合理应用 PostgreSQL 的 Hot Standby 模式,结合性能优化、监控以及常见问题的解决方法,可以构建一个高可用、高性能的 PostgreSQL 数据库系统,满足各种业务场景的需求。无论是对于企业级应用还是互联网应用,Hot Standby 模式都为数据库的可靠性和扩展性提供了强大的支持。在实际应用中,需要根据具体的业务需求和硬件环境,对该模式进行细致的配置和优化,以达到最佳的效果。同时,持续关注 PostgreSQL 的版本更新和新技术发展,不断提升数据库系统的性能和稳定性。