联系管理员

开通文章发布权限

扫码 添加微信
微信图片
电话:15897897836 QQ:2106973531

PostgreSQL的物理复制

物理复制只能针对实例级进行复制,就是复制单位为一个数据库实例,无法精确到数据库中某些表。物理复制分为同步复制和异步复制,异步复制就是主库上提交事务时必须等待备库接受WAL日志并写入到WAL文件中后才能返回成功,异步复制相反。

1、背景

在9.0之前,通常依赖第三方工具解决方案(如 Slony-I、Londiste、pgpool-II 和 Bucardo)来实现数据库复制和高可用性。从9.0开始,pg就开始支持物理复制,就是从实例级复制出一个与主库一模一样的从库(也叫备库)。有基于文件的拷贝基于TCP流的数据传输(物理流复制)两种方式。两种方式都是传输 wal 数据,前者是等待生成一个完整的wal文件后,才会触发传输,后者是实时传输的。可以看出来基于文件方式的延迟会比较高,而且wal文件有可能没来得及传输就被损坏了,造成了这块的数据丢失。基于TCP流的方式延迟非常低,是现在最常见的方式。

  • 基于文件的拷贝就是将实例数据文件拷贝到备库上,可以用pg_basebackup来实现,拷贝粒度为wal文件,所以数据会出现不一致的情况。

  • 物理流复制就是在基于文件的拷贝的基础上,将主库的WAL Record 复制到从库,从库重放WAL Record来进行数据的恢复,拷贝粒度为wal record,可以极大保证数据的一致性。

物理复制只能针对实例级进行复制,就是复制单位为一个数据库实例,无法精确到数据库中某些表。物理复制分为同步复制异步复制,异步复制就是主库上提交事务时必须等待备库接受WAL日志并写入到WAL文件中后才能返回成功,异步复制相反。

2、怎么使用物理复制

实现物理复制的详细步骤:

配置主服务器

首先,需要在主服务器上启用物理复制。编辑 postgresql.conf 文件,确保以下参数已正确配置:

wal_level = replica  (wal日志的输出级别:minimal,replica,logical)

archive_mode = on (开启归档)

archive_command = '/bin/**' (wal日志归档命令)

