前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >进阶数据库系列(十五):PostgreSQL 主从同步原理与实践

进阶数据库系列(十五):PostgreSQL 主从同步原理与实践

作者头像
民工哥
发布2023-08-22 13:57:16
3.8K0
发布2023-08-22 13:57:16
举报
文章被收录于专栏:民工哥技术之路

在正式介绍 PostgreSQL 主从同步复制 之前,我们先了解一下 PostgreSQL 的预写日志机制(WAL)。

PostgreSQL 预写日志机制(WAL)

关于持久性

持久性是指,事务提交后,对系统的影响必须是永久的,即使系统意外宕机,也必须确保事务提交时的修改已真正永久写入到永久存储中。

最简单的实现方法,当然是在事务提交后立即刷新事务修改后的数据到磁盘。但是磁盘和内存之间的IO操作是最影响数据库系统影响时间的,一有事务提交就去刷新磁盘,会对数据库性能产生不好影响。

WAL机制的引入,即保证了事务持久性和数据完整性,又尽量地避免了频繁IO对性能的影响。

WAL过程分析

Write-Ahead Logging,前写日志。

在MVCC的部分中,我们已经分析了PostgreSQL的存储结构:元组-文件页-物理段-表; 以及写数据的步骤:先写到缓冲区Buffer-再刷新到磁盘Disk。

WAL机制实际是在这个写数据的过程中加入了对应的写wal log的过程,步骤一样是先到Buffer,再刷新到Disk。

  • Change发生时:
  • 先将变更后内容记入WAL Buffer
  • 再将更新后的数据写入Data Buffer
  • Commit发生时:
  • WAL Buffer刷新到Disk
  • Data Buffer写磁盘推迟
  • Checkpoint发生时:
  • 将所有Data Buffer刷新到磁盘
数据发生变动时

commit和checkpoint

WAL的好处

通过上面的分析,可以看到:

当宕机发生时,

  • Data Buffer的内容还没有全部写入到永久存储中,数据丢失;
  • 但是WAL Buffer的内容已写入磁盘,根据WAL日志的内容,可以恢复库丢失的内容。

在提交时,仅把WAL刷新到了磁盘,而不是Data刷新:

  • 从IO次数来说,WAL刷新是少量IO,Data刷新是大量IO,WAL刷新次数少得多;
  • 从IO花销来说,WAL刷新是连续IO,Data刷新是随机IO,WAL刷新花销小得多。

因此WAL机制在保证事务持久性和数据完整性的同时,成功地提升了系统性能。

主从复制

基于文件的日志传送

创建一个高可用性(HA)集群配置可采用连续归档,集群中主服务器工作在连续归档模式下,备服务器工作在连续恢复模式下(1台或多台可随时接管主服务器),备持续从主服务器读取WAL文件。

连续归档不需要对数据库表做任何改动,可有效降低管理开销,对主服务器的性能影响也相对较低。

直接从一个数据库服务器移动 WAL 记录到另一台服务器被称为日志传送,PostgreSQL 通过一次一文件(WAL段)的WAL记录传输实现了基于文件的日志传送。

  • 日志传送所需的带宽取根据主服务器的事务率而变化;
  • 日志传送是异步的,即WAL记录是在事务提交后才被传送,那么在一个窗口期内如果主服务器发生灾难性的失效则会导致数据丢失,还没有被传送的事务将会被丢失;
  • 数据丢失窗口可以通过使用参数archive_timeout进行限制,可以低至数秒,但同时会增加文件传送所需的带宽。
流复制

PostgreSQL 在9.x之后引入了主从的流复制机制,所谓流复制,就是备服务器通过tcp流从主服务器中同步相应的数据,主服务器在WAL记录产生时即将它们以流式传送给备服务器,而不必等到WAL文件被填充。

  • 默认情况下流复制是异步的,这种情况下主服务器上提交一个事务与该变化在备服务器上变得可见之间客观上存在短暂的延迟,但这种延迟相比基于文件的日志传送方式依然要小得多,在备服务器的能力满足负载的前提下延迟通常低于一秒;
  • 在流复制中,备服务器比使用基于文件的日志传送具有更小的数据丢失窗口,不需要采用archive_timeout来缩减数据丢失窗口;
  • 将一个备服务器从基于文件日志传送转变成基于流复制的步骤是:把recovery.conf文件中的primary_conninfo设置指向主服务器;设置主服务器配置文件的listen_addresses参数与认证文件即可。
  • PostgreSql 主从同步搭建
