转载

PostgreSQL 主备流复制机制介绍/搭建步骤



链接:http://blog.itpub.net/28602568/viewspace-2107799/

标题:PostgreSQL 主备流复制机制介绍/搭建步骤 

作者:lōττéry©版权所有[文章允许转载,但必须以链接方式注明源地址,否则追究法律责任.]



PostgreSQL主备流复制机制介绍

     PostgreSQL在9.0之后引入了主备流复制机制,通过流复制,备库不断的从主库同步相应的数据,并在备库apply每个WAL record,这里的流复制每次传输单位是WAL日志的record。
     而PostgreSQL9.0之前提供的方法是主库写完一个WAL日志文件后,才把WAL日志文件传送到备库,这样的方式导致主备延迟特别大。
     同时PostgreSQL9.0之后提供了Hot Standby,备库在应用WAL record的同时也能够提供只读服务,大大提升了用户体验。

PG主备流复制的核心部分由walsender,walreceiver和startup三个进程组成。
     walsender进程是用来发送WAL日志记录的
     walreceiver进程是用来接收WAL日志记录的
     startup进程是用来apply日志的

               下图是PG主备总体框架图:
PostgreSQL 主备流复制机制介绍/搭建步骤

walsender和walreceiver进程流复制过程

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

  1. walreceiver启动后通过recovery.conf文件中的primary_conninfo参数信息连向主库,主库通过连接参数replication=true启动walsender进程;
  2. walreceiver执行identify_system命令,获取主库systemid/timeline/xlogpos等信息,执行TIMELINE_HISTORY命令拉取history文件;
  3. 执行wal_startstreaming开始启动流复制,通过walrcv_receive获取WAL日志,期间也会回应主库发过来的心跳信息(接收位点、flush位点、apply位点),向主库发送feedback信息(最老的事务id),避免vacuum删掉备库正在使用的记录;
  4. 执行walrcv_endstreaming结束流复制,等待startup进程更新receiveStart和receiveStartTLI,一旦更新,进入步骤2。
PostgreSQL 主备流复制机制介绍/搭建步骤

图2. PG流复制过程

walreceiver和startup进程

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:

    MemSet((char *) htup, 0, sizeof(HeapTupleHeaderData)); /* PG73FORMAT: get bitmap [+ padding] [+ oid] + data */ memcpy((char *) htup + offsetof(HeapTupleHeaderData, t_bits), (char *) xlrec + SizeOfHeapInsert + SizeOfHeapHeader, newlen); newlen += offsetof(HeapTupleHeaderData, t_bits); htup->t_infomask2 = xlhdr.t_infomask2; htup->t_infomask = xlhdr.t_infomask; htup->t_hoff = xlhdr.t_hoff; HeapTupleHeaderSetXmin(htup, record->xl_xid); HeapTupleHeaderSetCmin(htup, FirstCommandId); htup->t_ctid = xlrec->target.tid; offnum = PageAddItem(page, (Item) htup, newlen, offnum, true, true); if (offnum == InvalidOffsetNumber) elog(PANIC, "heap_insert_redo: failed to add tuple"); freespace = PageGetHeapFreeSpace(page); /* needed to update FSM below */ PageSetLSN(page, lsn); if (xlrec->flags&XLOG_HEAP_ALL_VISIBLE_CLEARED) PageClearAllVisible(page); MarkBufferDirty(buffer);

    还有部分redo操作(vacuum产生的record)需要检查在Hot Standby模式下的查询冲突,比如某些tuples需要remove,而存在正在执行的query可能读到这些tuples,这样就会破坏事务隔离级别。通过函数ResolveRecoveryConflictWithSnapshot检测冲突,如果发生冲突,那么就把这个query所在的进程kill掉。

  5. 检查一致性,如果一致了,Hot Standby模式可以接受用户只读查询;更新共享内存中XLogCtlData的apply位点和时间线;如果恢复到时间点,时间线或者事务id需要检查是否恢复到当前目标;
  6. 回到步骤3,读取next WAL record。
PostgreSQL 主备流复制机制介绍/搭建步骤

图3. PG standby模式和apply日志过程

                      如上postgresql主备流复制机制介绍 信息来源于网站 http://mysql.taobao.org/monthly/2015/10/04/ 

搭建步骤

环境:
Wonhigh-Test15  10.240.1.101 -->主
Wonhigh-Test16  10.240.1.102 -->备
前提:主备机器都安装DB..【搭建步骤可参考 http://blog.itpub.net/28602568/viewspace-1841163/  】

primary 主

