如何通过OMS加快大表迁移至OceanBase

2024-05-10 06:36

本文主要是介绍如何通过OMS加快大表迁移至OceanBase,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

OMS,是OceanBase官方推出的数据迁移工具,能够满足众多数据迁移场景的需求,现已成为众多用户进行数据迁移同步的重要工具。OMS不仅支持多种数据源,还具备全量迁移、增量同步、数据校验等功能,并能够对分表进行聚合操作,例如将MySQL的分库分表数据通过OMS聚合到OceanBase数据库的单表中。

如需深入了解OMS的完整功能,请访问OceanBase的OMS文档进行进一步了解。

今日,我们的将主要介绍如何使用OMS迁移大表时,如何提升迁移速度。这在迁移历史库或归档库的数据时尤为重要,能够带来显著效益。接下来,我们将通过一个具体实例来探讨如何实现迁移过程的加速。

案例背景

最近遇到一个用户,使用 OMS 迁移 某数据到 OceanBase MySQL 模式,原表中的数据量大约有300+亿行,并且表存在longtext字段,这整体来看,是一个非常大的迁移工程,普通迁移也是至少耗时在周级别以上。用户在使用 OMS 迁移时,也遇到了很多问题:

  1. 原表中的表主键使用的是AUTO_RANDOM(5),这个是其源数据库特有的生成随机数方式,因为其分Region的方式是按range分,因此为了避免局部热点,需要随机生成。但是这样就导致一个问题,OMS在对源表进行切片时,效率非常差。
  2. OMS 在全量迁移时,会对表进行切片,根据主键的最大值和最小值,然后切分成多个分片分别进行迁移,因为表数据量非常大,导致分片数量非常多,影响迁移速度;
  3. OMS 日常迁移最快可以到30w行/秒,但是因为表中有longtext字段等原因,实测最多到1w行/秒,这样的迁移整体可能要超过1个月的时间;
  4. OMS 在写入目标端时,出现磁盘不足情况报错。

开始优化

问题1

首先,用户在 OMS 配置完迁移任务之后,发现迁移任务迟迟不开启同步,如下图,一直没有反应

这里因此对日志进行分析,查看 OMS 的 connetor.log 日志,发现在执行切片的 SQL 时,总是出现超时的报错,下面是报错的日志,日志的最后一条,就是执行切片的 SQL,可以看到会根据 id 字段进行一次排序。

The last packet successfully received from the server was 600,100 milliseconds ago.  The last packet sent successfully to the server was 600,098 milliseconds ago.
460 	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
461 	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
462 	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
463 	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
464 	at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
465 	at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:990)
466 	at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3562)
467 	at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3462)
468 	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3905)
469 	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2530)
470 	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2683)
471 	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2495)
472 	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:1903)
473 	at com.mysql.jdbc.PreparedStatement.executeQuery(PreparedStatement.java:2011)
474 	at com.alibaba.druid.pool.DruidPooledPreparedStatement.executeQuery(DruidPooledPreparedStatement.java:227)
475 	at com.oceanbase.oms.dataflow.jdbcclient.AbstractJDBCClient.nextSlicePkTop(AbstractJDBCClient.java:1438)
476 	at com.oceanbase.oms.dataflow.jdbcclient.AbstractJDBCClient.nextSlicePkTop(AbstractJDBCClient.java:1473)
477 	at com.oceanbase.oms.dataflow.slice.PkSliceService.lambda$slice$2(PkSliceService.java:207)
478 	... 6 common frames omitted
479 Caused by: java.net.SocketTimeoutException: Read timed out
480 	at java.net.SocketInputStream.socketRead0(Native Method)
481 	at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
482 	at java.net.SocketInputStream.read(SocketInputStream.java:171)
483 	at java.net.SocketInputStream.read(SocketInputStream.java:141)
484 	at com.mysql.jdbc.util.ReadAheadInputStream.fill(ReadAheadInputStream.java:101)
485 	at com.mysql.jdbc.util.ReadAheadInputStream.readFromUnderlyingStreamIfNecessary(ReadAheadInputStream.java:144)
486 	at com.mysql.jdbc.util.ReadAheadInputStream.read(ReadAheadInputStream.java:174)
487 	at com.mysql.jdbc.MysqlIO.readFully(MysqlIO.java:3011)
488 	at com.mysql.jdbc.MysqlIO.reuseAndReadPacket(MysqlIO.java:3472)
489 	... 17 common frames omitted
490 [2024-02-01 12:43:40.589] [INFO] [slice-worker-2] [SELECT  `id` FROM `xxx`.`xxx`  FORCE INDEX(`PRIMARY`)   ORDER BY `id` ASC LIMIT 1]

