一、前言
说一下我和崖山数据库的结缘,大概在去年吧,因为我经常在墨天轮写文章,看到崖山数据库推出了一崖山体验官的活动,我就报名参加了。第一次体验了崖山数据库,也测试了我司数据库到崖山数据库的兼容性,发现崖山数据库的兼容性真的很不错的,尤其是对Oracle的兼容性做的真的挺不错。而且崖山数据库的一些命令和Oracle很兼容,对一些Oracle DBA来说上手特别容易,甚至可以说是无缝衔接。
最近受崖山数据库邀请做为【YashanDB迁移体验官】,体验了一把YMP的迁移,我也搭建了测试环境,并验证了我司一些Oracle和MySQL到崖山数据库的迁移,并参与了上周五崖山的直播和大家分享了YMP的迁移感受。
在验证测试中也发现了一些YMP的问题,也将这些问题反馈了崖山官方技术人员,他们的响应速度也是非常快,对于反馈的一些问题有些已经提交研发进行修复,给他们点个大大的赞。
下面我将为大家附上我本次迁移测试的全过程,以及对YMP的迁移感受。不足之处还望大家多多指正。
也希望大家多多支持崖山,多多支持国产数据库,只有大家齐心协力,国产数据库的将来才会越来越好。
1.1 产品介绍
根据崖山官网介绍,崖山迁移平台(Yashan Migration Platform),简称YMP,是YashanDB提供的数据库迁移产品,支持异构RDBMS与YashanDB之间进行迁移评估、离线迁移、数据校验的功能。另外,YMP提供页面可视化服务,使用者只需通过一些简单的界面操作,即可完成从评估到迁移到数据一致性评估整个流程的执行与监控,整个操作过程门槛比较低,操作比较流畅。
YMP安装后,会集成一个YashanDB内置库,该内置库的作用是用于YMP进行校验评估是需要的,不能作为业务目标库使用,建议在做数据迁移时,单独部署一套YashanDB(目标端业务库),
内置库是用于ymp在迁移评估阶段待迁移元数据的兼容度评估,不能作为业务目标库使用,做数据同步测试,部署一套YashanDB(目标端业务库)和YMP自嵌的内置库是很规范的。
当前YMP支持(Oracle、MySQL、DM)等异构库到YashanDB的迁移,也支持YashanDB到YashanDB的同构迁移。
YMP整个迁移过程包括如下 六 个主要阶段,如下图所示:
这六个主要阶段分别是:
- 创建任务
- 迁移评估
- 迁移配置
- 离线迁移
- 校验初始化
- 一致性校验
1.2 产品架构
在崖山官网,有如下一幅图介绍YMP的检品架构,如下所示:
根据上面产品架构显示,主要包括了(对象评估、元数据迁移、数据迁移、数据校验)等几个核心服务。
1.3 数据库版本支持
根据官网资料介绍,当前最新版YMP版本为YMP 23.2,其对异构和同构数据库有一定的版本限制,详见如下:
数据库 | 说明 |
---|---|
YashanDB | 适配YashanDB数据库v23.2版本,形态支持单机、共享集群,并兼容YashanDB数据库v22.2版本。 |
Oracle | 支持的版本为 11g,12c,19c,21c,部署形态为单机和RAC。 |
MySQL | 支持的版本为 5.6,5.7,8.0。 |
DM | 支持的版本为 8。 |
另外在官网【https://doc.yashandb.com/ymp/23.2/zh/产品简介/产品规格】链接页面中,也有对异构RDBMS库相应数据类型的支持。
二、外置库部署
部署外置库的目的是为将迁移评估后源端数据迁移到YashanDB后的目标端库,为保证迁移顺利,外置库存放数据目录一定要有足够存储空间。
建议将外置库和YMP内置库分开部署,推荐是将内置库和外置库部署在不同服务器上,若部署在同一台服务器,使用不同用户部署外置库和内置库。
因为条件限制,我本次选择在同一台物理测试服务器上部署外置库和YMP,两者分别部署在不同用户下,外置库选择部署在yashan用户下,内置库部署在ymp用户下。
对于外置库的安装部署,在官方文档【https://doc.yashandb.com/yashandb/23.2/zh/产品描述/产品简介.html】里有详细的介绍,本次就不再做过多赘述,只是简单描述整个安装部署过程。
1) 软件下载:
截止到2024-04-25日,当前YashanDB最新版本为23.2,可在官网主页【https://www.yashandb.com/】,点击**【免费下载】根据操作系统类型下载YashanDB 个人版**,当前可供下载的类型包括X86和ARM两种类型。
2)环境准备:
环境准备包括服务器系统及网络规划、系统参数调整、目录及用户规划等,服务器和操作系统的配置要满足官网服务器配置需求。
3)软件安装:
崖山数据库的安装方式有命令行安装和可视化安装两种类型,数据库安装类型有(单机主备部署、分布式部署、共享集群部署)这三种部署形态,可以按照自己的业务需求选择相应的部署方式。
4)初始化环境:
数据库安装部署后,需要设置环境变量、初始数据库。如在安装过程中未对监听端口进行调整,默认监听端口为1688。可根据需要设置是否开机启动,实例如下。
[yashan@dsmart install]$ ./bin/yasboot package se gen --cluster yashandb -u yashan -p yashan --ip 10.110.8.42 --port 22 --install-path /data/yashan/yasdb_home --data-path /data/yashan/yasdb_data --begin-port 1688
hostid | group | node_type | node_name | listen_addr | replication_addr | data_path
----------------------------------------------------------------------------------------------------------
host0001 | dbg1 | db | 1-1 | 10.110.8.42:1688 | 10.110.8.42:1689 | /data/yashan/yasdb_data
----------+-------+-----------+-----------+------------------+------------------+-------------------------
Generate config success
**补充:**安装YashanDB时,可通过指定-d, --child
参数,展示任务以及子任务信息,以便了解部署进度。,如下所示:
[yashan@dsmart install]$ ./bin/yasboot cluster deploy -t yashandb.toml -d --child
type | uuid | name | hostid | index | status | return_code | progress | cost
------------------------------------------------------------------------------------------------------------------------
task | 274c34dbc58b9cbd | DeployYasdbCluster | - | yashandb | SUCCESS | 0 | 100 | 9
-------+------------------+--------------------+----------+-------------------+---------+-------------+----------+------
child | 9d1fafb987ad2b56 | DeployDBPrimary | host0001 | yashandb.1-1 | SUCCESS | 0 | 100 | 6
+------------------+--------------------+----------+-------------------+---------+-------------+----------+------
| 12f5e1c9e1bfd015 | SyncNodeConfig | - | yashandb | SUCCESS | 0 | 100 | 1
+------------------+--------------------+----------+-------------------+---------+-------------+----------+------
| cba90435323b808c | MonitReload | host0001 | yashandb-host0001 | SUCCESS | 0 | 100 | 1
-------+------------------+--------------------+----------+-------------------+---------+-------------+----------+------
task completed, status: SUCCESS
# 返回 task completed, status: SUCCESS 表示安装成功
三、YMP部署
在官网【https://doc.yashandb.com/ymp/23.2/zh/产品简介/产品概述.html】有详细对YMP的安装部署介绍,这里根据官网文档做简要介绍。
3.1 安装前准备:
服务器配置: 安装YMP的服务器要满足官网配置要求,详见如下:
项目 | 说明 |
---|---|
系统 | CentOS 7.6以上、KylinOS V10 |
架构 | X86-64/ARM-64 |
CPU | 4核及以上 |
内存 | 8G及以上 |
磁盘 | SSD(建议不小于待同步表中的最大单表数据量的三倍) |
操作系统参数调整: 需确保操作系统max user processes最大用户线程数不小于65535。
# 查看最大用户线程数 # ulimit -u # 执行如下命令使最大用户线程数临时生效,重启后无效 # ulimit -u 65536 # 执行执行如下命令将最大用户线程数写入/etc/security/limits.conf文件,重启后参数永久生效 echo " * soft nproc 65536 * hard nproc 65536 " >> /etc/security/limits.conf
**用户准备:**创建一个用户用于安装YMP,以YMP为例,在用户创建和授权后,后续所有安装步骤均在该用户下操作。
# 新建YMP用户 # useradd -d /home/ymp -m ymp # passwd ymp
开放端口: 如未进行调整,YMP将采用如下端口。
YMP监听 | 数据库监听 | 主机间通信 | yasom | yasagent |
---|---|---|---|---|
8090 | 8091 | 8092 | 8093 | 8094 |
如无特殊需求,建议关闭服务器防火墙:
# 关闭防火墙 # systemctl stop firewalld # 关闭开机自启 # systemctl disable firewalld
**JDK环境准备:**YMP仅支持在JDK8或JDK11的环境下安装。
通过Java官方路径下载上述版本的JDK并安装成功后,还需配置如下环境变量:
# 以JDK安装路径为/usr/tools/jdk8为例 # vi /etc/profile # 在文件结尾添加如下 # export JAVA_HOME=/usr/tools/jdk8 # export PATH=$JAVA_HOME/bin:$PATH # export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar # 重新载入配置文件 # source /etc/profile # 安装成功后查看JDK版本信息 # java -version
**libaio环境准备:**YMP运行需要libaio动态库。
# 查看是否已安装libaio动态库 # rpm -qa | grep libaio # 若未有版本信息打印,安装libaio # yum install -y libaio
OCI环境准备(可选): 若用YMP迁移Oracle到YashanDB数据库,需要安装OCI环境。
到Oracle官网【https://www.oracle.com/database/technologies/instant-client/linux-x86-64-downloads.html#license-lightbox】下载OCI 客户端软件。
YMP当前仅支持 OCI Version 19.19.0.0.0及以上版本。
上传安装包至YMP用户/home/ymp/路径。
# 修改安装包所属用户及用户组为ymp用户 # chown ymp:ymp instantclient-xxx # 从root用户切换至ymp用户 # su - ymp # 切换至安装路径 $ cd /home/ymp # 解压OCI安装包 $ unzip instantclient-xxx
软件包准备:请根据自己操作系统选择对应YMP软件安装包,当前YMP有Linux X86和Linux ARM两个版本,最新版为 Yashan Migration Platform 23.2.1版本。
将下载的YMP软件包上传到服务器/home/ymp用户。
#修改安装包所属用户及用户组为ymp用户 # chown ymp:ymp yashan-migrate-platform-v23.2.1.0-linux-x86-64.zip # 从root用户切换至ymp用户 # su - ymp # 切换至安装路径 $ cd /home/ymp
客户端浏览器: YMP的操作需要浏览器支持,YMP支持当前主流浏览器,参照如下:
YMP支持浏览器Google Chrome、Microsoft Edge和Firefox,建议使用当前较新的版本。
浏览器支持 | 要求版本 |
---|---|
Google Chrome | 88 及以上版本 |
Microsoft Edge | 88 及以上版本 |
Firefox | 78 及以上版本 |
3.2 安装YMP
**1) 解压YMP安装包:****使用ymp用户解压YMP安装包,操作如下:
# 切换至YMP安装目录 # su - ymp $ cd /home/ymp/ $ unzip yashan-migrate-platform-v23.2.1.0-linux-x86-64.zip
**2)安装参数调整:****可依据实际需要对默认内置库安装端口、启动参数、密码登进行设置,其中有两个文件非常重要,如下所示:
# 文件所在目录 /home/ymp/yashan-migrate-platform/conf
db.properties: 默认内置库安装配置文件,里面包含内置库sys默认密码,默认端口号,默认字符集(UTF8),详细内容如下:
YASDB_PASSWORD=ymppw602.
YASDB_PORT=8091
YASDB_CHARACTER_SET=UTF8
## character_set optional: UTF8, ASCII, ISO88591, GBK
application.properties: YMP配置文件,该文件包含内容较多,详细内容如下
# YMP服务端口
server.port=8090
# 用户登录后空闲过期时间,单位秒(s),默认15分钟
shiro.session.timeout=900
# YMP使用的最大堆内存,单位: GB
ymp_memory=4
# YMP使用的堆外内存,单位: GB
ymp_direct_memory=2
# ========================================YMP业务数据库=============================================
# YMP业务数据库连接信息
spring.datasource.url=jdbc:yasdb://127.0.0.1:8091/yashan
spring.datasource.username=YMP_DEFAULT
spring.datasource.password=ymppw602
spring.datasource.largePoolSize=64M
spring.datasource.cursorPoolSize=64M
# 默认内置库表类型,默认HEAP,可选HEAP,TAC,LSC
spring.datasource.defaultTableType=HEAP
spring.datasource.openCursors=3000
spring.datasource.sharePoolSize=2G
spring.datasource.dateFormat=yyyy-mm-dd hh24:mi:ss
spring.datasource.ddlLockTimeout=2
# ========================================评估=============================================
# YMP的最大并行任务数
task.parallel.max-num=500
# 预计数据迁移速度,KB/s。修改会影响评估结果预计迁移时间的大小
commons.dataMigrateSpeed=51200
# 预计对象迁移速度,number/s。修改会影响评估结果预计迁移时间的大小
commons.objMigrateSpeed=200
# 评估任务单个会话获取DDL的数量,如果Oracle性能较差,则需要降低该值
assessment.ddlCount=50
# 评估任务最多同时拥有的会话数,如果Oracle性能较差,则需要降低该值
assessment.maxThreadCount=20
# 内置库表类型是否为LSC,默认为false
isLscTable=false
# 拦截的Oracle数据源db/schema黑名单
schemaBlackList.oracle=ANONYMOUS,APEX_030200,APEX_PUBLIC_USER,APPQOSSYS,BI,CTXSYS,DBSNMP,DIP,EXFSYS,FLOWS_FILES,HR,IX,MDDATA,MDSYS,MGMT_VIEW,OE,OLAPSYS,ORACLE_OCM,ORDDATA,ORDPLUGINS,ORDSYS,OUTLN,OWBSYS,OWBSYS_AUDIT,PM,SCOTT,SH,SI_INFORMTN_SCHEMA,SPATIAL_CSW_ADMIN_USR,SPATIAL_WFS_ADMIN_USR,SYS,SYSMAN,SYSTEM,WMSYS,XDB,XS$NULL
# 拦截的MySQL数据源db/schema黑名单
schemaBlackList.mysql=information_schema,mysql,performance_schema,sys
# 拦截的dm数据源db/schema黑名单
schemaBlackList.dm=SYS,SYSDBA,SYSSSO,SYSAUDITOR,CTISYS
# ========================================迁移=============================================
# 元数据迁移过程中源端、目标端查询视图连接数。在元数据迁移过程中会有分批量的查询的动作, 需要开启多个查询连接并行查询。该参数配置元数据迁移的源端、目标端查询的并行线程数,决定了对数据库的查询最大连接数,不设置默认20
migration.parallel.query=20
# 元数据迁移过程中目标端执行创建连接数。在元数据迁移过程中会并行把对象在目标端的执行,以提升迁移效率。该参数配置元数据迁移的目标端DDL执行的并行线程数,决定了连接数据库的执行最大连接数,不设置默认20。migration.parallel.query和migration.parallel.execute的连接总和,是最终迁移过程中所有的目标端数据库连接数。
migration.parallel.execute=20
# 创建索引是否使用并行参数,true/TRUE:使用,false/FALSE:不使用
migration.parallel.createIndexUseParallel=true
# 索引创建的并行度,需要考虑migration.parallel.execute。例:migration.parallel.execute:10,migration.parallel.index: 5,表示,同时10个连接在并行建索引,每个索引的并行度是5(CREATE INDEX XXX PARALLEL 5)。不填默认CPU核数。
migration.parallel.index=5
# 数据迁移前是否将表设为nologging,默认为false
setNoLogging=false
# 导出oracle时使用的导出方式,支持 [dts, jdbc] 两种方式
export.oracle.tool=dts
# 导出时每个csv文件的行数
export.csv.exportRowsEveryFile=2000000
# 迁移成功时候是否删除csv文件
export.csv.isRemoveCsvFileInSuccess=true
# csv文件存储路径包含对schema和table的拼接,schema名或table名中包含以上字符时,将会被替换,以避免被操作系统识别错误导致迁移失败;不过这可能会使某些表(比如AA$与AA.)在替换后使用的csv文件存储路径相同,导致迁移失败(No such file or directory),可以通过重新迁移失败表来解决
export.csv.path.replacement.from=\ /'."*$
# 发生csv文件存储路径字符替换时(详见export.csv.path.replacement.from),指定替换的目标字符或字符串
export.csv.path.replacement.to=_
# 导出时大表拆分的个数
export.table.splitCount=5
# 导出时触发大表拆分的行数
export.table.splitConditionCount=10000000
# 导出时触发大表拆分的表大小(G)
export.table.splitConditionSize=5
# 导出时带lob字段大表拆分的个数
export.lobTable.splitCount=5
# 导出时触发带lob字段大表拆分的行数
export.lobTable.splitConditionCount=1000000
# 导出时触发带lob字段大表拆分的表大小(G)
export.lobTable.splitConditionSize=5
# 使用jdbc导出时每个csv文件的最大行数
export.jdbc.thresholdForSplittingFileLines=5000000
# 使用jdbc导出时每个csv文件的最大大小(M)
export.jdbc.thresholdForSplittingFileSize=3072
# #yasldr More References: http://doc.yashandb.com/yashandb/22.2/zh/%E5%B7%A5%E5%85%B7%E6%89%8B%E5%86%8C/yasldr/yasldr%E4%BD%BF%E7%94%A8%E6%8C%87%E5%AF%BC.html
# yasldr导入时的并行度
import.degree_of_parallelism=16
# yasldr导入时每批次的CSV数据行数
import.batch_size=2048
# yasldr导入方式,包括BASIC方式和BATCH方式
import.mode=BATCH
import.SENDERS=7
import.CSV_CHUNK_SIZE=128
# ========================================校验=============================================
# 校验任务限制每个数据源支持的最大连接数
checkTask.datasource.max-connection=500
# 校验任务获取连接超时时间,单位:ms
checkTask.datasource.connection-timeout=10000
# 校验任务获取的连接池中维持的最小连接数
checkTask.datasource.minimum-idle=0
# 校验任务的最大并行任务数
checkTask.task.parallel.max-num=20
# 校验任务的子任务的最大并行任务数,即一个任务多少个表在同时校验
checkTask.subTask.parallel.max-num=200
# 校验任务的全量校验对FLOAT数据类型的校验精度
checkTask.checkFloatPrecision=6
# 校验任务的数据类型映射有一边是char数据类型就移除数据右侧空格进行对比
checkTask.isRemoveCharBlank=true
#以上两个文件参数都可以依据需要进行调整,调整后重启YMP生效。
3)YMP安装:
YMP安装时按默认方式自行安装YashanDB作为内置库。
默认内置库相关信息:
- 部署形态:单机
- 集群名称:ymp
- 安装目录:/home/ymp/yashan-migrate-platform/db
YMP安装内置库有两种方式:
-
方式一:安装内置库并启动YMP
# 进入安装目录执行安装命令 $ cd /home/ymp/yashan-migrate-platform/ $ sh bin/ymp.sh install --db /home/ymp/yashandb-23.2.1.0-linux-x86_64.tar.gz
-
方式二:安装内置库和OCI客户端并启动YMP
# 进入安装目录执行安装命令 $ cd /home/ymp/yashan-migrate-platform/ $ sh bin/ymp.sh install --db /home/ymp/yashandb-personal-23.2.1.100-linux-x86_64.tar.gz --path /home/ymp/instantclient_19_19
上述两种方式的安装都需要借助YashanDB软件安装压缩文件。
**4)查看运行状态:**通过如下方式可查看YMP运行状态
[ymp@dsmart ~]$ cd yashan-migrate-platform/ [ymp@dsmart yashan-migrate-platform]$ sh bin/ymp.sh status YMP is running, pid is 9512. Built-in database is used, pid is 9382. # 还可以通过如下方式查看YMP版本 [ymp@dsmart yashan-migrate-platform]$ sh bin/ymp.sh -v Yashan-migrate-platform version: Release v23.2.1.0 YashanDB SQL Personal Edition Release 23.2.1.100 x86_64 YashanDB Loader Personal Edition Release 23.2.1.100 x86_64 2d13f1d
四、访问YMP(崖山数据迁移平台)
4.1 设置初始密码
YMP部署后,YMP提供了账号和密码同为admin的账户,使用该账户初次登录会提示需修改初始密码,并且初始密码的设置要符合密码规范要求。
修改初始密码后,使用新密码登录YMP,主界面如下:
如希望重新设置admin密码,可通过主界面右上角**【个人中心】**进行设置,如下所示:
点击**【个人中心】**进入如下页面:
点击上图红色箭头处,可修改admin密码,如下所示:
4.2 查看YMP版本信息
在**【个人中心】**处也能查看到当前YMP版本、内置库版本、JDBC及OCI等版本信息,如下所示:
五、数据源管理
5.1 创建用户并授权
这一步操作目的主要是为连接源端数据源,评估源端对象兼容性做准备。
此处有三种迁移平台所需权限,分别如下:
- 跨用户评估迁移权限
- 仅本连接用户元数据评估迁移所需权限
- 跳过评估所需权限
注:
跨用户评估迁移权限:指的是迁移平台使用的用户和需要迁移的用户不是同一个的场景
仅本连接用户元数据评估迁移所需权限:指的是迁移平台使用的用户和需要迁移的用户是同一个的场景
本次选择使用跨用户评估迁移权限,源端执行如下操作:
CREATE USER orauser IDENTIFIED BY XXXX;
GRANT CREATE SESSION TO orauser;
GRANT SELECT_CATALOG_ROLE TO orauser;
GRANT SELECT ANY TABLE TO orauser;
GRANT SELECT ANY SEQUENCE TO orauser;
5.2 添加数据源
在YMP主界面点击**【数据源管理】**,如下所示:
5.2.1 添加源端
点击上图箭头处**【添加数据源】**
参照上图信息,填写数据源名称、数据源类型、选择连接类型、源端IP和端口、数据库可以选择ServiceName或者SID,填写用户名和密码。
然后点击测试连接,成功连接会有返回提示,然后点击确认,源端数据源添加后,如下所示:
并可以对上述创建的数据源进行相应信息修改和删除数据源。
5.2.2 添加目标端
参照添加源端,设置目标端,本次我选择使用sys系统用户,如下所示:
数据源类型选择 YashanDB,端口本次采用默认端口,然后点击测试连接,成功连接会有返回提示,然后点击确认,目标端数据源添加后,如下所示:
六、任务管理
上述数据源创建后,方可进行任务管理。
6.1 创建任务
创建任务是进行数据库迁移评估的起点,首先要先创建一个迁移评估任务。点击**【任务管理】**,进入任务管理界面。
如上图所示,点击右上角 **【创建任务】**按钮创建任务,如下所示:
创建任务有四个主要选项,分别是:
- 基础信息 包含[任务名称、源端数据库、是否评估、评估数据库(若选择外置库,需设置外置库信息)]
- 选择评估对象 包含如表、约束、索引、视图等相关信息
- 选择评估范围 可根据需要选择待评估的对象用户
- 其他设置 包含[是否校验失效对象、是否忽略nologging、评估部署模式、手动DDL保留策略]
在官网链接 [ https://doc.yashandb.com/ymp/23.2/zh/用户指南/任务管理/创建任务.html ] 这部分有对上述几个主要选项的详细描述,限于篇幅,本次不做赘述。
上述信息填写后,可点击**【保存】,会暂存填写的任务信息,此时任务状态为评估编辑中。若希望进行评估,可点击【下一步:开始迁移评估】**进入迁移评估阶段,如下所示:
迁移评估结束后,会给出评估结果,如下所示:
本次仅为测试验证,如上图所示,在**【对象详情】界面,勾选【不兼容】,然后点击【确定】**按钮,如下所示:
然后勾选 【全选所有】,再点击又上角**【批量设置是否忽略】,选择【忽略】**,如下所示:
此时,会有如下提示,提示需要重新刷新报告,如下所示:
然后点击 【刷新报告】,待报告刷新后,点击 【下一步:迁移配置】,如下所示:
选择批量忽略不兼容对象,然后点击 【迁移配置】
6.2 迁移配置
上面点击**【下一步:迁移配置】**进入如下界面,如下所示:
注:可根据需要进行配置,本次仅为测试,绝大多数配置选择默认。
点击 【下一步:离线迁移】
6.3 离线迁移
在上面点击离线迁移后,进入如下界面,如下所示:
待一段时间后,迁移结束,信息如下所示:
6.4 校验初始化
点击上图**【下一步:校验初始化】**,进入如下页面,如下所示:
6.5 一致性校验
如上图所示,点击**【下一步:开始一致性校验】**,如下所示:
6.6 MySQL 迁移
上面我们主要是测试了Oracle到崖山的数据迁移,接下来我们将演示下MySQL到崖山数据库的迁移。
本次选择的MySQL库版本是 5.6,通过YMP将其迁移到yashanDB库。
6.6.1 添加数据源
参照上述Oracle迁移,在**【数据源管理】界面,添加数据源名称、选择数据源类型为MySQL,根据MySQL环境设置数据库IP和端口号、用户名和密码,【测试连接】通过,点击【确认】**保存。
6.6.2 创建任务
在**【任务管理】**界面,创建任务,如下所示:
6.6.3 迁移评估
根据上面提示设置后,点击**【下一步:开始迁移评估】**,进入迁移评估阶段,如下所示,会对MySQL迁移到yashanDB的对象进行兼容性评估,如下所示。
根据上面的评估结果,可以查看哪些对象不兼容,选择“不兼容”在**【对象详情】菜单,选择【评估结果】**项,勾选“不兼容”选项,如下所示:
如果是生产迁移,一定要对不兼容对象进行兼容处理。
本次作为测试,对于不兼容类型,选择忽略,首先勾选**【全选所有】,然后再【批量设置是否忽略】选项,勾选【忽略】**,如下所示:
忽略全部不兼容对象后,需要重新刷新报告,如下所示:
重新刷新报告,重新评估后,结果如下所示:
只有兼容占比达到100%,才可以选择迁移配置。
6.6.4 迁移配置
上述迁移评估完成后,点击【下一步:迁移配置】,进入迁移配置界面,如下所示:
如上所示,在**【目标端数据库及迁移范围】选择yashanDB外智库,在【迁移初始化配置】处,如果是首次迁移,可以选择默认,如果外置库已有之前迁移的对象而未删除,再次迁移可以选择【覆盖】,【表空间初始化】**选择默认“跳过”。
6.6.5 离线迁移
上述操作完成后,点击**【下一步:离线迁移】**进入离线迁移界面,在迁移过程中,会显示迁移进度,迁移结束后,如下所示:
6.6.6 校验初始化
上述离线迁移完成后,点击【下一步:校验初始化】,进入如下所示页面:
如上图所示,在校验初始化页面,在**【选择校验范围】选择校验的用户,在【校验设置】**可以选择“完整对比”或者“统计对比”,两者的相关含义如下所示:
- 统计对比:一致性校验页面显示统计校验。
- 完整对比:新增单表不一致阈值,可选无限制或自定义阈值,达到阈值后停止校验,一致性校验页面显示全量校验。
在**【高级选项】**中,性能配置表示支持最大可同时进行表校验的数目,每一对表的校验会使用一个线程,同时源端与目标端各占用一个连接数,默认范围[1,200]。
6.6.7 一致性校验
参照5.6.6 章节,在设置了相关参数后,点击**【下一步:开始一致性校验】**进行数据校验,校验过程中,会显示校验进度,校验结束后,结果如下所示:
七、问题梳理
在验证YMP的迁移过程中,也发现了一些问题,也将如下问题反馈给了崖山官方人员,他们已将收集的问题反馈给了研发,后续会进一步完善YMP功能,值得期待。
7.1 下载报告报提示未知错误
在迁移评估后,下载评估报告,总是报错,提示“未知错误”,如下所示。
未知错误
查看了相关日志,报如下错误:
# 日志目录在 /home/ymp/yashan-migrate-platform/logs,查看 YMP-INFO***.log
2024-04-19 15:32:21.627 [http-nio-8090-exec-7] INFO com.sics.migrate.port.common.util.YasldrParser - yasldr version::YashanDB Loader Personal Edition Release 23.2.1.100 x86_64 2d13f1d
2024-04-19 15:32:21.801 [http-nio-8090-exec-2] INFO com.sics.migrate.port.common.util.YasldrParser - yasldr version::YashanDB Loader Personal Edition Release 23.2.1.100 x86_64 2d13f1d
2024-04-19 15:32:29.143 [http-nio-8090-exec-9] INFO com.sics.migrate.server.ObjAssessmentPercentServer - 新的连接加入:28
2024-04-19 15:32:29.180 [http-nio-8090-exec-10] INFO com.sics.check.server.CheckTaskProgressWebSocket - 新的连接加入:29
2024-04-19 15:32:29.259 [http-nio-8090-exec-7] INFO com.sics.migrate.handler.InterfaceLogHandler - interface Call details: {"startTime":1713511949242,"spendTime":17,"uri":"/yashan/task/getTaskList","url":"http://10.110.8.42:8090/yashan/task/getTaskList","method":"GET","ip":"10.10.52.21","parameter":"{taskStage\u003dnull, pageSize\u003d10, taskName\u003d, pageNum\u003d1, taskStatus\u003dnull, dateOrderBy\u003dnull}","result":"{\"code\":200,\"message\":\"success\",\"result\":{\"records\":[{\"id\":1,\"taskName\":\"ddd\",\"taskStage\":\"ASSESSMENT\",\"taskStatus\":\"ASSESSMENT_FINISHED\",\"taskProgress\":100.0,\"sourceDbType\":\"ORACLE\",\"startTime\":\"2024-04-19 14:28:25\"}],\"total\":1,\"size\":10,\"current\":1,\"orders\":[],\"optimizeCountSql\":true,\"searchCount\":true,\"optimizeJoinOfCountSql\":true}}"}
2024-04-19 15:32:29.821 [http-nio-8090-exec-5] INFO com.sics.check.server.CheckTaskProgressWebSocket - 连接关闭:29
2024-04-19 15:32:29.821 [http-nio-8090-exec-2] INFO com.sics.migrate.server.ObjAssessmentPercentServer - 连接关闭:28
2024-04-19 15:32:30.746 [http-nio-8090-exec-4] INFO com.sics.migrate.server.ObjAssessmentPercentServer - 新的连接加入:2a
2024-04-19 15:32:30.773 [http-nio-8090-exec-6] INFO com.sics.check.server.CheckTaskProgressWebSocket - 新的连接加入:2b
2024-04-19 15:32:30.841 [http-nio-8090-exec-1] INFO com.sics.migrate.handler.InterfaceLogHandler - interface Call details: {"startTime":1713511950825,"spendTime":16,"uri":"/yashan/task/getTaskList","url":"http://10.110.8.42:8090/yashan/task/getTaskList","method":"GET","ip":"10.10.52.21","parameter":"{taskStage\u003dnull, pageSize\u003d10, taskName\u003d, pageNum\u003d1, taskStatus\u003dnull, dateOrderBy\u003dnull}","result":"{\"code\":200,\"message\":\"success\",\"result\":{\"records\":[{\"id\":1,\"taskName\":\"ddd\",\"taskStage\":\"ASSESSMENT\",\"taskStatus\":\"ASSESSMENT_FINISHED\",\"taskProgress\":100.0,\"sourceDbType\":\"ORACLE\",\"startTime\":\"2024-04-19 14:28:25\"}],\"total\":1,\"size\":10,\"current\":1,\"orders\":[],\"optimizeCountSql\":true,\"searchCount\":true,\"optimizeJoinOfCountSql\":true}}"}
2024-04-19 15:32:32.645 [http-nio-8090-exec-9] INFO com.sics.check.server.CheckTaskProgressWebSocket - 连接关闭:2b
2024-04-19 15:32:32.645 [http-nio-8090-exec-10] INFO com.sics.migrate.server.ObjAssessmentPercentServer - 连接关闭:2a
2024-04-19 15:32:33.730 [http-nio-8090-exec-5] INFO com.sics.migrate.server.ObjAssessmentPercentServer - 新的连接加入:2c
2024-04-19 15:32:33.767 [http-nio-8090-exec-2] INFO com.sics.check.server.CheckTaskProgressWebSocket - 新的连接加入:2d
2024-04-19 15:32:33.822 [http-nio-8090-exec-8] INFO com.sics.migrate.handler.InterfaceLogHandler - interface Call details: {"startTime":1713511953804,"spendTime":17,"uri":"/yashan/task/getTaskList","url":"http://10.110.8.42:8090/yashan/task/getTaskList","method":"GET","ip":"10.10.52.21","parameter":"{taskStage\u003dnull, pageSize\u003d10, taskName\u003d, pageNum\u003d1, taskStatus\u003dnull, dateOrderBy\u003dnull}","result":"{\"code\":200,\"message\":\"success\",\"result\":{\"records\":[{\"id\":1,\"taskName\":\"ddd\",\"taskStage\":\"ASSESSMENT\",\"taskStatus\":\"ASSESSMENT_FINISHED\",\"taskProgress\":100.0,\"sourceDbType\":\"ORACLE\",\"startTime\":\"2024-04-19 14:28:25\"}],\"total\":1,\"size\":10,\"current\":1,\"orders\":[],\"optimizeCountSql\":true,\"searchCount\":true,\"optimizeJoinOfCountSql\":true}}"}
2024-04-19 15:32:35.525 [http-nio-8090-exec-6] INFO com.sics.migrate.server.ObjAssessmentPercentServer - 连接关闭:2c
2024-04-19 15:32:35.525 [http-nio-8090-exec-4] INFO com.sics.check.server.CheckTaskProgressWebSocket - 连接关闭:2d
2024-04-19 15:32:35.577 [http-nio-8090-exec-1] INFO com.sics.migrate.port.common.util.YasldrParser - yasldr version::YashanDB Loader Personal Edition Release 23.2.1.100 x86_64 2d13f1d
2024-04-19 15:32:35.694 [http-nio-8090-exec-10] INFO com.sics.migrate.port.common.util.YasldrParser - yasldr version::YashanDB Loader Personal Edition Release 23.2.1.100 x86_64 2d13f1d
2024-04-19 15:32:37.817 [http-nio-8090-exec-4] INFO com.sics.migrate.port.common.util.YasldrParser - yasldr version::YashanDB Loader Personal Edition Release 23.2.1.100 x86_64 2d13f1d
2024-04-19 15:33:12.736 [http-nio-8090-exec-4] ERROR com.sics.migrate.handler.GlobalExceptionHandler - 错误的请求:
com.sics.migrate.exception.YashanMigratePlatformException: null
at com.sics.migrate.controller.ReportDownloadController.getObjAssessmentTaskReport(ReportDownloadController.java:78)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:61)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AdviceFilter.executeChain(AdviceFilter.java:108)
at org.apache.shiro.web.servlet.AdviceFilter.doFilterInternal(AdviceFilter.java:137)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
at org.apache.shiro.web.servlet.ProxiedFilterChain.doFilter(ProxiedFilterChain.java:66)
at org.apache.shiro.web.servlet.AbstractShiroFilter.executeChain(AbstractShiroFilter.java:458)
at org.apache.shiro.web.servlet.AbstractShiroFilter$1.call(AbstractShiroFilter.java:373)
at org.apache.shiro.subject.support.SubjectCallable.doCall(SubjectCallable.java:90)
at org.apache.shiro.subject.support.SubjectCallable.call(SubjectCallable.java:83)
at org.apache.shiro.subject.support.DelegatingSubject.execute(DelegatingSubject.java:387)
at org.apache.shiro.web.servlet.AbstractShiroFilter.doFilterInternal(AbstractShiroFilter.java:370)
at org.apache.shiro.web.servlet.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:154)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:382)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:895)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1722)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.NullPointerException: null
at java.util.Comparator.lambda$comparingInt$7b0bb60$1(Comparator.java:490)
at java.util.TimSort.countRunAndMakeAscending(TimSort.java:356)
at java.util.TimSort.sort(TimSort.java:220)
at java.util.Arrays.sort(Arrays.java:1512)
at java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:348)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:483)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at com.sics.migrate.serviceimpl.ObjAssessmentResultServiceImpl.getObjAssessmentTaskReport(ObjAssessmentResultServiceImpl.java:613)
at com.sics.migrate.serviceimpl.ObjAssessmentResultServiceImpl$$FastClassBySpringCGLIB$$92addf36.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.sics.migrate.serviceimpl.ObjAssessmentResultServiceImpl$$EnhancerBySpringCGLIB$$51c97367.getObjAssessmentTaskReport(<generated>)
at com.sics.migrate.serviceimpl.ObjAssessmentResultServiceImpl$$FastClassBySpringCGLIB$$92addf36.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
at com.sics.migrate.serviceimpl.ObjAssessmentResultServiceImpl$$EnhancerBySpringCGLIB$$3a0b72e9.getObjAssessmentTaskReport(<generated>)
at com.sics.migrate.controller.ReportDownloadController.getObjAssessmentTaskReport(ReportDownloadController.java:67)
... 68 common frames omitted
该问题已反馈崖山官方相关人员
7.2 迁移评估修改对象后需新刷新报告
在执行迁移评估过程中,如果对一些有问题的对象,比如选择选择忽略该对象,在执行后,会提示需要重新刷新报告,如下所示:
7.3 任务名称不对应
在创建迁移任务时,开始随便创建了一个任务,并设置了一个任务名称,点击**“保存”**,未退出该页面,直接在该页面删除了原任务名称,重新填写了一个任务名称,点击保存并进行下一步,结果发现在主页面看到的任务名称和点击该任务名称看到的任务名称不对应,如下所示。
该问题已反馈给崖山官方人员。
7.4 不兼容TIMESTAMP (6) WITH TIME ZONE DEFAULT
当前我们这边很多表中有字段使用 timestamp with zone,当前yashandb不支持这种类型,已将问题反馈给官方人员。
7.5 迁移失败对象不允许手动修复
迁移时,不允许对迁移失败的对象进行手动修复。
7.6 YMP不支持Oracle 10g
配置数据源的时候,可以正常连接Oracle10g,但在配置任务时提示不支持Oracle 10g
7.7 需删除评估任务才能评估同名的用户
当新创建的任务在评估任务时,如果评估的schema和其它任务评估的schema同名,会提示有冲突。
7.8 不支持对DG备库评估对象
7.9 YMP和数据库建议选择相同版本
我初期在部署YMP的时候,YashanDB数据库软件的版本高于YMP版本,导致安装YMP时出现报错。
官方建议YMP版本应高于YashanDB数据库软件版本或者选择相同版本。
如果yashan-migrate-platform采用 23.1.1版本,而 数据库采用 23.2.1版本,安装就会报如下错误
八、补充
以下为一些验证中不兼容的类型实例:
九、问答环节
以下是受崖山直播之邀,谈谈对于迁移的感受,迁移有同构和异构迁移,一个完整而顺利的迁移是要在迁移前付出很多的努力的,以下是我个人对数据库的迁移的感受整理。
Q1.一般在数据迁移场景中,我们常见的风险有哪些?
在数据迁移过程中,尤其是涉及异构数据库时,以下是几个具体的常见风险及应对策略:
-
数据丢失或损坏:
- 风险:在迁移过程中,由于错误配置、网络问题或其他技术故障,可能会导致数据丢失或损坏。
- 应对:确保进行完整的数据备份,并在迁移前进行完整性检查。使用可靠的迁移工具和经过验证的迁移过程。
-
数据不一致:
- 风险:在迁移过程中,由于事务处理不同步或迁移脚本错误,源和目标数据库之间可能出现数据不一致。
- 应对:使用数据比较工具定期校验源数据库和目标数据库之间的数据一致性,确保同步机制正确实施。
-
性能下降:
- 风险:迁移到新的数据库可能由于配置不当或硬件限制导致性能问题。
- 应对:在迁移前进行容量规划和基准测试,迁移后对系统进行调优,如索引优化、查询优化等。
-
兼容性问题:
- 风险:数据兼容性:
- 数据类型兼容性问题
- 数据表兼容性(普通表、分区表等)
- 数据结构兼容性问题
数字、字符串,时间类型(精度问题) - SQL语句兼容性、执行计划兼容性问题
执行计划、逻辑等 - 存储过程、函数、包、触发器等翻译问题
- 表大小存储逻辑等
- 迁移后,数据库与其他系统之间接口,业务,或者复制等关系问题相关协调&优化
- 针对TP/AP等不同业务系统,测试重点关注点等问题
- 应对:在做迁移之前,应该进行大量兼容性验证测试,避免迁移前后数据库不兼容
- 风险:数据兼容性:
-
成本和时间超支:
- 风险:迁移项目可能因未预见的技术挑战、资源不足或管理不当导致时间延长和成本增加。
- 应对:进行详尽的项目规划,设立明确的时间表和预算。适时调整计划,保持通信透明,及时解决出现的问题
-
反向复制:
- 风险:数据的不一致,导致数据错乱
- 应对:为保证迁移后因其它情况需要回退,一定要制定好反向复制方案,保证能顺利进行回退
Q2. 您觉得在做异构数据库迁移前后需要做哪些操作呢?
对于成功的数据库迁移,每个阶段的准备和后续操作都至关重要:
迁移前的操作
- 详细评估:
- 审核现有数据库的规模、使用的数据类型、复杂的SQL查询和存储过程。
- 评估目标数据库的功能以及可能的限制。
- 迁移策略制定:
- 决定迁移是一次性还是分阶段进行。
- 选择适当的迁移工具和方法(如全量迁移或增量迁移)。
- 测试环境准备:
- 构建与生产环境相仿的测试环境,用于迁移过程中的测试。
- 风险管理计划:
- 设计回滚方案以应对迁移失败的情况。
- 制定紧急恢复计划和数据备份策略。
迁移后的操作
- 系统验证:
- 执行数据完整性检查,验证数据迁移后的准确性。
- 进行功能测试和性能测试,确保所有系统功能正常运行,性能达标。
- 优化调整:
- 根据实际运行情况调整数据库参数。
- 优化SQL查询和索引,提高查询效率和响应时间。
- 持续监控:
- 监控系统的性能和稳定性,及时发现和解决新出现的问题。
- 使用监控工具跟踪关键性能指标和日志。
- 培训与文档:
- 更新技术文档和用户手册。
- 对维护团队和用户进行新系统的培训。
Q3.您觉得在使用YMP过程中,有什么好用的地方和需要改进的地方吗?
**好的方面:**安装部署简单,文档也比较详尽,迁移过程步骤明确,而且界面比较清爽,这是我特别欣赏的地方,对于很多操作也有明确的提示,另外在迁移过程中对于不明白的地方也得到官方技术人员的给力指导。
**需要改进的方面:**目前YMP迁移还只支持全量迁移,另外对于支持的数据库类型还比较少,另外在迁移过程中也发现了一些待改进的地方,这块也已反馈给相关负责人。
建议后续增加增量迁移,以及复制迁移,另外也希望能支持更多异构数据库类型。