参数文件配置
[postgres@Wonhigh-Test15 data]$ grep -v "^#"  postgresql.conf
默认配置:
max_connections = 100
shared_buffers = 128MB                
dynamic_shared_memory_type = posix      
log_timezone = 'PRC'
datestyle = 'iso, ymd'
timezone = 'PRC'
lc_messages = 'zh_CN.UTF-8'               # locale for system error message
lc_monetary = 'zh_CN.UTF-8'               # locale for monetary formatting
lc_numeric = 'zh_CN.UTF-8'                 # locale for number formatting
lc_time = 'zh_CN.UTF-8'                       # locale for time formatting
default_text_search_config = 'pg_catalog.simple' 
#主备配置更改部分
wal_level = hot_standby     # 这个是设置主为wal的主机
max_wal_senders = 32        # 这个设置了可以最多有几个流复制连接,差不多有几个备,就设置几个
wal_keep_segments = 256  #设置流复制保留的最多的xlog数目
wal_sender_timeout = 60s   #设置流复制主机发送数据的超时时间
max_connections = 100       # 这个设置要注意下,备库的max_connections必须要大于主库的
listen_addresses = '*'   
[postgres@Wonhigh-Test15 data]$
访问权限配置
[postgres@Wonhigh-Test15 data]$ grep -v "^#"  pg_hba.conf |grep replication  
host    replication   replica     10.240.1.102/32          md5 
[postgres@Wonhigh-Test15 data]$
DB同步账号配置
[postgres@Wonhigh-Test15 data]$ psql -c"CREATE ROLE replica login replication encrypted password 'replica';"


standby 备

复制主库到备库...前提/data/pgsql/data/需要为空
[postgres@Wonhigh-Test16 ~]$ pg_basebackup -D /data/pgsql/data/  -Fp -Xs -v -P -h 10.240.1.101  -U replica -p5432 --password
Password:
transaction log start point: 0/2000028 on timeline 1
pg_basebackup: starting background WAL receiver
41369/41369 kB (100%), 1/1 tablespace                                        
transaction log end point: 0/20000F0
pg_basebackup: waiting for background process to finish streaming ...
pg_basebackup: base backup completed
[postgres@Wonhigh-Test16 ~]$ 

配置参数文件postgresql.conf
hot_standby = on   # 说明这台机器不仅仅是用于数据归档,也用于数据查询   <若是off的话 启动DB链接时会报错psql: FATAL:  the database system is starting up>
max_standby_streaming_delay = 30s    # 数据流备份的最大延迟时间
wal_receiver_status_interval = 1s          # 多久向主报告一次备的状态,当然备每次数据复制都会向主报告状态,这里只是设置最长的间隔时间
hot_standby_feedback = on                 # 如果有错误的数据复制,是否向主进行反馈

配置recover.conf文件
$ cp /usr/local/pgsql/share/recovery.conf.sample /data/pgsql/data/recovery.conf
$ grep -v '^#' /data/pgsql/data/recovery.conf
standby_mode = 'on'                             # 这个说明这台机器为备库 
trigger_file = '/data/pgsql/data/postgresql.trigger.1949'
primary_conninfo = 'host=10.240.1.101 port=5432 user=replica password=replica keepalives_idle=60'   # 这个说明这台机器对应主库的信息
recovery_target_timeline = 'latest'  # 这个说明这个流复制同步到最新的数据 
$
启动备库
$ pg_ctl restart  -D /data/pgsql/data/ -l /data/pgsql/log.log   



查看复制状态 

postgres=# /x                                                           --
Expanded display is on.
postgres=#  select * from pg_stat_replication;
-[ RECORD 1 ]----+------------------------------
pid            | 8964       # sender的进程
usesysid        | 16384      # 复制的用户id
usename         | replica    # 复制的用户用户名
application_name   | walreceiver 
client_addr      | 10.240.1.102 # 复制的客户端地址
client_hostname    |
client_port      | 50511  # 复制的客户端端口
backend_start    | 2016-05-25 17:29:53.874416+08  # 这个主备搭建的时间
backend_xmin     |
state          | streaming  # 同步状态 startup: 连接中、catchup: 同步中、streaming: 同步
sent_location    | 0/3012290 # Master传送WAL的位置
write_location    | 0/3012290 # Slave接收WAL的位置
flush_location    | 0/3012290 # Slave同步到磁盘的WAL位置
replay_location    | 0/3012290 # Slave同步到数据库的WAL位置
sync_priority    | 0         #同步Replication的优先度      0: 异步、1~?: 同步(数字越小优先度越高)
sync_state       | async  # 有三个值,async: 异步、sync: 同步、potential: 虽然现在是异步模式,但是有可能升级到同步模式
postgres=# 


查看主从进程
 -->查看wal sender进程    -->walsender进程是用来发送WAL日志记录的
《主》$ ps -ef |grep sender|grep -v grep
          postgres  8964  4365  0 17:29 ?        00:00:00 postgres: wal sender process replica 10.240.1.102(50511) streaming 0/3012368

  -->查看receiver/start进程  --> walreceiver进程是用来接收WAL日志记录的,startup进程是用来apply日志的
《备》$ ps -ef |grep receiver|grep -v grep                
          postgres 21103 21098  0 17:29 ?        00:00:00 postgres: wal receiver process   streaming 0/3012368
$ ps -ef |grep startup|grep -v grep
postgres 21099 21098  0 17:29 ?        00:00:00 postgres: startup process   recovering 000000010000000000000003


验证是否开始同步
主库执行DDL/DML ,在备库验证是否同步
     主:
     test=# create table t_1 (name varchar(10));
     CREATE TABLE
     test=# insert into t_1 values('1');
     INSERT 0 1
     test=#
     备:
     postgres=# /c test
     You are now connected to database "test" as user "postgres".
     test=# select * from  t_1;
     name
     ------
     1
     (1 row)
     
     test=# 



    【源于本人笔记】 若有书写错误,表达错误,请指正...


此条目发表在 PostgreSQL 分类目录。将固定连接加入收藏夹。


正文到此结束
Loading...