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

PostgreSQL逻辑复制与物理复制的性能对比

2022-06-048.0k 阅读

一、PostgreSQL 复制概述

在数据库管理系统中,复制是一种关键技术,它允许将数据从一个数据库实例(源)复制到一个或多个其他数据库实例(目标)。PostgreSQL 提供了两种主要的复制方式:逻辑复制和物理复制。这两种复制方法各有其特点,在不同的应用场景下发挥着重要作用。理解它们的性能差异对于优化数据库架构和确保数据的高可用性、灾难恢复能力至关重要。

1.1 逻辑复制原理

逻辑复制基于数据库的逻辑层面进行数据传输。它通过捕捉数据库的逻辑更改,例如 SQL 语句(INSERT、UPDATE、DELETE),然后将这些更改应用到目标数据库。逻辑复制使用发布 - 订阅模型,源数据库作为发布者,将数据更改发布出去,而目标数据库作为订阅者,接收并应用这些更改。

在逻辑复制中,PostgreSQL 使用逻辑解码功能来解析 WAL(Write - Ahead Log)日志,将其转换为逻辑更改集。这些更改集以一种与具体存储格式无关的方式表示,使得它们可以在不同版本的 PostgreSQL 之间以及不同的操作系统平台之间进行传输。

1.2 物理复制原理

物理复制则是在物理层面进行数据复制。它基于 WAL 日志的物理内容,将源数据库的 WAL 日志连续地发送到目标数据库。目标数据库通过重放这些 WAL 日志来保持与源数据库的数据一致性。物理复制使用流复制协议,源数据库不断地将新生成的 WAL 日志发送给目标数据库,目标数据库则实时地应用这些日志。

物理复制在底层依赖于 PostgreSQL 的 WAL 机制,WAL 日志记录了数据库的每一个物理更改,包括页面的修改、事务的提交等。通过重放这些物理日志,目标数据库可以精确地复制源数据库的状态,包括数据文件、索引和其他物理结构。

二、性能对比分析维度

2.1 复制延迟

复制延迟是衡量复制性能的一个重要指标,它表示源数据库发生更改到目标数据库应用该更改之间的时间差。

在逻辑复制中,由于需要对 WAL 日志进行逻辑解码,将物理日志转换为逻辑更改集,然后再将这些更改集应用到目标数据库,这个过程涉及到额外的处理步骤,因此逻辑复制通常会引入相对较高的延迟。特别是在高并发写入的情况下,逻辑解码和应用更改的过程可能会成为瓶颈,导致延迟增加。

而物理复制直接基于 WAL 日志的物理内容进行传输和应用,跳过了逻辑解码这一复杂步骤,因此在一般情况下,物理复制的延迟相对较低。它能够更快速地将源数据库的更改同步到目标数据库,尤其适用于对数据实时性要求较高的场景,如金融交易系统的灾备。

2.2 带宽消耗

带宽消耗也是评估复制性能的关键因素之一,特别是在跨数据中心或广域网环境下进行复制时。

逻辑复制传输的是逻辑更改集,这些更改集通常以一种紧凑的格式表示,相对物理 WAL 日志来说,数据量可能较小。然而,逻辑复制需要额外的元数据来描述更改的逻辑含义,例如表结构信息、事务上下文等,这些元数据可能会增加一定的带宽开销。此外,逻辑复制在处理复杂数据类型和操作时,生成的逻辑更改集可能会变得较大。

物理复制传输的是 WAL 日志的物理内容,WAL 日志记录了数据库的每一个物理更改,包括页面的完整副本。因此,物理复制的带宽消耗通常较大,尤其是在源数据库有大量数据修改的情况下。但在某些情况下,如果源数据库的更改相对简单且集中在少数页面上,物理复制可能由于不需要传输额外的逻辑元数据而在带宽消耗上表现较好。

2.3 资源利用率

资源利用率涉及到源数据库、目标数据库以及网络资源的使用情况。

在源数据库端,逻辑复制需要运行逻辑解码进程,该进程会占用一定的 CPU 和内存资源来解析 WAL 日志。同时,为了生成逻辑更改集,还可能需要额外的 I/O 操作来读取相关的数据库页面。物理复制在源数据库端的开销相对较小,主要是将 WAL 日志发送到目标数据库,不需要进行复杂的逻辑解码,因此对源数据库的 CPU 和内存资源占用相对较低。