这里为什么执行切片。OMS 的全量迁移逻辑,首先默认会对源表的主键找到最大值和做小值,然后每600条数据(sliceBatchSize参数控制) 做一个分片,这样源表会切成多个分片,然后并发地同步多个分片到目标端,这样可以加快整个同步的任务。

因为表的数据量非常大,并且主键是 AUTO_RANDOM(5),因此要进行一次排序执行时间会很长,OMS 切片查询默认超时时间是 10 分钟,超时之后又会重试,因此这个 SQL 基本是执行不出来,所以迁移任务迟迟没有办法启动。

可以看到,想通过 OMS 自动来做切片,基本比较困难,因此这里第一个优化就是人工介入进行手动切片,这块在全量迁移的参数管理里有几个参数,可以帮助我们进行手动进行切片

source."sliceByMinMax"=true
source."sliceMinMaxValue"=5342,17870283355246524268
source."sliceBatchSize":6000
  • sliceByMinMax:设置为false,则表示人工手动设置最大值和最小值,而不是通过 SQL 去查;
  • sliceMinMaxValue:设置主键 id 字段的最大值和最小值,这个我们自己可以根据 SQL 查询结果设置;
  • sliceBatchSize:每个切片内的数据量

修改方式,在迁移任务的右上角-> 查看组件监控-> Full-Import 全量导入组件-> 点击更新,然后在source中加入这三个参数:

通过修改上面的参数,OMS 任务顺利运行起来了!

问题2

通过问题1的优化,虽然 OMS 迁移运行起来了,但是在执行一段时间之后发现,迁移任务又掉 0 了,并且持续时间很长

这里掉 0 之后,再次查看 connector.log 日志发现,因为我们手动设置了切片的最大值和最小值,而这个最大值和最小值相差比较大,所以在做分片的时候,因为很多切片区间是没有数据的,数据量为 0,所以在迁移这个切片时,实际没有数据迁移。

[2024-02-06 14:15:10.035] [INFO] [sourceTask-11] [xxx.xxx {xxx.xxx PK 13216115 [id:79296689342] - [id:79296695342]} rows : 0 , onNewBatchState:0.021]

实际这里 id 字段并不是连续递增的,因为 AUTO_RANDOM(5) 的缘故,导致表中 id 字段的最大最小值跨度非常大,但是小的值很多都是空的,所以 id 字段并不适合用来做切片。

因此是需要重新选择一个字段用来做切片的,经过对表结构分析,发现有个时间的字段比较适合来做切片 created double(20,8),字段保存的是:秒的时间戳+毫秒,用了double类型,时间精确到了毫秒,因为时间是连续的,并且跨度不大,基本每个时间段内都是有数据的,所以相比较来说是适合用来切片,并且上面有索引,切片查询是范围扫,不会太慢。

这里就需要另外修改一个参数,来指定切片使用这个字段

sliceIndex: {"库名.表名": "索引名:字段名"}

另外考虑到 sliceBatchSize 为 600,created字段每相差600秒内的数据量不能太大,否则每个切片数据量会比较大,迁移任务的jvm内存可能会撑爆。

因此重新调整参数之后如下:

source."sliceByMinMax"=true
source."sliceIndex"={"库名.表名": "索引名:created"}
source."sliceMinMaxValue"=1293595467,1707212258
source."sliceBatchSize":60

重新调整之后,恢复任务开始重新同步。

问题3

用户在遇到上面几个问题时,用的 OMS 版本还是4.2.1的版本,4.2.1 版本是不支持旁路导入的。旁路导入实际上是一个针对大表迁移的最优方式,旁路导入支持向 data 文件中直接写入数据,可以绕过 SQL 层的接口,直接在 data 文件中分配空间并插入数据,从而提高数据导入的效率,测试发现整体效率可以提升3-6倍。

这块因为在用户遇到这个问题时,OMS 4.2.2 版本即将发布,因此在让用户等了两天之后,将 OMS 升级到4.2.2 版本,开始使用旁路导入的方式。

