文章详情

短信预约信息系统项目管理师 报名、考试、查分时间动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

异构数据库迁移埋下的 9 个大坑,你怎么还不会躲开?

2016-08-22 00:08

关注

异构数据库迁移埋下的 9 个大坑,你怎么还不会躲开?

在开源技术使用日益广泛的今天,笔者也可能突然被要求用一个新工具同步数据到一个新数据库,时间还可能更紧迫。到时怎么办呢?再愤怒一次吗?不了不了,还是脚踏实地总结一下,记下这些坑,日后类似项目,哪怕被拿着枪指着头也好,下述问题都要在前期阶段予以考虑。

作者介绍

黎君原,新炬网络架构师。

“贰过”,重犯同一过失的意思,语出《论语》,完整句子为“不迁怒不贰过”,乃仲尼对其不幸早逝的弟子颜回的极高评价。就it项目而言,从管理者的角度来说,一个错误犯两次,别说是同一个人了,哪怕是同一团队的不同人也不可接受。说到这里,不由得脑补出一位平时慈眉善目的老领导作嗔怒状,大喊“干掉干掉”的恐怖场面。不重犯同一错误真的很难吗,实话实说,确实难,君不闻,人类从历史中得到的最大教训就是从不吸取教训。

笔者上述感叹的背后是有故事的。那是本世纪最“2”的一天,笔者在排查Oracle到ADB(此处指ADB PG,全称AnalyticDB PostgreSQL版,是阿里的MPP架构的数据库)之间数据实时同步过程中,突然发现自己埋了个大雷——没区分空值和空字符串,导致同样的字段值在全量同步阶段标志为空字符串,增量同步阶段则标志为空值,这显然不是一种合乎逻辑的行为。

其实在发现这个问题前,笔者已经在这项目中苦苦挣扎了一个月,在此之前的两天,笔者自以为数据质量已经完全没问题,数据同步达到“又不是不能用”的境界了(笔者注:此处能用是真的能用,非为上线而上线那种能用)。Oracle DB本身确实不区分空值和空字符串,对于搞Oracle出身的工程师,没意识到这个似乎情有可原,然而笔者作为搬砖佬,已经前前后后搬了十几年,数据库异构迁移项目也认认真真地做过好几个,这件事对笔者而言,其实无异于“低级错误”。

回想起来,这个项目笔者做得甚是狼狈,这里面固然有进度紧以及新工具、新技术引入需要边学边用的客观因素,但这不足以平息笔者对自己的愤怒。问题来了,在开源技术使用日益广泛的今天,笔者也可能突然被要求用一个新工具同步数据到一个新数据库,时间还可能更紧迫。到时怎么办呢?再愤怒一次吗?不了不了,还是脚踏实地总结一下,记下这些坑,日后类似项目,哪怕被拿着枪指着头也好,下述问题都要在前期阶段予以考虑。

一、空值和空字符串

对于Oracle DB⽽⾔,空值和空字符串是同⼀回事,其中判断某个值是否为空值/空字符串统⼀使⽤"IS NULL"即可,⾄于=""是⽆效的。

这点对于其余数据库来说,可真不⼀定了。就源端为Oracle DB,⽬标端为其余数据库的项⽬⽽⾔,我们需要与开发商确认好,⽬标端究竟⽤哪种值表⽰源端的空值/空字符。⽽对于实时同步的项⽬来说,还需要在全量同步以及增量同步期间保持数据的⼀致。

除了空值和空字符串以外,其实还有⼀个隐藏的⼤boss——固定⻓度类型中的空格值。以Oracle DB为例,char类型⽤于存放固定⻓度的字符串,⽽⻓度不⾜的字符串则会被⾃动补充空格,对于这种值,⽆论是char_col=""还是char_col is null均⽆法识别,只能通过trim(char_col) is null识别,对此值使⽤length函数会返回本字段的⻓度,⼀个⾮0值。⽽这种数据同步到adb后则表现有⼀定差异了,char_col=""可以识别这种数据(哪怕ADB中也是⽤了固定⻓度的数据类型),然⽽对这个值使⽤char_length函数,结果会返回0,如果实在要把这种数据抓出来,我们还得加⼀个条件oct_length(char_col)>0。很明显,这⼜是⼀个坑!

二、数据类型转换问题

笔者的朋友阿强一直立志做一个温文儒雅的人,嗯,前提是不要让他“写材料”、“擦屁股”以及“估算工作量”!没错,“估算工作量”对他这种以txt狂魔自称的人来说是一种煎熬,光说起这个词,他已经脑补出把pm按在地上,一边揍一边说,“我想做个好人,为什么要逼我”?问题来了,如果让阿强估算这个数据类型转换的工作量,估计他连40米的刀都可以拿出来了。

