【脱敏迁移】两种脱敏迁移模式的再思考
在近期从事的数据库表迁移脱敏工作中,我逐渐归纳出两种迁移方式:
一.BlockMigrater:这种模式是一行行读取ResultSet的内容,凑足一万行后向目标库提交,提交完毕后再继续读取,再提交,直到处理完所有数据;
二.UnblockMigrater:这种模式读取时还是一行行读取ResultSet的内容,凑足一万行后使用线程/线程池向目标端异步提交,主线程不阻塞,马上就再读取提交....;
按普遍的认知来说,第二种方式会更快,因为读取源端和写入目标端是异步进行的,互不阻滞。
但这是理想中情况,前提是分支的写线程比读线程快很多。如果不满足这个条件,UnblockMigrater就容易出乱子。
笔者的环境中有两种DB,Oracle和greenplum,简称o和pg,源端和目标端DB是二者之一。
从读写速度方面来说,使用jdbc的ExecuteBatch方式写一万行数据进oracleDB比读取一万行快很多,因此UnblockMigrater在两端都是Oracle数据库时能充分展现优势;
而pg数据库的读取速度要高于Oracle约五成,而写速度慢得让人发指,是同等条件下oracle库的十分之一到百分之一。
当pg作为源端,oracle作为目标端,数据量超过四五百万行记录时,如果使用UnblockMigrater进行迁移,会出现堆内存耗尽异常,我猜是读取速度较快,大批写线程携带万行数据在线程池外或是目标端外等待,不断堆积导致的堆内存耗尽;
当pg或oracle作为源端,pg作为目标端,这时pg写入慢的弊端就彻底显现了,堆内存耗尽很快会发生,原因和上面一样,都是大批等待的写线程携带的数据把内存耗尽了。
到这里,可以发现,多线程程序并非就比单线程好,不考察读写速度的差异,多线程也会带来麻烦。
在找到更好的办法前,我换用了BlockMigrater来应对上面两种情况,程序如期在平稳中完成了任务。
这并不出人意料,因为写数据时就万行,写完就置空让gc回收了,用完一万就释放,没有多个线程把着不放的事发生,这就不会导致堆内存耗尽异常。
虽然BlockMigrater模式写数据时读取在等待,但整体速度也可以,一千三百万行数据,70字段的表从pg迁移到o端,虚拟机上只用20分钟,这用户也能接受。
但用户接受不了出错,锁死和OOM,因此我在源端或目标端存在PG时就使用BlockMigrater类,在两端都是Oracle时采用UnblockMigrater类。
事后看来,BlockMigrater类是最先采用的,也是最经得起考验的方式,无论数据量大小,无论DB类型是什么,它都能稳定地完成任务,速度也能让人接受,故我将其改名为StableMigrater;
UnblockMigrater是后采用的,虽然在两端都是Oracle即写入远快于读取时能达到高速,但应用面窄,以其速度命名为FastMigrater。
二者可能要并存下去,也存在前者独霸天下的可能,实际运行效果就是砝码。
END