1、概述

1.1、什么是流复制?
如果有人问你PostgreSQL的流复制究竟是什么?你大概会说通过wal日志来进行数据同步之类的,的确如此,流复制大概就是这么回事。
但是准确的来说:PostgreSQL通过wal日志来传送的方式有两种:基于文件的日志传送和流复制。
不同于基于文件的日志传送,流复制的关键在于“流”,所谓流,就是没有界限的一串数据,类似于河里的水流,是连成一片的。因此流复制允许一台后备服务器比使用基于文件的日志传送更能保持为最新的状态。
比如我们有一个大文件要从本地主机发送到远程主机,如果是按照“流”接收到的话,我们可以一边接收,一边将文本流存入文件系统。这样,等到“流”接收完了,硬盘写入操作也已经完成。

1.2、流复制发展历史
流复制之前的手段:
像我们上面说的,pg在流复制出现之前,使用的就是基于文件的日志传送:对wal日志进行拷贝,因此从库始终落后主库一个日志文件,并且使用rsync工具同步data目录。

而流复制出现是从2010年推出的pg9.0开始的,其历史大致为:

  1. 起源:pg9.0开始支持流式物理复制,用户可以通过流式复制,构建只读备库
    (主备物理复制,块级别一致)。流式物理复制可以做到极低的延迟(通常在1毫秒以内)。
  2. 同步流复制:pg9.1开始支持同步复制,但是当时只支持一个同步流复制备节点(例如配置了3个备,只有一个是同步模式的,其他都是异步模式)。同步流复制的出现,保证了数据的0丢失。
  3. 级联流复制:pg9.2支持级联流复制。即备库还可以再连备库。
  4. 流式虚拟备库:pg9.2还支持虚拟备库,即就是只有WAL,没有数据文件的备库。
  5. 逻辑复制:pg9.4开始可以实现逻辑复制,逻辑复制可以做到对主库的部分复制,例如表级复制,而不是整个集群的块级一致复制。
  6. 增加多种同步级别:pg9.6版本开始可以通过synchronous_commit参数,来配置事务的同步级别。

1.3、流复制概述
流复制其原理为:备库不断的从主库同步相应的数据,并在备库apply每个WAL record,这里的流复制每次传输单位是WAL日志的record。

PostgreSQL物理流复制按照同步方式分为两类:

  • 异步流复制
  • 同步流复制

物理流复制具有以下特点:
1、延迟极低,不怕大事务
2、支持断点续传
3、支持多副本
4、配置简单
5、备库与主库物理完全一致,并支持只读

2、流复制原理

2.1、日志提交过程

postgresql复制流配置 pg数据库流复制_PostgreSQL


从上图我们可以看到流复制中日志提交的大致流程为:

1、事务commit后,日志在主库写入wal日志,还需要根据配置的日志同步级别,等待从库反馈的接收结果。

2、主库通过日志传输进程将日志块传给从库,从库接收进程收到日志开始回放,最终保证主从数据一致性。

2.2、流复制同步级别
PostgreSQL通过配置synchronous_commit (enum)参数来指定事务的同步级别。我们可以根据实际的业务需求,对不同的事务,设置不同的同步级别。

synchronous_commit = off                # synchronization level;  
                                        # off, local, remote_write, or on
  • remote_apply:事务commit或rollback时,等待其redo在primary、以及同步standby(s)已持久化,并且其redo在同步standby(s)已apply。
  • on:事务commit或rollback时,等待其redo在primary、以及同步standby(s)已持久化。
  • remote_write:事务commit或rollback时,等待其redo在primary已持久化; 其redo在同步standby(s)已调用write接口(写到 OS, 但是还没有调用持久化接口如fsync)。
  • local:事务commit或rollback时,等待其redo在primary已持久化;
  • off:事务commit或rollback时,等待其redo在primary已写入wal buffer,不需要等待其持久化;

不同的事务同步级别对应的数据安全级别越高,对应的对性能影响也就越大。上述从上至下安全级别越来越低。

 

3.流复制的应用

