大佬教程收集整理的这篇文章主要介绍了PostgreSQL主备流复制机制详解,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
首先,附上原文链接:http://mysql.taobao.org/monthly/2015/10/04/
POSTGResql在9.0之后引入了主备流复制机制,通过流复制,备库不断的从主库同步相应的数据,并在备库apply每个WAL record,这里的流复制每次传输单位是WAL日志的record。而POSTGResql9.0之前提供的方法是主库写完一个WAL日志文件后,才把WAL日志文件传送到备库,这样的方式导致主备延迟特别大。同时POSTGResql9.0之后提供了Hot Standby,备库在应用WAL record的同时也能够提供只读服务,大大提升了用户体验。
主备总体结构
PG主备流复制的核心部分由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()
下图是PG主备总体框架图:
walsender和walreceiver进程流复制过程
walsender和walreceiver交互主要分为以下几个步骤:
(1)walreceiver启动后通过recovery.conf文件中的pri
Mary_conninfo参数信息连向主库,主库通过连接参数
Replication=true启动walsender进程;
(2)walreceiver执行IDentify_system命令,获取主库systemID/timeline/xlogpos等信息,执行TIMEliNE_HISTORY命令拉取history文件;
(3)执行wal_startstreaming开始启动流复制,通过walrcv_receive获取WAL日志,期间也会回应主库发过来的心跳信息(接收位点、flush位点、apply位点),向主库发送
Feed
BACk信息(最老的事务ID),避免
VACUUM删掉备库正在使用的记录;
(4)执行walrcv_endstreaming结束流复制,等待startup进程更新receiveStart和receiveStartTli,一旦更新,进入步骤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:
@H_537_73
@memSet((char *) htup,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,tru
E);
if (offnum == InvalIDOffset
number)
elog(PANIC,"heap_insert_redo: Failed to add tuple"
);
freespace = PageGetHeapFreeSpace(pag
E); /* needed to
update FSM below */
PageSetLSN(page,lsn
);
if (xlrec->flags & XLOG_HEAP_
all_VISIBLE_CLEARED)
PageClearallVisible(pag
E);
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。
下图是PG standby模式和apply日志过程:
大佬总结
以上是大佬教程为你收集整理的PostgreSQL主备流复制机制详解全部内容,希望文章能够帮你解决PostgreSQL主备流复制机制详解所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。