旁路导入的配置也很简单,如下图,在配置 OMS 迁移任务时,在迁移选项中有个写入方式的选项,这里选择Direct Load方式,这样数据的迁移就会自动使用旁路导入的方式。

不过旁路导入这里有个问题,就是如果表中有数据,需要将数据清空之后再开始导入。即使旁路导入报错中断,如果要恢复迁移的话,也是需要重新清空表。

如何确认是否成功开启了旁路导入,这块可以在迁移任务的参数配置页面看到,如下图,出现direct.sink时,说明启动了旁路导入功能。

问题4

在任务开始一段时间后,OMS 收到报错

查看日志报错如下

[2024-02-21 05:37:06.473] [WARN] [sinkTask-27] [SyncSinkTask run ignore error, batch [com.oceanbase.oms.dataflow.common.stream.PartOfStreamRecordBatch
@67403183], cause [{}]]
java.lang.RuntimeException: Direct insert into "actions" failedat com.oceanbase.oms.connector.direct.sink.DirectPathWriter.flushRecords(DirectPathWriter.java:120)at com.oceanbase.oms.connector.direct.sink.DefaultDirectPathSink.offer(DefaultDirectPathSink.java:68)at com.oceanbase.connector.framework.threadmanager.sinktask.SyncSinkConnectorTask.run(SyncSinkConnectorTask.java:47)at java.lang.Thread.run(Thread.java:853)
Caused by: java.sql.SQLException: status : ERROR , error code : -4184at com.oceanbase.oms.connector.direct.sink.DirectPathConnection.insert(DirectPathConnection.java:233)at com.oceanbase.oms.connector.direct.sink.DirectPathPreparedStatement.executeBatch(DirectPathPreparedStatement.java:103)at com.oceanbase.oms.connector.direct.sink.DirectPathWriter.flushRecords(DirectPathWriter.java:95)... 3 common frames omitted

可以看到返回了4184的错误,查看 OceanBase 错误码,4184 的报错表示磁盘满了,实际这里只迁移了1亿多行,根据估算,是不能把磁盘写满的。

因此对每个磁盘的容量进行排查,发现每个 zone 只有 2 台机器上有流量,其他 4 台机器上基本没有写入流量,这里怀疑可能出现了数据的倾斜。但是这张表创建的是时候是做了分区,分区是均匀打散到所有机器上的,不应该出现倾斜。

继续排查发现,因为业务量随着时间不断增长,年份越近,数据量越大,分区打散虽然是按分区数量打散的,但是没有考虑到数据量的问题,可以看到2018年的数据量明显比2015年大很多。

而2018年的所有分区是集中在了一台机器上,导致这台机器的数据量非常大,这个是不符合预期的。经过验证,发现 OceanBase 目前在创建分区的时候,会以多个分区为一组,然后将这一组的分区集中到一台机器上,这个在range分区时有些不太合理。例如2018年按月有12个分区,一般情况下这12个分区应该在同一个zone中的6台机器上每台上有2个分区,同理2017年的分区也是这样。而实际时2017年的所有分区在一台机器上,2018年的所有分区在另一台机器上。这块和OceanBase官方确认之后,这块后续会做优化。

不过目前这种情况,有两种方式可以解决:

  1. 在创建二级分区,二级分区使用hash分区,进一步将分区打散;
  2. 手动迁移分区,迁移分区方式参考:Transfer Partition

因业务模型关系,这里无法做二级分区,否则会导致大量的跨机事务,因此只能选择手动迁移分区。

其他优化

优化1:

除了上面三个问题的解决,另外为了加快整体同步速度,这里还做了对JVM的调整,因为用户的 OMS 机器配置较高,所以默认的 JVM 参数无法全部发挥机器的性能。

调整 JVM 参数,同样也是在迁移任务的参数配置页面,修改如下

connectorJvmParam=-server -Xms64g -Xmx64g -Xmn60g -Xss512k 

优化2:

当资源充分的情况下,也可以修改 source 和 sink 端的 workNum 数量,默认是8,这里也是修改成了32

source.workNum: 32
sink.workNum: 32

优化后收益