环境
操作系统:

CentOS Linux release 7.6.1810 (Core)

数据库版本:

PostgreSQL 12.4

IP:

192.168.100.170 主库 192.168.100.202 从库

实施步骤
主库创建账号同步数据
代码语言:javascript
复制
postgres=# CREATE ROLE replica login replication encrypted password 'replica';
CREATE ROLE
主库 pg_hba.conf 文件增加备库访问控制
代码语言:javascript
复制
host    replication     replica         192.168.100.202/32      trust
主库 postgresql.conf 文件添加主从同步参数
代码语言:javascript
复制
wal_level = hot_standby 
max_wal_senders = 8 
wal_keep_segments = 64 
wal_sender_timeout = 60s
max_connections = 100 
主库重启
代码语言:javascript
复制
[postgres@yuan data]$ pg_ctl restart -D $PGDATA -l $PGLOG
waiting for server to shut down.... done
server stopped
waiting for server to start.... done
server started
从库验证可访问主库

返回输入密码即表示可访问

代码语言:javascript
复制
[postgres@dj ~]$ psql -h 192.168.100.170 -U postgres
Password for user postgres:
停止从库
代码语言:javascript
复制
[postgres@dj ~]$ pg_ctl stop -D $PGDATA -l $PGLOG
waiting for server to shut down.... done
server stopped
清空从库数据文件
代码语言:javascript
复制
[postgres@dj data]$ rm -rf  /app/pgsql/data/*
[postgres@dj data]$ ll
total 0
拉取主库数据文件
代码语言:javascript
复制
[postgres@dj data]$ pg_basebackup -h 192.168.100.170 -D /app/pgsql/data -p 5432 -U replica -Fp -Xs -Pv -R --checkpoint=fast
Password:
pg_basebackup: initiating base backup, waiting for checkpoint to complete
pg_basebackup: checkpoint completed
pg_basebackup: write-ahead log start point: 0/D000028 on timeline 1
pg_basebackup: starting background WAL receiver
pg_basebackup: created temporary replication slot "pg_basebackup_17064"
50729/50729 kB (100%), 1/1 tablespace
pg_basebackup: write-ahead log end point: 0/D000100
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: syncing data to disk ...
pg_basebackup: base backup completed
[postgres@dj data]$ ll
total 128
-rw-------. 1 postgres postgres   224 Jul 12 03:43 backup_label
drwx------. 7 postgres postgres  4096 Jul 12 03:43 base
drwx------. 2 postgres postgres  4096 Jul 12 03:43 global
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_commit_ts
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_dynshmem
-rw-------. 1 postgres postgres  4886 Jul 12 03:43 pg_hba.conf
-rw-------. 1 postgres postgres  1636 Jul 12 03:43 pg_ident.conf
drwx------. 4 postgres postgres  4096 Jul 12 03:43 pg_logical
drwx------. 4 postgres postgres  4096 Jul 12 03:43 pg_multixact
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_notify
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_replslot
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_serial
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_snapshots
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_stat
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_stat_tmp
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_subtrans
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_tblspc
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_twophase
-rw-------. 1 postgres postgres     3 Jul 12 03:43 PG_VERSION
drwx------. 3 postgres postgres  4096 Jul 12 03:43 pg_wal
drwx------. 5 postgres postgres  4096 Jul 12 03:43 pg_walminer
drwx------. 2 postgres postgres  4096 Jul 12 03:43 pg_xact
-rw-------. 1 postgres postgres   267 Jul 12 03:43 postgresql.auto.conf
-rw-------. 1 postgres postgres 27115 Jul 12 03:43 postgresql.conf
-rw-------. 1 postgres postgres    30 Jul 12 03:43 postmaster.opts.bak
-rw-------. 1 postgres postgres     0 Jul 12 03:43 standby.signal
从库 postgresql.conf 文件修改主从同步参数

删掉主库添加的同步参数,添加如下参数:

代码语言:javascript
复制
primary_conninfo = 'host=192.168.100.170 port=5432 user=replica password=replica'
recovery_target_timeline = latest 
hot_standby = on
max_standby_streaming_delay = 30s
wal_receiver_status_interval = 10s
hot_standby_feedback = on
max_connections = 200  #大于主节点
max_worker_processes = 20
验证同步
启动从库
代码语言:javascript
复制
[postgres@dj data]$ pg_ctl start -D $PGDATA -l $PGLOG
waiting for server to start.... done
server started
主从同步验证
代码语言:javascript
复制
--主库查询
postgres=# select client_addr,usename,backend_start,application_name,sync_state,sync_priority FROM pg_stat_replication;
   client_addr   | usename |         backend_start         | application_name | sync_state | sync_priority
-----------------+---------+-------------------------------+------------------+------------+---------------
 192.168.100.202 | replica | 2021-08-24 18:03:32.089937+08 | walreceiver      | async      |             0


--测试创建删除数据库观察从库是否同步
create database test;
drop database test;

PostgreSql 主从流复制切换

概述

PostgreSql 数据库主库意外宕机,手动切换主备数据库流程。

代码语言:javascript
复制
环境:PostgreSql v12 + Centos 7
主库:192.168.100.170
备库:192.168.100.171
备库提升为主库

此时主库已意外宕机。

代码语言:javascript
复制
--提升备库为主库(171)
pg_ctl promote -D $PGDATA

--检查数据库状态,为 in production,说明备库已提升为主库(171)
pg_controldata | grep cluster

此时应用可以连接备库地址进行业务办理。

原主库恢复

排查原主库宕机原因,进行恢复。

原主库调整为备库

将恢复完成后的原主库调整为备库,有如下两种方式可选。

方式一:重新拉取主库数据进行同步

优势:不用提前修改数据库参数,步骤较简单。 劣势:只能全量重新同步,无法增量,数据库数据量大时不适用。

代码语言:javascript
复制
--停原主库(170)
pg_ctl stop

--备份原主库数据文件(170)
mv /data/pgdata /data/pgdata20220503

--拉取新主库数据(170)
pg_basebackup -h 192.168.100.171  -p 5432 -U postgres -D $PGDATA -Fp -P -Xs -R -v -l postgresbak

--启动数据库(170)
pg_ctl start
代码语言:javascript
复制
--新主库查询同步状态(171)
select pid,state,client_addr,sync_priority,sync_state from pg_stat_replication;

--进行简单的同步测试
新主库(171)
create database test;
新备库(170)
\l
可查询到主库创建的 test 数据库,说明主从同步正常。
新主库(171)
drop database test;
方式二:使用 pg_rewind 工具进行同步
  • 优势:可以增量同步数据。
  • 劣势:需要提前修改数据库参数,步骤多了几步。

使用前提:需要数据库 wal_log_hints(默认 off,未开启),full_page_writes(默认 on,开启),这两个参数开启。

代码语言:javascript
复制
--原主库检查参数开启状态,若未开启,进行开启(170)
show wal_log_hints;
show full_page_writes;

alter system set wal_log_hints = 'on';
代码语言:javascript
复制
pg_ctl restart

--停原主库,pg_rewind 拉取新主库增量数据(170)
pg_ctl stop
pg_rewind --target-pgdata /data/pgdata --source-server='host=192.168.100.171 port=5432 user=postgres dbname=postgres password=Syd@171345'

--原主库配置文件追加同步信息参数(170)
vi $PGDATA/postgresql.auto.conf

primary_conninfo = 'user=postgres password=Syd@171345 host=192.168.100.171 port=5432'
recovery_target_timeline = 'latest'

--原主库创建恢复标识文件(170)
此文件为 PG v12 版本后引入的,之前版本使用上一步骤中 postgresql.auto.conf 文件中追加 standby_mode = 'on' 实现

touch $PGDATA/standby.signal

--启动数据库(170)
pg_ctl start
代码语言:javascript
复制
--新主库查询同步状态(171)
select pid,state,client_addr,sync_priority,sync_state from pg_stat_replication;

--进行简单的同步测试
新主库(171)
create database test;
新备库(170)
\l
可查询到主库创建的 test 数据库,说明主从同步正常。
新主库(171)
drop database test;

参考文章:https://cnblogs.com/VicLiu/p/12993542.html xiaosonggong.blog.csdn.net/article/details/120053437 xiaosonggong.blog.csdn.net/article/details/124554260

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-07-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 民工哥技术之路 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • PostgreSQL 预写日志机制(WAL)
    • 关于持久性
      • WAL过程分析
      • 主从复制
        • 基于文件的日志传送
          • 流复制
            • 环境
              • 实施步骤
                • 验证同步
                  • 概述
                    • 备库提升为主库
                      • 原主库恢复
                        • 原主库调整为备库
                        相关产品与服务
                        数据库
                        云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档