在目标数据库端,逻辑复制需要应用逻辑更改集,这涉及到解析逻辑操作、检查数据一致性等复杂过程,对 CPU 和内存的要求较高。物理复制则相对简单,只需重放 WAL 日志,对目标数据库的资源消耗相对较低。

网络资源方面,如前文所述,逻辑复制带宽消耗可能相对较小,但由于其逻辑更改集的传输可能需要更复杂的协议和机制,网络连接的稳定性和延迟对其性能影响较大。物理复制带宽消耗大,对网络带宽要求高,但由于其基于简单的 WAL 日志流传输,网络协议相对简单,在高带宽且稳定的网络环境下性能更好。

2.4 对源库性能影响

复制过程对源数据库的性能影响也不容忽视。

逻辑复制由于需要逻辑解码 WAL 日志,生成逻辑更改集,这个过程会增加源数据库的 CPU 和 I/O 负载。特别是在高并发写入的场景下,逻辑解码进程可能会与正常的数据库操作竞争资源,导致源数据库性能下降。

物理复制对源数据库的性能影响相对较小。它主要是将 WAL 日志发送出去,对源数据库的正常事务处理干扰较少。在源数据库的 WAL 生成速度与网络传输速度匹配的情况下,物理复制对源数据库的性能几乎没有额外的负面影响。

三、性能测试环境搭建

3.1 硬件环境

为了准确对比逻辑复制和物理复制的性能,我们搭建了以下硬件环境:

  • 源数据库服务器
    • CPU:Intel Xeon E5 - 2620 v4 @ 2.10GHz,8 核
    • 内存:32GB
    • 存储:512GB SSD
    • 操作系统:CentOS 7.9
  • 目标数据库服务器
    • CPU:Intel Xeon E5 - 2620 v4 @ 2.10GHz,8 核
    • 内存:32GB
    • 存储:512GB SSD
    • 操作系统:CentOS 7.9
  • 网络环境:源数据库服务器和目标数据库服务器通过 10Gbps 以太网连接,确保网络带宽充足且稳定。

3.2 软件环境

在硬件环境基础上,安装如下软件:

  • PostgreSQL 版本:13.4
  • 数据库初始化:在源数据库和目标数据库上分别初始化一个相同结构的测试数据库。数据库包含多个表,其中一个表 test_table 结构如下:
CREATE TABLE test_table (
    id SERIAL PRIMARY KEY,
    data TEXT,
    timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

并插入 100 万条测试数据,数据插入脚本如下:

BEGIN;
FOR i IN 1..1000000 LOOP
    INSERT INTO test_table (data) VALUES ('test data' || i);
END LOOP;
COMMIT;

四、逻辑复制性能测试

4.1 配置逻辑复制

  1. 源数据库配置
    • 编辑 postgresql.conf 文件,确保以下参数配置:
wal_level = logical
max_replication_slots = 10
max_wal_senders = 10
  • 重启 PostgreSQL 服务使配置生效。
  • 创建发布:
CREATE PUBLICATION my_publication FOR ALL TABLES;
  1. 目标数据库配置
    • 编辑 postgresql.conf 文件,确保 wal_level 参数为 logical
    • 重启 PostgreSQL 服务。
    • 创建订阅:
CREATE SUBSCRIPTION my_subscription
CONNECTION 'host=源数据库服务器IP port=5432 user=postgres password=password dbname=测试数据库名'
PUBLICATION my_publication;

4.2 测试逻辑复制延迟

  1. 测试方法:在源数据库执行一个事务,向 test_table 插入 1000 条记录,记录插入开始时间。然后在目标数据库查询这些记录是否存在,并记录查询到这些记录的时间。计算两者的时间差作为复制延迟。
  2. 测试脚本
    • 源数据库插入脚本(insert_data.sh)
#!/bin/bash
psql -U postgres -d 测试数据库名 -c "BEGIN; INSERT INTO test_table (data) SELECT 'test data' || generate_series(1,1000); COMMIT;"
start_time=$(date +%s%N)
echo $start_time > start_time.txt
  • 目标数据库查询脚本(check_data.sh)
#!/bin/bash
while true
do
    count=$(psql -U postgres -d 测试数据库名 -c "SELECT COUNT(*) FROM test_table WHERE data LIKE 'test data%' AND data NOT IN (SELECT data FROM test_table WHERE data LIKE 'test data%' LIMIT 1000 OFFSET 0);" -t -A)
    if [ $count -eq 0 ]; then
        end_time=$(date +%s%N)
        echo $end_time > end_time.txt
        break
    fi
    sleep 1
done
  1. 测试结果:经过多次测试,平均复制延迟约为 500 毫秒。在高并发写入情况下,延迟明显增加,最高可达 2 秒。

4.3 测试逻辑复制带宽消耗

  1. 测试方法:使用 iftop 工具监控源数据库服务器到目标数据库服务器的网络带宽。在源数据库执行一系列数据更改操作,包括插入、更新和删除,记录操作期间的平均带宽消耗。
  2. 测试脚本
    • 数据更改脚本(change_data.sh)
#!/bin/bash
psql -U postgres -d 测试数据库名 -c "BEGIN; INSERT INTO test_table (data) SELECT 'test data' || generate_series(1,1000); UPDATE test_table SET data = 'updated data' WHERE id <= 1000; DELETE FROM test_table WHERE id <= 500; COMMIT;"
  1. 测试结果:在执行数据更改操作期间,平均带宽消耗约为 1Mbps。随着数据更改量的增加,带宽消耗也相应增加,但增长幅度相对较缓。

4.4 测试逻辑复制对源库性能影响

  1. 测试方法:在源数据库执行一系列复杂查询,同时进行逻辑复制数据更改操作。使用 pg_stat_statements 扩展来统计查询的执行时间和资源消耗。
  2. 配置 pg_stat_statements
    • 编辑 postgresql.conf 文件,添加 shared_preload_libraries = 'pg_stat_statements'
    • 重启 PostgreSQL 服务。
    • 执行 CREATE EXTENSION pg_stat_statements;
  3. 测试脚本
    • 复杂查询脚本(query_data.sh)
#!/bin/bash
psql -U postgres -d 测试数据库名 -c "SELECT COUNT(*), AVG(LENGTH(data)) FROM test_table WHERE timestamp > current_timestamp - INTERVAL '1 day';"
  • 数据更改脚本(同 4.3 中的 change_data.sh)
#!/bin/bash
psql -U postgres -d 测试数据库名 -c "BEGIN; INSERT INTO test_table (data) SELECT 'test data' || generate_series(1,1000); UPDATE test_table SET data = 'updated data' WHERE id <= 1000; DELETE FROM test_table WHERE id <= 500; COMMIT;"
  1. 测试结果:在进行逻辑复制数据更改操作时,复杂查询的平均执行时间增加了约 30%,CPU 使用率也有明显上升,从平均 30% 增加到 50%。

五、物理复制性能测试

5.1 配置物理复制

  1. 源数据库配置
    • 编辑 postgresql.conf 文件,确保以下参数配置:
wal_level = replica
max_replication_slots = 10
max_wal_senders = 10
  • 重启 PostgreSQL 服务。
  • 配置流复制认证,在 pg_hba.conf 文件中添加:
host    replication     postgres    目标数据库服务器IP/32     md5
  1. 目标数据库配置
    • 停止目标数据库服务。
    • 清空目标数据库数据目录(通常为 /var/lib/pgsql/data)。
    • 使用 pg_basebackup 工具从源数据库创建基础备份:
pg_basebackup -h 源数据库服务器IP -U postgres -D /var/lib/pgsql/data -P -X stream
  • 编辑 recovery.conf 文件(PostgreSQL 12 及以上版本为 postgresql.auto.conf),添加以下内容:
standby_mode = 'on'
primary_conninfo = 'host=源数据库服务器IP port=5432 user=postgres password=password'
  • 启动目标数据库服务。

5.2 测试物理复制延迟

  1. 测试方法:与逻辑复制延迟测试方法类似,在源数据库执行一个事务,向 test_table 插入 1000 条记录,记录插入开始时间。然后在目标数据库查询这些记录是否存在,并记录查询到这些记录的时间。计算两者的时间差作为复制延迟。
  2. 测试脚本
    • 源数据库插入脚本(同逻辑复制中的 insert_data.sh)
#!/bin/bash
psql -U postgres -d 测试数据库名 -c "BEGIN; INSERT INTO test_table (data) SELECT 'test data' || generate_series(1,1000); COMMIT;"
start_time=$(date +%s%N)
echo $start_time > start_time.txt
  • 目标数据库查询脚本(同逻辑复制中的 check_data.sh)
#!/bin/bash
while true
do
    count=$(psql -U postgres -d 测试数据库名 -c "SELECT COUNT(*) FROM test_table WHERE data LIKE 'test data%' AND data NOT IN (SELECT data FROM test_table WHERE data LIKE 'test data%' LIMIT 1000 OFFSET 0);" -t -A)
    if [ $count -eq 0 ]; then
        end_time=$(date +%s%N)
        echo $end_time > end_time.txt
        break
    fi
    sleep 1
done
  1. 测试结果:经过多次测试,平均复制延迟约为 100 毫秒。在高并发写入情况下,延迟增加相对较小,最高约为 300 毫秒。

5.3 测试物理复制带宽消耗

  1. 测试方法:与逻辑复制带宽消耗测试方法相同,使用 iftop 工具监控源数据库服务器到目标数据库服务器的网络带宽。在源数据库执行一系列数据更改操作,包括插入、更新和删除,记录操作期间的平均带宽消耗。
  2. 测试脚本
    • 数据更改脚本(同逻辑复制中的 change_data.sh)
#!/bin/bash
psql -U postgres -d 测试数据库名 -c "BEGIN; INSERT INTO test_table (data) SELECT 'test data' || generate_series(1,1000); UPDATE test_table SET data = 'updated data' WHERE id <= 1000; DELETE FROM test_table WHERE id <= 500; COMMIT;"
  1. 测试结果:在执行数据更改操作期间,平均带宽消耗约为 5Mbps。随着数据更改量的增加,带宽消耗增长明显,与数据更改量几乎成正比。

5.4 测试物理复制对源库性能影响

  1. 测试方法:与逻辑复制对源库性能影响测试方法相同,在源数据库执行一系列复杂查询,同时进行物理复制数据更改操作。使用 pg_stat_statements 扩展来统计查询的执行时间和资源消耗。
  2. 配置 pg_stat_statements:(同逻辑复制中的配置)
    • 编辑 postgresql.conf 文件,添加 shared_preload_libraries = 'pg_stat_statements'
    • 重启 PostgreSQL 服务。
    • 执行 CREATE EXTENSION pg_stat_statements;
  3. 测试脚本
    • 复杂查询脚本(同逻辑复制中的 query_data.sh)
#!/bin/bash
psql -U postgres -d 测试数据库名 -c "SELECT COUNT(*), AVG(LENGTH(data)) FROM test_table WHERE timestamp > current_timestamp - INTERVAL '1 day';"
  • 数据更改脚本(同逻辑复制中的 change_data.sh)
#!/bin/bash
psql -U postgres -d 测试数据库名 -c "BEGIN; INSERT INTO test_table (data) SELECT 'test data' || generate_series(1,1000); UPDATE test_table SET data = 'updated data' WHERE id <= 1000; DELETE FROM test_table WHERE id <= 500; COMMIT;"
  1. 测试结果:在进行物理复制数据更改操作时,复杂查询的平均执行时间增加了约 10%,CPU 使用率略有上升,从平均 30% 增加到 35%。

六、性能对比总结

通过以上详细的性能测试,我们可以清晰地看到逻辑复制和物理复制在各项性能指标上的差异。

在复制延迟方面,物理复制明显优于逻辑复制。物理复制基于 WAL 日志的直接重放,能够快速将源数据库的更改同步到目标数据库,尤其在高并发写入场景下,延迟增加相对较小。而逻辑复制由于需要逻辑解码和应用逻辑更改集等复杂步骤,延迟相对较高,且在高并发情况下延迟增加明显。

带宽消耗上,逻辑复制相对较小,其传输的逻辑更改集相对紧凑,虽然需要额外的元数据,但在一般情况下带宽需求较低。物理复制由于传输的是 WAL 日志的物理内容,带宽消耗较大,且随着数据更改量的增加而显著增长。

资源利用率方面,逻辑复制在源数据库和目标数据库端都需要进行相对复杂的处理,对 CPU 和内存资源的占用较高。物理复制在源数据库端开销较小,在目标数据库端也只需重放 WAL 日志,资源消耗相对较低。

对源库性能影响上,逻辑复制由于逻辑解码等操作,对源数据库的 CPU 和 I/O 负载影响较大,导致源数据库性能下降明显。物理复制对源数据库的性能影响相对较小,对源数据库正常事务处理的干扰较少。

在实际应用中,应根据具体的业务需求和环境来选择合适的复制方式。如果对数据实时性要求极高,如金融交易系统的灾备,物理复制是更好的选择。而如果需要在不同版本的 PostgreSQL 之间进行复制,或者需要更细粒度的复制控制,逻辑复制则更具优势。同时,考虑到网络带宽、资源利用率等因素,综合评估后做出决策,以确保数据库系统的高效运行和数据的可靠复制。