本文介绍了如何使用工具的Merge能力,融合迁移源端与目标端的变更操作,并处理冲突。
1 背景
由于大数据集群迁移是一个持续性过程,时间周期根据规模与复杂度可能从数周至数月不等,因此一边进行迁移一边源端持续性开发、一边迁移一边目标端进行集群适配性改造是比较常见的。通常需要多轮迁移来同步源端的变更(含增量),同时将有选择的保留在目标端的一些改造调整。
基于以上情况,LHM调度迁移工具提供了源与目标同步变更时的有选择性Merge能力——识别双端的变更,并提示冲突部分,让用户有选择性的进行向目标端的覆写。
常见的双端变更冲突场景例如:源端、目标端均修改了同一节点的脚本代码。
2 先验信息
2.1 迁移常规流程
LHM调度迁移常规流程包括三步:Reader-源端导出(解析)、Converter-转换、Writer-目标端导入。每步将产生一个LHM调度输出包。
2.2 获取双端变更的方式
两次迁移之间,用户在迁移源端的变更操作将体现在Reader输出包的变化上。
由于调度转换是确定性的、线性的映射,两次迁移中Converter输出包的差异也可视作源端修改的体现。
用户在迁移目标端上的变更操作可以通过上次迁移的Writer输出包和当前时刻DataWorks Reader输出包之间的差异进行分析。
2.3 LHM调度迁移流程中的Merge动作
双端的异构性导致源端的变更与目标端的变更难以对照、难以合并。考虑到源端变更会反映到转换结果的变化上,而转换结果与目标端的数据结构一致,因此我们选择将转换结果的变更与目标端的变更相Merge,以实现双端变更融合。Merge行为将发生于调度转换与调度提交之间。
存在双端变更Merge的LHM调度迁移流程:
LHM调度迁移Merge原理(输入、输出与流程):
工具将默认采纳无冲突的修改。
为降低实施风险,工具将保守处理用户在源端与目标端的删除动作: 1. 源端删除:不在目标端上执行相应删除;2. 目标端删除:恢复为源端的最新版本。 若仍需删除,请在工具导入DataWorks后手动删除。变更报表中记录的删除记录可作为辅助。
3 操作流程
3.1 文件准备:LHM调度数据包
用户需要提供上次迁移和本次迁移中LHM调度迁移工具过程产物,使工具能够识别源端和目标端的修改情况。包括:
· 上次迁移的Reader输出包(如下图中的FirstTime/ReadOutput.zip)
· 上次迁移的Converter输出包(如下图中的FirstTime/ConvertOutput.zip)
· 上次迁移的Writer输出包(如下图中的FirstTime/WriteOutput.zip)
· 本次迁移的Reader输出包(如下图中的SecondTime/ReadOutput.zip)
· 本次迁移的Converter输出包(如下图中的SecondTime/ConvertOutput.zip)
· 当前时刻DataWorks Reader输出包(如下图中的SecondTime/ReadFromDataWorks.zip)
3.2 文件准备:配置项
配置项以json文件形式传入,例如MergeConfig.json。包括三个部分:
3.2.1 LHM调度数据包的路径
本文3.1节提到的6个LHM调度数据包的路径。
3.2.2 Merge工具输出文件的目标路径
包括两个文件:
· Diff&Merge报表(仅在CUSTOM模式下生效):展示源端、目标端的变更,以及存在冲突的变更条目。针对每一对冲突,用户需要决定采纳源端变更或目标端变更。
· Merge输出包:根据用户对于冲突的选择,生成新的调度信息包。
3.2.3 Merge模式与规则
Merge工具提供了五种模式,模式通过配置项中的"merge.mode"进行设置:
1、SOURCE_OVERWRITE:源端覆盖模式。
2、SOURCE_PRIORITY:双端融合修改,在冲突时优先采纳源端变更。
3、TARGET_PRIORITY:双端融合修改,在冲突时优先采纳目标端变更。
4、RULES:规则模式,用户可指定各元素变更在冲突时采纳源端/目标端变更。
5、CUSTOM:自定义模式,用户自行决定每一处冲突。
其中模式1-4将自动处理变更冲突,Merge工具一次运行即可获得Merge输出包。模式5需要用户输入,Merge工具将分两阶段运行,一阶段输出变更冲突清单(Diff&Merge报表)供用户决策,二阶段完成Merge动作、输出Merge结果包。
RULES模式下需配置"merge.rules",为各元素设置源端优先/目标端优先(Source/Target),模板如下:
{
"merge.rules": {
"workflow.property.update": {
"Owner": "Source",
"Description": "Source",
"ParamMap": "Source",
"Cron": "Source",
"InstanceMode": "Source"
},
"node.property.update": {
"Script": "Source",
"Owner": "Source",
"Description": "Source",
"ParamMap": "Source",
"Cron": "Source",
"InstanceMode": "Source",
"State": "Source",
"RerunMode": "Source",
"ResourceGroupIdentifier": "Source",
"WorkflowCu": "Source",
"Image": "Source",
"DiResourceGroupIdentifier": "Source",
"DiWorkflowCu": "Source"
}
}
}
3.2.4 配置项模板
{
"reader.output.t-1.package.path": "上次迁移Reader输出包的路径",
"reader.output.t.package.path": "本次迁移Reader输出包的路径",
"convert.output.t-1.package.path": "上次迁移Converter输出包的路径",
"convert.output.t.package.path": "本次迁移Converter输出包的路径",
"write.output.t-1.package.path": "上次迁移Writer输出包的路径",
"target.reader.output.t.package.path": "当前时刻DataWorks Reader输出包的路径",
"merge.xls.output.path": "Diff&Merge报表的存储位置(.xls文件)",
"result.output.t.package.path": "Merge结果包的存储位置",
"merge.mode": "Merge模式:可选SOURCE_OVERWRITE、SOURCE_PRIORITY、TARGET_PRIORITY、RULES、CUSTOM",
"merge.rules": {
"workflow.property.update": {
"Owner": "Source",
"Description": "Source",
"ParamMap": "Source",
"Cron": "Source",
"InstanceMode": "Source"
},
"node.property.update": {
"Script": "Source",
"Owner": "Source",
"Description": "Source",
"ParamMap": "Source",
"Cron": "Source",
"InstanceMode": "Source",
"State": "Source",
"RerunMode": "Source",
"ResourceGroupIdentifier": "Source",
"WorkflowCu": "Source",
"Image": "Source",
"DiResourceGroupIdentifier": "Source",
"DiWorkflowCu": "Source"
}
}
}
取值样例:
{
"reader.output.t-1.package.path": "/root/data/first/ReadOutput.zip",
"reader.output.t.package.path": "/root/data/second/ReadOutput.zip",
"convert.output.t-1.package.path": "/root/data/first/ConvertOutput.zip",
"convert.output.t.package.path": "/root/data/second/ConvertOutput.zip",
"write.output.t-1.package.path": "/root/data/first/WriteOutput.zip",
"target.reader.output.t.package.path": "/root/data/second/ReadFromDataWorks.zip",
"merge.xls.output.path": "/root/data/merge.xls",
"result.output.t.package.path": "/root/data/result.zip",
"merge.mode": "RULES",
"merge.rules": {
"workflow.property.update": {
"Owner": "Source",
"Description": "Source",
"ParamMap": "Source",
"Cron": "Source",
"InstanceMode": "Source"
},
"node.property.update": {
"Script": "Source",
"Owner": "Source",
"Description": "Source",
"ParamMap": "Source",
"Cron": "Source",
"InstanceMode": "Source",
"State": "Source",
"RerunMode": "Source",
"ResourceGroupIdentifier": "Source",
"WorkflowCu": "Source",
"Image": "Source",
"DiResourceGroupIdentifier": "Source",
"DiWorkflowCu": "Source"
}
}
}
3.3 运行命令
运行命令:
sh ./bin/run.sh merge -c ./conf/<你的配置文件>.JSON
SOURCE_OVERWRITE、SOURCE_PRIORITY、TARGET_PRIORITY、RULES模式下,运行一次指令即可实现Merge操作。
CUSTOM模式下,Merge工具分两次运行:一阶段分析双端变更、判断冲突并输出Diff&Merge报表,用户可在Diff&Merge报表中完成冲突处理;二阶段获取用户决策,执行Merge动作,输出调度数据包。两阶段独立运行,均采用上述指令触发执行。工具会根据Diff&Merge报表是否存在来判断目前所处的阶段。
3.4 冲突处理(CUSTOM模式)
打开Diff&Merge报表,可预览源端和目标端的变更统计与明细。
在“冲突处理”子表,可查看存在冲突的双端变更。用户可通过H列决策采纳源端/目标端。
4 融合案例
DolphinScheduler -> DataWorks,首次迁移后,在双端进行了如下修改。
4.1 源端修改
1、修改了头节点的脚本。
2、增加了一个节点。
3、增加了两条血缘
4.2 目标端修改
1、修改了头节点的脚本。(与源端冲突的一个Case)
2、修改了头节点的备注。
3、增加了一个节点。
4、增加了两条血缘。
4.3 融合结果
源端新增的节点与血缘均被保留。
存在冲突的“节点脚本修改”根据用户选择采纳了源端的修改动作。
附:特殊用法——仅查看源端变更
若用户仅需要查看迁移源端的变更明细、无需下一步动作,可使用如下配置项运行:
{
"reader.output.t-1.package.path": "上次迁移Reader输出包的路径",
"reader.output.t.package.path": "本次迁移Reader输出包的路径",
"merge.mode": "CUSTOM",
"merge.xls.output.path": "Diff报表的存储位置(.xls文件)"
}