经过以上这些优化之后,这张大表的迁移实时流量基本达到了 1.5G/s,RPS最高可以达到 61w行/s,可以看到整体收效明显,如果迁移正常的话,基本2-3天就可以完成这张大表的迁移。

这篇关于如何通过OMS加快大表迁移至OceanBase的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/975701

相关文章

CentOs7上Mysql快速迁移脚本

因公司业务需要,对原来在/usr/local/mysql/data目录下的数据迁移到/data/local/mysql/mysqlData。 原因是系统盘太小,只有20G,几下就快满了。 参考过几篇文章,基于大神们的思路,我封装成了.sh脚本。 步骤如下: 1) 先修改好/etc/my.cnf,        ##[mysqld]       ##datadir=/data/loc

CentOS下mysql数据库data目录迁移

https://my.oschina.net/u/873762/blog/180388        公司新上线一个资讯网站,独立主机,raid5,lamp架构。由于资讯网是面向小行业,初步估计一两年内访问量压力不大,故,在做服务器系统搭建的时候,只是简单分出一个独立的data区作为数据库和网站程序的专区,其他按照linux的默认分区。apache,mysql,php均使用yum安装(也尝试

Linux Centos 迁移Mysql 数据位置

转自:http://www.tuicool.com/articles/zmqIn2 由于业务量增加导致安装在系统盘(20G)磁盘空间被占满了, 现在进行数据库的迁移. Mysql 是通过 yum 安装的. Centos6.5Mysql5.1 yum 安装的 mysql 服务 查看 mysql 的安装路径 执行查询 SQL show variables like

风格控制水平创新高!南理工InstantX小红书发布CSGO:简单高效的端到端风格迁移框架

论文链接:https://arxiv.org/pdf/2408.16766 项目链接:https://csgo-gen.github.io/ 亮点直击 构建了一个专门用于风格迁移的数据集设计了一个简单但有效的端到端训练的风格迁移框架CSGO框架,以验证这个大规模数据集在风格迁移中的有益效果。引入了内容对齐评分(Content Alignment Score,简称CAS)来评估风格迁移

DataGrip数据迁移

第一步 第二步  第三步  第四步 选择你刚刚到处的文件即可

关于OceanBase MySQL 模式中全局索引 global index 的常见问题

在OceanBase的问答区和开源社区钉钉群聊中,时常会有关于全局索引 global index的诸多提问,因此,借这篇博客,针对其中一些普遍出现的问题进行简要的解答。 什么是 global index ? 由于 MySQL 不具备 global index 的概念,因此这一问题会经常被社区版用户提及。就在前几天,就要人询问下面这个语法的意义。 create table part_tes

从VC6迁移至VS2005 ,VS2008

最近开发平台由VC6.0升级至VS2005,需要将原有的项目迁移,特将碰到的问题归纳如下: 1消息映射 VS2005对消息的检查更为严格,以前在VC6下完全正常运行的消息映射在VS2005下编译不通过 a. ON_MESSAGE(message,OnMyMessage);   OnMyMessage返回值必须为LRESULT,其形式为:afx_msg LRESULT OnMyMessage(

基于人工智能的图像风格迁移系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像风格迁移是一种计算机视觉技术,它可以将一种图像的风格(如梵高的绘画风格)迁移到另一幅图像上,从而生成一幅具有特定艺术风格的图像。基于深度学习的图像风格迁移技术已经广泛应用于艺术创作、图像处理等领域。本文将介绍如何构建一个基于人工智能的图像风格迁移

gs_dump和gs_dumpall 迁移数据库

目录 0、源端实例收集AWR1、创建目录2、gs_dump - 业务停机3、gs_dumpall - 业务停机4、拷贝文件5、目标实例导入数据 0、源端实例收集AWR https://blog.csdn.net/hezuijiudexiaobai/article/details/134220949 1、创建目录 mkdir -p /pgdata/data/opengauss-

ASM 10G 基于RMAN 迁移

ASM 10G 基于RMAN 迁移 场景 单节点基于10G R2 的数据库,其数据文件及日志文件均存放在ASM 里,现在为业务需求,将此数据库做迁 移,迁移到另个机房,但是两个机房的网络是通畅的,为尽量减少数据的丢失及平稳迁移和经济实惠,迁 移时,数据库需停应用 工具 本次采用RMAN 的duplicate 命令来进行迁移,运用此命令简化复杂度; 一、源库和目标库的