跨数据库的表字段数据类型转换工作主要涉及“精度”、“效率”、以及“兼容性”等方面。部分数据同步软件确实具备自动转换的功能,然而这种情况,仅对于管理规范的数据库适用,不规范的库则需要耗费较大精力了,下面举几个典型的例子说明这个问题:

不要问为什么要在id类字段加空格:第一,这是合法的;第二,这未尝不是一种有创意的备份数据方法。这么干,真的,没毛病!

为什么是转换后?这又是另一个故事了,这里就不展开了,只提示个关键词,“预分区”。

嗯嗯,这明显是个坑。那种由开发商定表结构的项目得心存感激,真的!

三、字符集转换问题

字符集转换深究起来其实并不是容易的事情,几年前笔者所参与的一个O2O同步(即Oracle到Oracle的同步,下同) 迁移项目中,涉及了BIG5到UTF8的转换,当时的同步工具为OGG。这个项目中各种乱七八糟的数据至今仍然对笔者历历在目,当然,这也让笔者能更有经验地处理异构数据库同步中的字符集转换问题。

跨字符集转换的工作其实陷阱不少,因此,条件允许的话,笔者建议尽量规避。当然,遇到PG这种服务器端不支持GBK,而源端Oracle DB偏偏是GBK的情况,那只好迎难而上了,下面为笔者的建议:

四、特殊字符处理

对于数据库异构同步而言,特殊的字符,诸如单引号、双引号、换行、斜杠、反斜杠等等也是一个困扰项,这一点在数据全量同步阶段尤其明显。

对于文本方式的全量数据同步来说,我们可以考虑下述几种方式:

这些内容要说透,需要另外写一篇文章了。

五、异常记录处理

这里的异常记录,指的是那种本身就违反数据库规范,不应该插入到数据库中的记录。

以Oracle DB为例,笔者遇到的记录有异常日期格式以及异常数值两类。

六、全量同步测试

通常情况下,各种数据同步软件都会自带全量数据同步的功能,至于这个功能的效率、资源消耗、空间占用等项目需要进行评估。如果其不能满足需求,则可能需要考虑替代的手段。

在选取测试表的时候,笔者考虑综合下面几个因素选择几个测试表:

七、增量同步测试

作为数据同步项目,同步效率是一个重要因素,笔者建议在搭建完整的同步链路之前,拿数据变更频繁的关键表进行测试,通过单表单进程的方式,剔除潜在的配置不当风险。

对于这方面,笔者建议如下:

笔者这次测试通过Ogg同步增量数据,比较切合生产实际变更情况,这种方式可以参考。

八、数据一致性测试

数据一致性又是一个可以另外写一篇文章的话题,对此,笔者建议如下:

九、软件局限性

“越是漂亮的女人就越会骗人,记住啊!”

“不光是漂亮的女人不能相信,连貌似忠良的男人也不能相信。”

我觉得这段对话充分展示了一个产品的售前与售后的结局——殊途同归。对于售前来说,拼指标、造场景、讲故事等等手段都是为了证明我家产品很棒,快来买买买;就售后而言,找到产品的痛点,予以规避,以达到保证工作顺利开展,避免一口大锅从天而降的目的。大家都是靠博弈而生的,没什么两样,手里的牌均是对技术的了解。

扯远了,回到it项目中,异构数据库的同步往往是逻辑的同步方式,这种方式必然有各种瓶颈的。对售后来说,再怎么谩骂售前“管杀不管埋”也无济于事,最现实的做法莫过于:找到短板,通过改善流程、优化需求甚至协同开发商改造应用的方式保证软件的稳定运行。

这里先讲个故事。Timesten是Oracle的内存数据库,其Cachegroup功能可以实现从物理库(即Oracle DB)到内存库的实时数据同步,而这个同步延迟对业务稳定运行是非常关键的。在实际使用中,运维人员总结出的经验就是得规避大事务变更,最终他们与开发商达成相应的操作规范,无论是业务变更需求也好,数据库运维发起的清理作业也罢,如涉及Timestens同步的表,都得遵循变更量达10w万就得分批提交,每个批次2万条记录,每批次之间sleep 30秒的硬性规定。我觉得这个故事的结局很完满了,真的,要是换成非得揪着Timesten不放,意图纯粹靠软件解决问题的话,那才是妥妥的灾难现场呢,毕竟其基于trigger的同步机制从原理上就对大事务极不友好……

问题来了,如何找到软件的短板呢?

