一、主从概念
通常为了解决单点数据库宕机后服务不可用的问题,在数据库服务器中都会有一个与主库数据同步的从库。主从的一个核心也就是需要保持主从数据的一致性。
保证主从数据的一致性(同步)
-
实现数据库的负载均衡,主提供读写能力,从复制主上的数据,从可以提供读的能力。
-
实现数据库服务高可用,主挂掉后,从可以升级为主继续提供服务。
pg主从实现方式
-
持续复制归档日志: 在主服务器开启归档后,我们可以把WAL日志备份出来,通过cp或者scp把日志拷贝到从上去,实现主从数据的同步。延迟大、从的数据落后主的一个WAL日志
-
流复制(PostgreSQL9.0之后):备服务器通过tcp流从主服务器中同步相应的数据。主服在WAL记录产生时即将它们以流式传送给备服务器,而不必等到WAL文件被填充。
-
同步流复制:高度耦合、从出问题,主跟着出问题。
-
异步流复制:备库的数据并不是最新的而是有延迟的,无法保证查询的一致性。
-
二、Write-Ahead Logging(WAL)机制
WAL log:记录插入、删除或提交操作等更改的日志。
1、在WAL日志空间中,被划分为WAL文件段,一个WAL文件最大16MB。
-
WAL段名称:TimeLineID+逻辑文件ID+物理文件ID
-
LSN(Log Sequence Number):这是WAL日志唯一的、全局的标识,给每条产生的wal日志记录一个编号(自增的),表示在wal日志空间中的位置。
2、WAL机制的核心思想就是:先日志落盘,后数据落盘。
-
无需每次修改了数据均要刷盘,I/O次数更少;I/O开销更少(随机写变为顺序写);
-
实现PITR和主从同步的基础;
3、基于WAL机制,其数据更新流程大致为:
(1)更改数据到share_buffer
(2)把操作写到wal_buffer,并且得到LSN
(3)将LSN写到数据页的pd_lsn字段
(4)Wal日志落盘(该LSN之前的);
(5)数据落盘;
三、基于流复制的主从结构及实现
一主一从/二从结构
涉及进程:
-
Wal sender:用于主库发送WAL日志记录至从库;
-
Wal receiver:存在于备库。用于从库接收主库的WAL日志记录
-
startup:备库实例恢复进程。将wal日志在备库上重放;
细节描述
为了了解上述三个进程启动先后关系,以一主一从为例,了解一主一从的实现细节。
(1)启动主、备;
(2)备启动startup进程;
(3)备启动walreceiver进程;
(4)walreceiver向主发送连接请求;
(5)当主收到连接请求,启动walsender进程,建立walsender与walreceiver之间的TCP连接;
(6)walreceiver发送备最新LSN(握手机制);
(7)将主库最新LSN到备库最新的LSN之间的wal 传递给walreceiver 。这个阶段就是备库追赶主库的阶段。
(8)流复制开始工作
部署注意事项
1、一主一从实现
首次主从部署:基础备份(全量复制)+主备同步(增量复制)
-
pg_basebackup:walsender发送整个数据库集簇到备机;
-
主:pg_hba.conf、postgresql.conf
-
从:standby.signal、primary_conninfo
后续主从切换:promote
-
主库宕机,从库需提升为主库
-
新主:检查pg_hba.conf、postgresql.conf
-
新从: standby.signal、primary_conninfo
2、一主二从实现
首次一主二从部署:
-
从2与主建立主从关系;
后续主从切换:
-
从集群中选择一个主;
-
该新主与旧主进行主从切换;
-
剩下的非主从更换主;
主从模型需要关注的问题
-
主从切换数据不同步?
情况1:若主宕机后,新主进行了DML,然后再进行主从切换,数据不同步?(新从数据“落后”新主的数据)
情况2:若主宕机后,新从进行了DML,然后再进行主从切换,数据不同步?(新从数据“领先”新主的数据)
答:可以利用 pg_rewind, pg_rewind是一种增量复制,会对比主从之间的TimeLine差异,进行一次同步。对于情况1没有问题。对于情况2:主从切换,老主可能因为有多的日志而无法直接作为新主的从库加入,使用pg_rewind删除多余日志。虽然可以做到主从数据同步,但可能会丢失数据。
-
数据的复制是异步的。客户端提交commit并且成功之后,数据可能还没有同步到只读节点。因此备库的数据并不是最新的而是有延迟的,无法保证查询的一致性。
-
网络好一些、避免主从节点在不同的机房;
-
可以开发一个外部程序来监控主从节点间的复制进度。监控程序查到主、从节点的进度,得到从节点和主节点间的复制进度差值。如果某个从节点的进度差值大于我们预设的阈值,我们可以让客户端不再和这个从节点连接进行数据读取,这样就可以减少读到不一致数据的情况。
四、基于主从的高可用数据库架构
主从结构最重要是可以给数据库解决高可用、高负载的问题。这同时也需要和一些其他组件搭配一起使用。那么一个比较典型的基于主从的高可用数据库的架构如图所示。首先,使用DBproxy作为代理管理主从集群,提供负载均衡机制读写分离等功能。但是,用DBproxy做了主从集群的转发,那这样读写请求的压力就落到DBproxy头上了,为了实现DBproxy的高可用,提高DBproxy单节点的并发能力,引入LVS组件并搭建LVS集群代理DBproxy集群,来扩展DBproxy的负载能力。并且LVS是工作在四层的,直接将读写请求给到后面的Dbproxy,能抗住更多的请求。最后通过keepalived结合LVS实现LVS集群的双主热备,解决定期对LVS进行健康检测,保障LVS的高可用。KeepAlived可以提供一个统一虚拟IP,业务系统直接连接这个虚拟IP,后面的过程对于应用系统是透明的,用户只在乎请求和及时响应。
总结一下:
-
DBproxy:DB代理管理数据库集群,读写分离、负载均衡机制,sql语句黑名单、DBA平滑下线DB、从库流量配置、动态加载配置项。
-
LVS组件:扩展DBproxy的负载能力,负载均衡、保证其高可用。DR模式,请求不通过LVS,直接给到DBProxy,工作在四层。
-
Keepalived:解决LVS单点故障问题,为LVS做健康检查保证LVS的高可用。同时,Keepalived可以提供一个同一的虚拟IP,业务系统直接连接这个虚拟IP,后面的过程对于应用系统是透明的。