探索BI系统搭建的必要性与AI技术的应用潜力
643
2022-05-29
一、用户场景与解决方案
随着业务的迅速增长,客户原有的生产集群部署的服务器性能会逐渐无法满足业务需求,由此客户可能会采购一批高配置的服务器搭建新集群,希望将生产集群的数据迁移到新集群。
先前客户通常使用GDS工具等方式,将生产集群数据先导出至中转服务器,然后从中转服务器再导入新集群。但这样周期很长,且需要客户提前准备大量机器用做GDS中转服务器。事实上,GaussDB(DWS)从两年前已研发出了一种新的集群数据迁移利器,可以高效完成该工作,该方案基于Roach物理备份恢复原理。
考虑到OLAP场景下,用户集群动辄数百个节点,数据量则高达若干PB,集群数据迁移过程往往需要数小时之久。一种应对方案是一次全量迁移加多次增量迁移配合,另一种是全量迁移与断点续做配合。目前客户稳妥起见通常选择固定的变更时间窗,停业务离线迁移结合断点续做的方式。本文主要就断点续做展开讨论。
二、断点续做原理解析
本文从宏观到微观,抽丝剥茧,带大家逐层了解断点续做的原理。
集群数据迁移框架是在SyncDataToStby.py工具中实现的,同时部署在新老集群上,该工具负责在生产集群上拉起GaussRoach.py -t backup备份任务,在新集群上拉起GaussRoach.py -t restore恢复任务。生产集群上由Roach备份生成的*.rch备份压缩文件,通过scp命令传输到新集群上,新集群通过Roach工具解压这些*.rch备份文件,从而将生产集群的数据文件以物理恢复的方式同步到了新集群。具体框架如下,细节本文不做展开描述。
上图只是简化示意,实际上scp动作发生在新老集群间的两个CN/DN实例之间,而非两个节点之间。因此,迁移框架支持两套集群节点数不同,只要两套集群的总DN个数相同即可(通常称为异构迁移或异形迁移)。熟悉GaussDB(DWS)的读者可能已经发现,该框架与GaussDB(DWS)双集群容灾架构完全相同。没错,该框架非常强大,对于异构或同构的双集群跨AZ容灾、集群间数据迁移都是通用的,且支持一次全量、多次增量容灾或数据同步,支持在线不停业务周期数据同步或容灾,支持容灾或迁移过程中断点续做。而集群数据迁移其实是使用了其最简单的一种场景,相当于离线场景下只做了一次全量数据同步到新集群。
回到正题,如上框架下,如何做到集群迁移的断点续做呢?
不难观察到,该框架基于Roach物理备份恢复,生产集群相当于做了一次全量集群物理备份,新集群相当于做了一次全量集群物理恢复。全量备份和全量恢复两个过程之间基本解耦,通过scp备份文件将两个过程关联起来。因此,该框架下的断点续做实现,最主要的就是分别管理好生产集群的全量备份断点续做和新集群的全量恢复断点续做,以及两个集群间的scp动作中断场景的续做。上图中的(1)、(2)、(3)标记指出了这3个过程。下文将基于这3个过程展开说明。
1、全量备份的断点续做
全量备份调用的是GaussRoach.py备份工具,这个就是大家熟悉的单个集群的备份恢复工具Roach。要控制全量备份的断点续做,就需要了解Roach工具的架构、内部运转流程,作为基础此处会带大家额外回顾下Roach的知识,已掌握的读者可以跳过。大家阅读的时候可以考虑这样的框架和流程下如何实现断点续做。
GaussDB(DWS)集群是分布式架构的,其备份工具Roach也基于分布式架构。Roach主要包括两个组件:调度框架GaussRoach.py和实际执行任务的gs_roach程序。假设集群有3个节点,用户在节点1调用GaussRoach.py发起备份操作,那么我们就将节点1称为master节点(主节点),其余节点称为agent节点。GaussRoach.py通过ssh命令给每个节点都拉起gs_roach进程,后者根据本节点DN个数fork相应数量的gs_roach子进程,每个gs_roach进程负责一个DN的备份任务。备份任务结束后,所有gs_roach和GaussRoach.py进程退出。同一时刻,集群内所有DN相当于都在并行备份数据。
为节省内存开销,主节点的gs_roach同时兼任Roach master和Roach agent身份。Roach master维护一个状态机,与其余节点的Roach agent通过TCP长连接进行通信,前者扮演主控角色,给其余节点发送命令,通知它们按状态机的次序逐个完成各项子任务,并控制其余节点的备份状态保持同步。目前集群全量备份共有十几个状态,各个Roach agent节点需要按Roach master的指令依次完成十几个子任务。Roach master会等待各个Roach agent都完成该项子任务才会推进到下一个状态。为了更好地控制分布式交互,各个Roach agent也维护了自己的一个状态机,其状态大体与Roach master的状态一一对应。
有了这些基础知识后,就不难想到分布式框架下实现全量备份断点续做的一个思路:用两个元数据文件resume_backup_master.metadata和resume_backup_agent.metadata,分别记录Roach master和Roach agent当前已完成到哪个状态机阶段,每完成一个子任务,就刷新一次续做的元数据文件。那么,中间出现故障后,需要拉起续做任务时,就读取这俩文件获知上次完成到哪个子任务,本次就从下一个子任务开始接着做。当然,每个节点都有Roach agent,所以resume_backup_agent.metadata也不止一个,每个节点负责维护自己的Roach agent续做元数据。同时,这个文件里面记录的信息也远远不止子任务状态。
然后进一步来看这十几个子任务内部如何续做。最主要的子任务包括生成实例数据文件清单、备份行存文件、创建barrier点、备份xlog文件、备份列存文件。创建barrier点大家已经了解,是一个全局事务一致性点,将来集群恢复时就是恢复到这个点。最关键的是备份行存、备份列存两个阶段,往往需要若干小时,那么这两个阶段过程中出现故障,下次就得重新做这个子任务,有没有办法优化呢,使重做的颗粒度更小?
我们知道,备份过程实质是将各个CN/DN等实例下的数据文件生成*.rch格式的压缩包,每个压缩包最大不超过4GB(可配置)。每个4GB的文件通常都能在几分钟内完成生成和备份,记录这些rch文件编号信息,就可以在下次续做时接着上次rch编号继续备份,从而每个实例续做浪费的时间就控制在几分钟内。这个思想简单,但实现起来却非常复杂,与当前Roach的核心流程、各种性能优化机制都息息相关,要考虑很多因素。由于Roach支持在线备份,且PG不支持undo,我们在备份文件之前会先生成备份开始时刻的数据文件清单,备份时按当时时刻的文件大小截取拷贝到内存中。而从磁盘读取文件内容开销会很大,因此Roach设计了多reader线程机制来加速读IO性能,小于8MB的文件(可配置)由reader线程负责读取,较大文件则由主线程exec负责读取,最后由exec负责内存数据汇总。这个性能优化机制带来了一个问题,就是rch文件中的备份文件顺序和文件清单中文件顺序可能出现不连续跳变,下次续做就无法接着上次文件清单进度进行。由此,新增了roach_resume_trans_log日志文件记录各个实例下的大小文件序号,分两条线保证续做的正确性。
下图是Roach备份过程中的生产者-消费者模型示意图,有助于大家理解这个过程。图中标记了几个典型产生断点的地方。
总结一下,4GB颗粒度的断点续做,其实就是基于备份前生成的数据文件清单而进行的续做。通过辅助的roach_resume_trans_log日志文件,记下最近一次完成的4GB的rch备份压缩文件里对应的数据文件编号最大值(包括exec线程和reader线程两种编号),下次续做时从这里记录的编号值接着读取数据文件清单,进行续做。
2、全量恢复的断点续做
集群全量恢复分为三个阶段:停止集群、恢复集群、启动集群。由于主备DN数据互为副本,备份DN时只备份了主DN数据,恢复集群过程中也只恢复主DN数据。然后在启动集群阶段,一方面会将主DN数据redo到barrier点,另一方面会用主DN数据build到备DN,使得备DN成为主DN数据的副本。这三个阶段中,最耗时的就是恢复集群阶段,本节主要展开讨论这个阶段的续做。
集群迁移场景下,为了尽可能缩短迁移时间窗,采用了很多黑科技,其中之一就是主备DN并行恢复。这样省去了主DN数据build备DN过程,使得恢复和迁移时间缩短一半以上。原理是先将主DN的rch备份压缩文件拷贝到备DN的关联路径下(都在新集群内部拷贝),然后主DN和备DN就可以同时进行解压恢复rch文件了。最后只需特殊处理一下备DN的postgresql.conf即可。
全量恢复的断点续做主要包括3个方面:
a) 全量恢复
看了前面的全量备份过程,大家自然联想到全量恢复是不是也是由状态机驱动、分为若干子任务。实际的情况是,全量恢复虽然也由状态机驱动,但状态个数非常少。这是因为恢复过程本身比较简单,所有实例、行列存/xlog对于Roach来说都可以一视同仁,因为rch备份文件最初就设计为自解析模式的,Roach解析rch文件就完全可以知道是哪个节点、哪个实例、行列存还是xlog的数据文件,因此主要的恢复过程只需要一个子任务调度就可以了。
全量恢复的断点续做,就只需处理好上次恢复到哪个rch。一种思路是也用meta元数据记录上次恢复进度信息,另一种更简单的思路是:不使用元数据,直接遍历本地已恢复完的rch文件,即可得知本次需要从哪个rch开始续做恢复。为了在线集群迁移方便扩展,新集群恢复完的rch文件并没有立即删除,而是重命名为*.rch.resume_delete后缀,所以断点续做时只需遍历找到当前目录下过滤掉*.rch.tmp、*.rch.resume_delete文件后,编号最小的那个*.rch文件,就是本次续做需要开始的文件。如下图所示,上次中断后,本次恢复只需从file_10.rch开始恢复即可。
b) 恢复中断、恢复比备份快的场景
恢复可能异常中断,导致Roach进程退出。另外若集群间带宽为瓶颈,则新集群恢复rch文件的速度大于生成集群scp拷贝rch文件过来的速度,则也会导致Roach提前完成任务而退出。由此,需要保证过段时间新的rch文件被scp过来后,仍然能接着恢复。
为实现该目的,SyncDataToStby.py工具借助了双集群之间的纽带文件backuprestoreinfo.csv,该文件记录了备份和恢复的当前状态等信息。如果当前备份状态为未完成,则恢复线程就会不断检测是否有新的rch文件传输过来,若有则先scp到新集群内的备实例,然后调度gs_roach并行恢复各个实例的新rch文件。直至所有的rch文件都恢复出来。
c) 启动集群
由于恢复集群前,先停止了集群,所以截止此时集群还处于停止状态,需要拉起集群。有了上面的backuprestoreinfo.csv和rch续做机制后,启动集群就变得比较简单,完全可以复用全量恢复的命令,再拉起一遍恢复续做任务即可。SyncDataToStby.py工具内部会检查核实是否所有rch都已恢复完毕,是则执行集群启动动作,否则续做全量恢复。
3、集群间scp中断后的断点续做
对于集群迁移来说,备份文件不仅要在本地生成,还需要scp到远端新集群,这里就得额外考虑一些问题。本地rch文件生成速度往往较快,如果集群间带宽有限,则rch文件会来不及scp到新集群,积压在生产集群本地。对于生产集群来说,积压过多备份文件在本地会导致磁盘空间紧张引发其它问题,因此断点续做通过流控机制完美解决了积压问题。对于新集群来说,如果出现断点续做,那么下次续做时,就得先查看本地rch编号和新集群已经scp过去的rch文件编号。另外,考虑网络传输时如果新集群设备掉电,可能造成新集群rch文件残缺,因此scp过去时先落盘为*.tmp后缀,fsync成功后,再重命名回*.rch。
4、其它续做考虑
断点续做还要考虑并行备份恢复。这里讲到的并行备份恢复就是又一个黑科技了。最初的迁移框架设计是:全量备份完毕后,新集群开始执行全量恢复,由此生产集群的备份和新集群的恢复是一个串行过程,集群迁移总时间 = 全量备份时间 + 全量恢复时间。为了实现更快、风险更小的迁移目标,我们改造了迁移框架,使得生产集群的备份过程和新集群的恢复过程可以并行起来,生产集群每生成一个rch文件,就scp到新集群,然后新集群就开始恢复。新集群通过backuprestoreinfo.csv文件的信息,结合本地已恢复完成的*.rch.resume_delete文件编号信息,可以持续推进恢复流程直至全部完成。前面章节已有陆续提及,此处不做展开说明。
当然,断点续做需要考虑的场景远不止此,比如硬件故障造成的实例主备切换、日志分叉、行存备份阶段内核开启的延迟xlog开关、列存备份阶段内核开启的延迟ddl开关等因素的兼容。这些都做了坚固的适配,以便下次重入时可以正确处理。限于篇幅,本文不做进一步说明。
三、约束与展望
基于Roach的集群迁移框架,是机房搬迁等应用场景的数据迁移利器,可大幅缩短迁移时间窗,两年来在大型金融机构客户里面也已多次成功实践,不断刷新客户的预期。该方案包含了很多黑科技,本文也有提及一二,但仍然有很多可以做的更好的地方。本节根据笔者的观点,给出一些约束与展望,仅供参考。
1、本迁移方案目前主要用于线下离线集群搬迁,在线上场景只要打通两套集群间互信与沙箱差异,也比较容易适配。在线迁移也是容易扩展的,因为第一版设计就已考虑兼容在线场景,事实上最新版本已差不多打通在线场景。
2、作为离线集群迁移方案,本方案还是要求集群处于启动且Normal状态。后续可以简单做下适配,改造为停集群搬迁,这样可以简化主备切换、集群健康监控干扰等大量故障场景的处理。
3、由于是物理搬迁,所以两套集群要求拓扑同构或异形,即两套集群的DN总数要相同,否则不好做映射。该约束目前还暂无计划去除。
4、断点续做技术在NBU/OBS备份介质上面还没有打通,剩最后一公里,后续版本已有规划,届时NBU/OBS集群备份将会更加健壮。
数据仓库服务 GaussDB(DWS)
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。