阅读官方文档自然是一个渠道,当然,阅读也是有“技巧” 的 :

这个嘛,春秋笔法是有的,这种玩法自古就有了。陈寿不也没在《三国志》里面明说司马昭弑君吗,后来大家不都知道了吗?

除了文档以外,我们还可以考虑结合自身经验考虑下述点。

分别对同步范围内外的对象做批量操作,加大数据库日志量,观察其对数据同步以及系统的影响,具体包括cpu、内存、io、空间等资源消耗以及同步延迟等。

以dts为例,源端oracle数据库产生的所有数据均会被拉到dts的库中分析,哪怕这数据与我们的同步策略无关。

目前有个黑名单功能可以绕过这问题。

包含启动增量同步前开启的事务能否正常同步、长时间未提交的事务是否影响同步进程重启等维度。

很明显, 这是被ogg吓到的结果。

笔者曾在O2O同步环境中遇到某应用使用了大量with as语法,后者隐式开启了大量的短事务,进而短时间内事务量暴涨,进而 导致同步软件Ogg抽取进程出现延迟。这个问题后来找开发商修改语句就解决了,然而其对笔者的心理阴影一直都在,以至于每遇到一个新场景,均会想想会不会遇到类似的问题。

这个探究的是,软件同步是否能保持事务的顺序,如不能保持,那就得多留个心眼了,这种情况轻则导致同步延迟误判,重则导致旧 数据覆盖新数据,影响数据一致性。

一个简单的测试样例为,创建一个周期性(如每分钟)更新的时间戳表,这个表的记录数与源端Oracle DB的节点数一致。定时脚本依次连接各个实例并以当前时间更新相应的字段,在目标端,我们可以通过查询时间点表观察会不会出现下面两种情况:

对于基于数据库日志的同步工具,大批量的DDL语句很可能会触发源端解析缓慢的情况,毕竟这涉及与数据字典的交互。

笔者曾遇过某个基于Ogg的O2O同步环境遇到这种瓶颈,而最终的解决方案为调整开发商版本上载的脚本,加大DDL语句之间等待时间间隔。

对于基于rowid的同步方案,没啥好说的,只能从规范上减少move、shrink等改变rowid操作,实在要操作的话,需要重新同步相应的数据。

对于基于主键的同步方案,则重点考虑如何处理无主键表如何处理。

包含两种场景,正常重启以及异常重启。

异常重启即高可用方面的,具体不展开了;至于正常重启的话,需要观察进程的一些自定义参数会不会被重置。

 

 

 

作者介绍

黎君原,新炬网络架构师。

“贰过”,重犯同一过失的意思,语出《论语》,完整句子为“不迁怒不贰过”,乃仲尼对其不幸早逝的弟子颜回的极高评价。就it项目而言,从管理者的角度来说,一个错误犯两次,别说是同一个人了,哪怕是同一团队的不同人也不可接受。说到这里,不由得脑补出一位平时慈眉善目的老领导作嗔怒状,大喊“干掉干掉”的恐怖场面。不重犯同一错误真的很难吗,实话实说,确实难,君不闻,人类从历史中得到的最大教训就是从不吸取教训。

笔者上述感叹的背后是有故事的。那是本世纪最“2”的一天,笔者在排查Oracle到ADB(此处指ADB PG,全称AnalyticDB PostgreSQL版,是阿里的MPP架构的数据库)之间数据实时同步过程中,突然发现自己埋了个大雷——没区分空值和空字符串,导致同样的字段值在全量同步阶段标志为空字符串,增量同步阶段则标志为空值,这显然不是一种合乎逻辑的行为。

其实在发现这个问题前,笔者已经在这项目中苦苦挣扎了一个月,在此之前的两天,笔者自以为数据质量已经完全没问题,数据同步达到“又不是不能用”的境界了(笔者注:此处能用是真的能用,非为上线而上线那种能用)。Oracle DB本身确实不区分空值和空字符串,对于搞Oracle出身的工程师,没意识到这个似乎情有可原,然而笔者作为搬砖佬,已经前前后后搬了十几年,数据库异构迁移项目也认认真真地做过好几个,这件事对笔者而言,其实无异于“低级错误”。

回想起来,这个项目笔者做得甚是狼狈,这里面固然有进度紧以及新工具、新技术引入需要边学边用的客观因素,但这不足以平息笔者对自己的愤怒。问题来了,在开源技术使用日益广泛的今天,笔者也可能突然被要求用一个新工具同步数据到一个新数据库,时间还可能更紧迫。到时怎么办呢?再愤怒一次吗?不了不了,还是脚踏实地总结一下,记下这些坑,日后类似项目,哪怕被拿着枪指着头也好,下述问题都要在前期阶段予以考虑。