基于流复制协议的wal日志从主节点到备节点实时复制传输与复用。为了实现数据库的高可用,一般需要搭建主库和备库。

流复制是搭建主备库的一种有效方式,它不需要额外增加软件,只需要在单数据库模式的基础上,再复制一份PostgreSQL数据库到另外的一台机器上,对两台数据库进行参数配置,即可实现。

这两套数据库之间的数据,通过wal日志,后台自动同步。对外部的应用程序而言,可以看作是两套数据库,需要根据业务需要,显式分别连接不同的数据库。

那流复制是怎么实现的呢?请参见下图,流复制主要涉及到几个backend辅助进程:walwriter,walsender,walreceiver,startup。

当用户连接进行数据操作,产生对应的WAL日志记录后,walwriter会周期性地把产生的WALpage刷新到磁盘中,如果配置了备库,则walsender会不断将WAL page发给备库的walreceiver进程,walreceiver进程会把对应WAL page直接写到本地磁盘,同时slave上的startup辅助进程会不断地应用xlog日志,改变本地数据,实现与主库之间的数据同步。而且,通过配置,备库是可以接受用户的只读请求。

postgresql复制流配置 pg数据库流复制_PostgreSQL_02

Postgresql不同版本流复制的主要区别如下:

而PostgreSQL9.0之前提供的方法是主库写完一个WAL日志文件后,才把WAL日志文件传送到备库,这样的方式导致主备延迟特别大。

PostgreSQL在9.0之后引入了主备流复制机制,通过流复制,备库不断的从主库同步相应的数据,并在备库apply每个WAL record,每次传输单位是WAL日志的record。

同时PostgreSQL9.0之后提供了Hot Standby,备库在应用WAL record的同时也能够提供只读服务,大大提升了用户体验。

 

附:

9.0开始支持1+n的异步流复制.

9.1支持1+1+n的同步和异步流复制

9.2开始支持级联流复制

9.3开始支持跨平台的流复制协议

9.3开始流复制协议增加了时间线文件传输的协议,支持自动切换时间线.

9.4可以使用流复制做增量数据同步,所以停机服务时间会非常短。

 

流复制传递日志两种方式:

异步流复制  

同步流复制

 

两者的主要区别是什么?

在异步流复制的情况下,事务被提交到master之后数据才可以被复制。

换句话说,slave从不会超前master,就写操作而言,通常滞后于master一些,此延迟(delay)被称为滞后性(lag)。

 

同步复制较高数据一致性规则

如果您决定使用同步复制,系统必须确保通过事务写入的数据至少事务同时在两台服务器上提交。这意味着:slave不滞后于master,而且终端用户在两台服务器上看到的数据是一致的。

 

考虑数据丢失

假设我们正在以异步复制方式同步数据:

1.事物发送到master。

2.事物提交到master。

3.在事物发送到slave之前,master宕机。

4.slave永远都不会收到这个事务。

 

在异步复制的情况下,有一个窗口(滞后),在滞后窗口期间数据会丢失。滞后窗口的大小因设置类型的不同而不同。它的大小非常短(几毫秒)或非常长(几分钟,几小时,几天)。

一个重要的事实是:数据可能丢失。一个小的滞后只会是数据丢失的可能性较小,但任何大于零的滞后都容易导致数据丢失。

 

如果您想确保数据永远不丢失,您必须切换到同步复制。

一个同步事务是同步的,因为如果事物提交到了两台服务器它才是有效的。

 

考虑性能问题

通过网络发送不必要的消息的开销是昂贵的和费时的。

如果一个事务采用同步的方式复制,PostgreSQL必须确保数据到达第二个节点,这样就会导致延迟问题。

同步复制要求在数据写入Standby数据库后,事务的commit才返回,所以Standby库出现问题时,会导致主库被hang住。(解决这个问题的方法是启动两个Standby数据库,这两个standby数据库只要有一个是正常的,就不会让主库hang住)

在许多方面,同步复制比异步复制要昂贵很多,因此如果这种消耗确实需要和调整,应该三思而后行。(只在需要的时候使用同步复制)