max_wal_senders = 10 (主库上最大的wal发送进程数

wal_keep_segments = 512 (保留的最小wal日志的文件数)

hot_standby = on (数据库恢复过程中是否可读)

然后,编辑 pg_hba.conf 文件,添加允许从服务器连接的条目:

#允许来自备用服务器的复制连接
host replication replicator *.*.*.*/* md5

修改后需要重新加载配置文件

使用 pg_basebackup 创建基础备份

在从服务器上,使用 pg_basebackup 从主服务器创建基础备份:

pg_basebackup -h primary_host -D /path/to/standby/data -U replicator -W -P --wal-method=stream
#参数解释
-h primary_host:主服务器的主机名或 IP 地址。
-D /path/to/standby/data:从服务器上数据目录的路径。
-U replicator:用于复制的用户。
-W:提示输入密码。
-P:显示进度。
-wal-method=stream:使用流复制方法获取 WAL 日志。

配置从服务器

在从服务器的数据目录中,创建一个 recovery.conf 文件(在 PostgreSQL 12 及更高版本中,使用 standby.signal 文件代替):

standby_mode = 'on'
primary_conninfo = 'host=primary_host port=5432 user=replicator password=yourpassword'
trigger_file = '/tmp/trigger'

对于 PostgreSQL 12 及更高版本,创建一个 standby.signal 文件,并在 postgresql.conf 中添加以下配置:

primary_conninfo = 'host=primary_host port=5432 user=replicator password=yourpassword'

启动从服务器

pg_ctl -D /path/to/standby/data start

验证复制

在从服务器上,检查复制状态:

SELECT * FROM pg_stat_wal_receiver;

在主服务器上,检查复制状态:

SELECT * FROM pg_stat_replication;

3、同步流复制和异步流复制

同步流复制:确保事务在主服务器和至少一个从服务器上都被写入 WAL 日志后才返回给客户端,提供更高的数据一致性,但会增加事务提交的延迟,对主服务器性能有一定影响。 异步流复制:主服务器提交事务后立即返回给客户端,不等待从服务器的确认,性能较高,但存在复制延迟,可能导致从服务器数据滞后于主服务器,在主服务器故障时可能会丢失一些数据。

postgresql.conf 配置文件中有两个参数 synchronous_commitsynchronous_standby_names

synchronous_commit 意思是当前数据库提交事务时是否需要等待WAL日志写入磁盘后才向客户端返回成功,该参数的值有五种:
on、off、local、remote_apply、remote_write

单机环境:

  • on:本地wal先写入wal缓冲区,再写入wal文件中,也就是说必须等到wal写入到wal文件中后才能向客户端返回成功。

  • off:wal日志写入到wal 缓存中,不需要等待写到wal文件中就可以向客户端返回成功。

  • local:与on类似。

主备场景:

  • remote_write:主机事务提交时,需要等待备机接受的wal日志写到wal缓冲区之后才能提交。

  • remote_apply:主机事务提交时,需要等待备机接受的wal日志写到wal缓冲区,然后写入到备机的wal文件中,并且需要对wal日志执行之后才能提交。

另外一个参数synchronous_standby_names,这个参数是用来开启同步复制的,异步复制不需要开,参数值就是备机的application_name,这个在备库的recovery.conf中的primary_conninfo中设置。 当synchronous_standby_names设置了参数时,那就指定当前复制方式为同步复制,synchronous_commit参数决定了事务提交时主服务器需要等待的确认级别。不同值对性能的影响:off (async) > on (async) > remote_write (sync) > on|local (sync) > remote_apply (sync) 当synchronous_standby_names没有设置参数,默认使用异步复制模式。因为没有指定同步备用服务器,所以synchronous_commit:on、remote_apply、remote_write和local的设置都提供相同级别的同步级别:事务提交只等待本地刷新到磁盘。

4、物理流复制的工作过程

图片#B #S #R #60% #auto

  • 启动主服务器和备服务器。

  • 备用服务器开始启动过程。

  • 备用服务器启动walreceiver进程。

  • walreceiver向主服务器发送连接请求,如果主服务器没有运行,walreceiver会定期发送这些请求。

  • 当主服务器收到连接请求时,启动一个walsender进程,walsender和walreceiver之间建立TCP连接。

  • walreceiver发送standby数据库集群最新的LSN(Log Sequence Number),在信息技术领域中,这被称为握手。

  • 如果备用数据库的最新 LSN 小于主数据库的最新 LSN(备用数据库的 LSN<<主服务器的 LSN 上发送 WAL 数据 (WAL 数据来自主服务器的 LSN),walsender 将前一个 LSN 上的 WAL 数据发送到后一个 LSN。这些 WAL 数据由存储在主服务器的 pg_wal 子目录中的 WAL 段提供 (在 9.6 或更早的版本中,pg_xlog)。然后,备用服务器重放收到的 WAL 数据。在此阶段,备用服务器会追上主服务器,因此称为追赶(catch-up ) 。

  • 流复制开始工作。

备库或者连接了wal接收器的应用程序的复制进度状态有四种:starup、catch-up、stream、backup。状态由wal发送进程维护。可以通过pg_stat_replication来进行查询当前备库的wal接收进程的复制状态。

5、物理流复制的进程架构

物理流复制的核心部分由walsender,walreceiver和startup三个进程组成。 walsender进程是用来发送WAL日志记录的,执行顺序如下:

PostgresMain()->exec_replication_command()->StartReplication()->WalSndLoop()->XLogSendPhysical()

walreceiver进程是用来接收WAL日志记录的,执行顺序如下:

sigusr1_handler()->StartWalReceiver()->AuxiliaryProcessMain()->WalReceiverMain()->walrcv_receive()

startup进程是用来apply日志的,执行顺序如下:

PostmasterMain()->StartupDataBase()->AuxiliaryProcessMain()->StartupProcessMain()->StartupXLOG()

总体框架图:
图片#B #S #R #60% #auto

walsender和walreceiver交互主要分为以下几个步骤:

 

  1. walreceiver启动后通过recovery.conf文件中的primary_conninfo参数信息连向主库,主库通过连接参数replication=true启动walsender进程;

  2. walreceiver执行identify_system命令,获取主库systemid/timeline/xlogpos等信息,执行TIMELINE_HISTORY命令拉取history文件;

每个 postgresql 数据库在第一次初始化时,都会分配一个唯一的systemid。当配置主从复制时,从库需要将主库的数据备份过来,这时候也会拷贝systemid,所以从库和主库的systemid是一样的。主库处理IDENTIFY_SYSTEM请求时,会返回自身的systemid。从库通过匹配它,可以判断出来主库的有效性。比如当用户在配置时错写了主库的地址,就可以检查出来。

  1. 执行wal_startstreaming开始启动流复制,通过walrcv_receive获取WAL日志,期间也会回应主库发过来的心跳信息(接收位点、flush位点、apply位点),向主库发送feedback信息(最老的事务id),避免vacuum删掉备库正在使用的记录;

从库会定期向主库汇报自身的同步进度,比如已经刷新wal数据的位置,已经应用wal数据的位置等,这样主库就可以了解到每个从库的情况。当主库超过指定时间间隔,没有收到来自从库的消息,会发送Keepalive消息,强制要求从库汇报自身进度。

  1. 执行walrcv_endstreaming结束流复制,等待startup进程更新receiveStart和receiveStartTLI,一旦更新,进入步骤2。
    图片#B #S #R #60% #auto

startup进程进入standby模式和apply日志主要过程:

  1. 读取pg_control文件,找到redo位点;读取recovery.conf,如果配置standby_mode=on则进入standby模式。

  2. 如果是Hot Standby需要初始化clog、subtrans、事务环境等。初始化redo资源管理器,比如Heap、Heap2、Database、XLOG等。

  3. 读取WAL record,如果record不存在需要调用XLogPageRead->WaitForWALToBecomeAvailable->RequestXLogStreaming唤醒walreceiver从walsender获取WAL record。

  4. 对读取的WAL record进行redo,通过record->xl_rmid信息,调用相应的redo资源管理器进行redo操作。比如heap_redo的XLOG_HEAP_INSERT操作,就是通过record的信息在buffer page中增加一个record。还有部分redo操作(vacuum产生的record)需要检查在Hot Standby模式下的查询冲突,比如某些tuples需要remove,而存在正在执行的query可能读到这些tuples,这样就会破坏事务隔离级别。通过函数ResolveRecoveryConflictWithSnapshot检测冲突,如果发生冲突,那么就把这个query所在的进程kill掉。

  5. 检查一致性,如果一致了,Hot Standby模式可以接受用户只读查询;更新共享内存中XLogCtlData的apply位点和时间线;如果恢复到时间点,时间线或者事务id需要检查是否恢复到当前目标;

  6. 回到步骤3,读取next WAL record。
    图片#B #S #R #60% #auto

6、物理复制实验

前期准备

在两台腾讯云CVM上搭建PG实例,相关信息如下:

主机IP*地址*OSPG*版本*
主节点43.136.168.127CentOS 7.911.4
备节点162.14.103.186CentOS 7.911.4

安装步骤:https://blog.csdn.net/sinat_42401704/article/details/127609394

主节点和备节点相关配置

1、新建归档目录

mkdir -p  /data/postgresql/archive/

2、修改主库和备库配置文件postgresql.conf

listen_address = '*' #按需设置,本次测试配置为所有主机均可以访问,生产环境可以按需配置网段或IP等
wal_level = replica  #设置流复制模式至少设置为replica
archive_mode = on   #本次启用归档
archive_command = 'cp %p /data/postgresql/archive/%f '  #WAL日志归档命令,生产环境可以将归档拷贝到对应目录或其他机器上,本次测试配置为归档到本机的另一个目录下
max_wal_senders= 10   #最大WAL发送进程数,此数量需大于等于从库个数且比max_connections小。
wal_keep_segments=1024  #pg_wal目录下保留WAL日志的个数,每个WAL文件默认16M,为保障从库能在应用归档落后时依旧能追上主库,此值建议设置较大一点。
hot_standby = on  #此参数控制在恢复归档期间是否支持只读操作,设置为ON后从库为只读模式。

这两个参数只需要在主节点上进行修改

synchronous_standby_names = 'cvm_wuchu_test2' //填备节点的application_name
synchronous_commit = on //同步等级

3、创建一个测试用户

create user repl  REPLICATION  LOGIN ENCRYPTED  PASSWORD 'repl123';

4、修改配置文件pg_hba.conf,在末尾添加下面内容

# replication privilege.
host    replication     repl             43.136.168.127/24            md5
host    replication     repl             162.14.103.186/24            md5

在备节点上执行

pg_basebackup -h 43.136.168.127 -U repl -p 5432 -F p   -X s  -v -P -R -D /data/postgresql/data/ -l postgres_2024

出现下面结果表示备份成生成:
图片#B #S #R #60% #auto
此时发现/data/postgresql/data中出现以下文件:
图片#B #S #R #60% #auto
修改recovery.conf文件

standby_mode = 'on'
recovery_target_timeline = 'latest'
primary_conninfo = 'user=repl password=repl123 host=43.136.168.127 port=5432 sslmode=disable sslcompression=0 target_session_attrs=any application_name=cvm_wuchu_test2'

重启备机的pg服务

pg_ctl restart

在主节点上执行

新建表,并插入数据
图片#B #S #R #60% #auto
执行下面命令

select usename,application_name,client_addr,sync_state from pg_stat_replication;

显示当前备节点的同步状态
图片#B #S #R #60% #auto

在备节点上查看

备节点数据已经跟主节点同步
图片#B #S #R #60% #auto
图片#B #S #R #60% #auto

异步复制

上述实验设置主备之间是同步复制,修改下述参数进行异步复制 修改主节点的postgresql.conf文件:

synchronous_standby_names = ''// 为空
synchronous_commit = off //完全异步

在主机上执行命令发现备机的复制状态为async,已经变为异步复制模式 :
图片#B #S #R #60% #auto

相关文章

从安装PostgreSQL开始
通过以下步骤,你可以在 CentOS 7 上成功安装和配置 PostgreSQL 14。首先,设置 RPM 仓库并安装 PostgreSQL 14 服务器。然后,创建自定义数据存储目录并初始化数据库。接下来,修改启动脚本以使用自定义数据存储目录,并设置 PostgreSQL 监听所有 IP 地址。为了增强安全性,配置密码认证并修改 postgres 超级用户密码。最后,确保所有配置生效,重启 PostgreSQL 服务。通过这些步骤,你将拥有一个配置良好且安全的 PostgreSQL 数据库环境。如果在过程中遇到任何问题,请参考官方文档或寻求专业支持。
checkpoint是什么东西?一个位置?还是一个操作?
checkpoint是一个操作,执行这个操作的开始时刻,会记录当前开始时刻的 WAL 位置作为重做点,这个位置会被保存在文件中。 然后将该重做点之前所有 shared buffer 中的脏页均被刷入到存储。checkpoint又名检查点,一般checkpoint会将某个时间点之前的脏数据全部刷新到磁盘,以实现数据的一致性与完整性。
PostgreSQL 内参:深入解析运行原理【快照篇】
来源于灿哥的:《PostgreSQL 内参:深入解析运行原理》,非常好的一本书。
PG存在的级联删除(ON DELETE CASCADE)
在 PostgreSQL 中,如果你有两张表:用户表(users)和订单表(orders),并且用户表的主键是订单表的外键,那么你可以通过以下步骤来进行实验,删除订单表中的一条数据,然后删除用户表中的一条数据。

评论

快捷导航

把好文章收藏到微信

打开微信,扫码查看

关闭

还没有账号?立即注册