一、空值和空字符串

对于Oracle DB⽽⾔,空值和空字符串是同⼀回事,其中判断某个值是否为空值/空字符串统⼀使⽤"IS NULL"即可,⾄于=""是⽆效的。

这点对于其余数据库来说,可真不⼀定了。就源端为Oracle DB,⽬标端为其余数据库的项⽬⽽⾔,我们需要与开发商确认好,⽬标端究竟⽤哪种值表⽰源端的空值/空字符。⽽对于实时同步的项⽬来说,还需要在全量同步以及增量同步期间保持数据的⼀致。

除了空值和空字符串以外,其实还有⼀个隐藏的⼤boss——固定⻓度类型中的空格值。以Oracle DB为例,char类型⽤于存放固定⻓度的字符串,⽽⻓度不⾜的字符串则会被⾃动补充空格,对于这种值,⽆论是char_col=""还是char_col is null均⽆法识别,只能通过trim(char_col) is null识别,对此值使⽤length函数会返回本字段的⻓度,⼀个⾮0值。⽽这种数据同步到adb后则表现有⼀定差异了,char_col=""可以识别这种数据(哪怕ADB中也是⽤了固定⻓度的数据类型),然⽽对这个值使⽤char_length函数,结果会返回0,如果实在要把这种数据抓出来,我们还得加⼀个条件oct_length(char_col)>0。很明显,这⼜是⼀个坑!

二、数据类型转换问题

笔者的朋友阿强一直立志做一个温文儒雅的人,嗯,前提是不要让他“写材料”、“擦屁股”以及“估算工作量”!没错,“估算工作量”对他这种以txt狂魔自称的人来说是一种煎熬,光说起这个词,他已经脑补出把pm按在地上,一边揍一边说,“我想做个好人,为什么要逼我”?问题来了,如果让阿强估算这个数据类型转换的工作量,估计他连40米的刀都可以拿出来了。

跨数据库的表字段数据类型转换工作主要涉及“精度”、“效率”、以及“兼容性”等方面。部分数据同步软件确实具备自动转换的功能,然而这种情况,仅对于管理规范的数据库适用,不规范的库则需要耗费较大精力了,下面举几个典型的例子说明这个问题:

不要问为什么要在id类字段加空格:第一,这是合法的;第二,这未尝不是一种有创意的备份数据方法。这么干,真的,没毛病!

为什么是转换后?这又是另一个故事了,这里就不展开了,只提示个关键词,“预分区”。

嗯嗯,这明显是个坑。那种由开发商定表结构的项目得心存感激,真的!

三、字符集转换问题

字符集转换深究起来其实并不是容易的事情,几年前笔者所参与的一个O2O同步(即Oracle到Oracle的同步,下同) 迁移项目中,涉及了BIG5到UTF8的转换,当时的同步工具为OGG。这个项目中各种乱七八糟的数据至今仍然对笔者历历在目,当然,这也让笔者能更有经验地处理异构数据库同步中的字符集转换问题。

跨字符集转换的工作其实陷阱不少,因此,条件允许的话,笔者建议尽量规避。当然,遇到PG这种服务器端不支持GBK,而源端Oracle DB偏偏是GBK的情况,那只好迎难而上了,下面为笔者的建议:

四、特殊字符处理

对于数据库异构同步而言,特殊的字符,诸如单引号、双引号、换行、斜杠、反斜杠等等也是一个困扰项,这一点在数据全量同步阶段尤其明显。

对于文本方式的全量数据同步来说,我们可以考虑下述几种方式:

这些内容要说透,需要另外写一篇文章了。

五、异常记录处理

这里的异常记录,指的是那种本身就违反数据库规范,不应该插入到数据库中的记录。

以Oracle DB为例,笔者遇到的记录有异常日期格式以及异常数值两类。

六、全量同步测试

通常情况下,各种数据同步软件都会自带全量数据同步的功能,至于这个功能的效率、资源消耗、空间占用等项目需要进行评估。如果其不能满足需求,则可能需要考虑替代的手段。

在选取测试表的时候,笔者考虑综合下面几个因素选择几个测试表:

七、增量同步测试

作为数据同步项目,同步效率是一个重要因素,笔者建议在搭建完整的同步链路之前,拿数据变更频繁的关键表进行测试,通过单表单进程的方式,剔除潜在的配置不当风险。

对于这方面,笔者建议如下:

笔者这次测试通过Ogg同步增量数据,比较切合生产实际变更情况,这种方式可以参考。

八、数据一致性测试

数据一致性又是一个可以另外写一篇文章的话题,对此,笔者建议如下:

九、软件局限性

“越是漂亮的女人就越会骗人,记住啊!”

“不光是漂亮的女人不能相信,连貌似忠良的男人也不能相信。”

我觉得这段对话充分展示了一个产品的售前与售后的结局——殊途同归。对于售前来说,拼指标、造场景、讲故事等等手段都是为了证明我家产品很棒,快来买买买;就售后而言,找到产品的痛点,予以规避,以达到保证工作顺利开展,避免一口大锅从天而降的目的。大家都是靠博弈而生的,没什么两样,手里的牌均是对技术的了解。

扯远了,回到it项目中,异构数据库的同步往往是逻辑的同步方式,这种方式必然有各种瓶颈的。对售后来说,再怎么谩骂售前“管杀不管埋”也无济于事,最现实的做法莫过于:找到短板,通过改善流程、优化需求甚至协同开发商改造应用的方式保证软件的稳定运行。

这里先讲个故事。Timesten是Oracle的内存数据库,其Cachegroup功能可以实现从物理库(即Oracle DB)到内存库的实时数据同步,而这个同步延迟对业务稳定运行是非常关键的。在实际使用中,运维人员总结出的经验就是得规避大事务变更,最终他们与开发商达成相应的操作规范,无论是业务变更需求也好,数据库运维发起的清理作业也罢,如涉及Timestens同步的表,都得遵循变更量达10w万就得分批提交,每个批次2万条记录,每批次之间sleep 30秒的硬性规定。我觉得这个故事的结局很完满了,真的,要是换成非得揪着Timesten不放,意图纯粹靠软件解决问题的话,那才是妥妥的灾难现场呢,毕竟其基于trigger的同步机制从原理上就对大事务极不友好……

问题来了,如何找到软件的短板呢?

阅读官方文档自然是一个渠道,当然,阅读也是有“技巧” 的 :

这个嘛,春秋笔法是有的,这种玩法自古就有了。陈寿不也没在《三国志》里面明说司马昭弑君吗,后来大家不都知道了吗?

除了文档以外,我们还可以考虑结合自身经验考虑下述点。

分别对同步范围内外的对象做批量操作,加大数据库日志量,观察其对数据同步以及系统的影响,具体包括cpu、内存、io、空间等资源消耗以及同步延迟等。

以dts为例,源端oracle数据库产生的所有数据均会被拉到dts的库中分析,哪怕这数据与我们的同步策略无关。

目前有个黑名单功能可以绕过这问题。

包含启动增量同步前开启的事务能否正常同步、长时间未提交的事务是否影响同步进程重启等维度。

很明显, 这是被ogg吓到的结果。

笔者曾在O2O同步环境中遇到某应用使用了大量with as语法,后者隐式开启了大量的短事务,进而短时间内事务量暴涨,进而 导致同步软件Ogg抽取进程出现延迟。这个问题后来找开发商修改语句就解决了,然而其对笔者的心理阴影一直都在,以至于每遇到一个新场景,均会想想会不会遇到类似的问题。

这个探究的是,软件同步是否能保持事务的顺序,如不能保持,那就得多留个心眼了,这种情况轻则导致同步延迟误判,重则导致旧 数据覆盖新数据,影响数据一致性。

一个简单的测试样例为,创建一个周期性(如每分钟)更新的时间戳表,这个表的记录数与源端Oracle DB的节点数一致。定时脚本依次连接各个实例并以当前时间更新相应的字段,在目标端,我们可以通过查询时间点表观察会不会出现下面两种情况:

对于基于数据库日志的同步工具,大批量的DDL语句很可能会触发源端解析缓慢的情况,毕竟这涉及与数据字典的交互。

笔者曾遇过某个基于Ogg的O2O同步环境遇到这种瓶颈,而最终的解决方案为调整开发商版本上载的脚本,加大DDL语句之间等待时间间隔。

对于基于rowid的同步方案,没啥好说的,只能从规范上减少move、shrink等改变rowid操作,实在要操作的话,需要重新同步相应的数据。

对于基于主键的同步方案,则重点考虑如何处理无主键表如何处理。

包含两种场景,正常重启以及异常重启。

异常重启即高可用方面的,具体不展开了;至于正常重启的话,需要观察进程的一些自定义参数会不会被重置。

本文来自云海天,作者:古道轻风,转载请注明原文链接:https://www.cnblogs.com/88223100/p/9_big_pits_buried_by_heterogeneous_database_migration.html

原文地址:https://www.cnblogs.com/88223100/archive/2022/03/16/9_big_pits_buried_by_heterogeneous_database_migration.html

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