📌 前言:在金融行业做数据开发,多环境、多数据中心是常态。最近一个银行项目,6个区域分行的数据仓库结构完全相同,只是表名后缀不同。如果为每个分行各做一套ETL,维护成本直接翻6倍。本文分享如何用Kettle的参数化机制,1套转换文件服务6个数据中心。
一、项目背景
某全国性商业银行,在全国6个区域分行各有独立的业务系统:
| 分行 | 标识 | 数据库 |
|---|---|---|
| 华东分行 | huadong | db_huadong |
| 华南分行 | huanan | db_huanan |
| 华北分行 | huabei | db_huabei |
| 西南分行 | xinan | db_xinan |
| 东北分行 | dongbei | db_dongbei |
| 西北分行 | xibei | db_xibei |
每个分行的ODS层表结构完全相同,只是表名带分行后缀:
ods_account_huadong ods_account_huanan ods_account_huabei ...
ods_transaction_huadong ods_transaction_huanan ods_transaction_huabei ...
ods_customer_huadong ods_customer_huanan ods_customer_huabei ...
DM层也是同样的命名规则:
dm_risk_assessment_huadong dm_risk_assessment_huanan ...
此外还有一个合并DM表 dm_risk_assessment,汇总6个分行的数据供总行使用。
二、最初的方案:6套ETL?
如果为每个分行各做一套转换文件:
- 6个分行 × 5个ODS表 × 1个DM表 = 30个转换步骤
- 每次修改逻辑需要改6遍
- 极易遗漏,导致分行间逻辑不一致
这显然不可接受。
三、参数化方案:1套转换 + 变量替换
3.1 核心思路
- 创建1个转换文件,SQL中的表名使用
${ENV_NAME}变量 - 在作业中创建6个"转换"作业项,每个传入不同的
ENV_NAME参数值 - 修改逻辑时只改1个文件,6个分行自动生效
3.2 转换文件设计
以ODS→DM的转换为例,创建 dm_batch_insert.ktr:
SQL中的变量使用:
INSERT IGNORE INTO dm_risk_assessment_${ENV_NAME} (
account_id, customer_name,
risk_cate1, risk_cate2, risk_cate3, risk_cate4,
product_cate1, product_cate2, product_cate3, product_cate4,
trans_id, trans_name, trans_code, method_name,
create_time, update_time
)
SELECT
a.account_id,
a.customer_name,
a.cate1, a.cate2, a.cate3, a.cate4,
NULL, NULL, NULL, NULL,
t.trans_id,
t.trans_name,
m.code,
m.name AS method_name,
NOW(), NOW()
FROM ods_account_${ENV_NAME} a
INNER JOIN ods_transaction_${ENV_NAME} tr ON a.account_id = tr.account_id
LEFT JOIN ods_trans_detail_${ENV_NAME} t ON tr.trans_id = t.trans_id
LEFT JOIN ods_stand_item_${ENV_NAME} si ON t.item_id = si.item_id
LEFT JOIN ods_stand_method_${ENV_NAME} m ON si.method_id = m.method_id
WHERE tr.update_time > '${LAST_SYNC_TIME}';
转换参数定义(右键画布 → 转换设置 → 参数):
| 参数名 | 默认值 | 描述 |
|---|---|---|
ENV_NAME | huadong | 分行标识 |
LAST_SYNC_TIME | 2026-01-01 00:00:00 | 上次同步时间 |
3.3 作业文件设计
在作业中创建6个"转换"作业项,每个引用同一个 dm_batch_insert.ktr,传入不同的参数:
START → DM_HUADONG → DM_HUANAN → DM_HUABEI → DM_XINAN → DM_DONGBEI → DM_XIBEI → 成功
每个作业项的参数配置:
| 作业项名称 | 转换文件 | ENV_NAME | LAST_SYNC_TIME |
|---|---|---|---|
| DM_HUADONG | dm_batch_insert.ktr | huadong | ${LAST_SYNC_TIME} |
| DM_HUANAN | dm_batch_insert.ktr | huanan | ${LAST_SYNC_TIME} |
| DM_HUABEI | dm_batch_insert.ktr | huabei | ${LAST_SYNC_TIME} |
| DM_XINAN | dm_batch_insert.ktr | xinan | ${LAST_SYNC_TIME} |
| DM_DONGBEI | dm_batch_insert.ktr | dongbei | ${LAST_SYNC_TIME} |
| DM_XIBEI | dm_batch_insert.ktr | xibei | ${LAST_SYNC_TIME} |
关键配置:每个转换作业项必须 ✅ 勾选"从上一个结果复制参数",这样 ${LAST_SYNC_TIME} 才能从作业级别传递到转换级别。
四、参数传递的完整链路
理解Kettle的参数传递机制是参数化方案的关键:
主作业 (LAST_SYNC_TIME=2026-04-23 00:00:00)
│
├─→ Step2作业 (继承LAST_SYNC_TIME)
│ ├─→ ODS_HUADONG转换 (ENV_NAME=huadong, 继承LAST_SYNC_TIME)
│ ├─→ ODS_HUANAN转换 (ENV_NAME=huanan, 继承LAST_SYNC_TIME)
│ └─→ ...
│
├─→ Step3作业 (继承LAST_SYNC_TIME)
│ ├─→ DM_HUADONG转换 (ENV_NAME=huadong, 继承LAST_SYNC_TIME)
│ ├─→ DM_HUANAN转换 (ENV_NAME=huanan, 继承LAST_SYNC_TIME)
│ └─→ ...
│
└─→ Step4作业
└─→ DATA_QUALITY转换
4.1 参数传递规则
- 作业→子作业:子作业勾选"从上一个结果复制参数"即可继承
- 作业→转换:转换作业项勾选"从上一个结果复制参数"
- 转换→步骤:步骤勾选"替换变量",SQL中的
${VAR}自动替换 - 作业项级别参数:优先级最高,会覆盖继承的参数
4.2 参数优先级
作业项级别参数 > 作业级别参数 > 转换级别默认值
例如,DM_HUADONG 作业项中设置了 ENV_NAME=huadong,即使转换的默认值是 huadong,作业项的设置也会优先生效。
五、ODS层:6个分行并行执行
ODS层的6个分行之间没有依赖关系,可以并行执行:
START ──→ ODS_HUADONG ──→ 成功
──→ ODS_HUANAN ──→ 成功
──→ ODS_HUABEI ──→ 成功
──→ ODS_XINAN ──→ 成功
──→ ODS_DONGBEI ──→ 成功
──→ ODS_XIBEI ──→ 成功
在Kettle作业中,从START节点画多条Hop线到不同作业项,它们会自动并行执行。
六、DM层:6个分行顺序执行
DM层的处理需要创建临时表来拆分逗号分隔的字段,如果并行执行会导致临时表冲突。因此必须顺序执行:
START → DM_HUADONG → DM_HUANAN → DM_HUABEI → DM_XINAN → DM_DONGBEI → DM_XIBEI → 成功
⚠️ 为什么不能并行:每个DM转换都会创建→使用→删除临时表
temp_trans_split。如果两个分行并行执行,分行A刚创建的临时表可能被分行B删掉,导致数据错乱。
七、合并DM表:UNION ALL汇总
6个分行的DM表处理完成后,需要将数据汇总到合并表供总行使用:
INSERT IGNORE INTO dm_risk_assessment (
account_id, customer_name,
risk_cate1, risk_cate2, risk_cate3, risk_cate4,
product_cate1, product_cate2, product_cate3, product_cate4,
trans_id, trans_name, trans_code, method_name,
create_time, update_time
)
SELECT ... FROM dm_risk_assessment_huadong WHERE create_time >= '${CURRENT_SYNC_TIME}'
UNION ALL
SELECT ... FROM dm_risk_assessment_huanan WHERE create_time >= '${CURRENT_SYNC_TIME}'
UNION ALL
SELECT ... FROM dm_risk_assessment_huabei WHERE create_time >= '${CURRENT_SYNC_TIME}'
UNION ALL
SELECT ... FROM dm_risk_assessment_xinan WHERE create_time >= '${CURRENT_SYNC_TIME}'
UNION ALL
SELECT ... FROM dm_risk_assessment_dongbei WHERE create_time >= '${CURRENT_SYNC_TIME}'
UNION ALL
SELECT ... FROM dm_risk_assessment_xibei WHERE create_time >= '${CURRENT_SYNC_TIME}';
这个转换单独创建为 refresh_combined_dm.ktr,放在6个分行DM处理之后执行。
八、方案对比
| 对比项 | 6套独立文件 | 1套参数化文件 |
|---|---|---|
| 转换文件数量 | 6×5=30个 | 5个 |
| 修改逻辑 | 改6遍 | 改1遍 |
| 遗漏风险 | 高 | 无 |
| 新增分行 | 复制+改表名 | 加1个作业项 |
| 维护成本 | 高 | 低 |
九、踩坑提醒
9.1 变量替换必须勾选
每个"执行SQL脚本"步骤都要勾选"替换变量",否则 ${ENV_NAME} 不会被替换,SQL会报语法错误。
9.2 参数传递必须勾选"从上一个结果复制参数"
作业项如果不勾选这个选项,子转换/子作业就拿不到父级传递的参数。
9.3 变量在SQL中的引号
字符串类型的变量在SQL中需要加引号:
WHERE update_time > '${LAST_SYNC_TIME}' -- ✅ 有引号
WHERE update_time > ${LAST_SYNC_TIME} -- ❌ 没引号,SQL语法错误
数字类型的变量不需要加引号:
WHERE id BETWEEN ${BATCH_START_ID} AND ${BATCH_END_ID} -- ✅ 数字不加引号
9.4 默认值是调试用的
转换参数的默认值只是方便在Spoon中单独测试,实际运行时由作业传入的参数覆盖。
十、总结
核心要点:
- 多环境ETL用参数化转换,1套文件服务N个环境
- 表名用
${ENV_NAME}变量,作业中传入不同值 - 参数传递链路:主作业 → 子作业 → 转换 → SQL步骤
- 无依赖的步骤可以并行,有临时表冲突的必须顺序
- 合并表用UNION ALL汇总各环境数据
💡 一句话总结:别为每个环境做一套ETL了,参数化才是多环境数据仓库的正确打开方式!
如果这篇文章对你有帮助,点赞收藏不迷路~ 多环境ETL还有什么好方案?欢迎评论区交流!
世局板块
1. 霍尔木兹海峡事件
伊朗军方20日宣布关闭霍尔木兹海峡后,伊朗塔斯尼姆通讯社称海事数据显示海峡通行量已归零,处于封锁状态。美军则称当日仍有55艘商船通行,否认封锁。双方说法相左,该战略水道航运受阻引发国际关注,地区紧张局势升级。
2. 美伊瑞士谈判
美伊代表团21日在瑞士展开“历史性”面对面谈判,美国副总统万斯出席。谈判因特朗普强硬言论一度中断,最终达成继续技术磋商共识。同期,伊朗总统重申铀浓缩权利,强调不造核武,但核心分歧仍存,前景待察。
3. 泽连斯基退还勋章
乌克兰总统泽连斯基20日宣布,已通过物流将波兰“白鹰勋章”退还总统纳夫罗茨基。此举回应波方因乌特种部队命名争议撤销授勋,凸显双方历史认知矛盾。乌波关系裂痕未消,外交博弈持续。
4. “月面X”天象上演
6月22日17时10分至19时30分,月球表面将现“X”状光影奇观,为我国今年第二次适宜观测时机。该现象由三座环形山投影交错形成,持续时间短暂。公众可借助望远镜或肉眼观赏这一罕见天象。
5. 厄瓜多尔队0∶0战平库拉索队,马宁任主裁判
6月21日,美加墨世界杯小组赛第二轮,厄瓜多尔队0∶0战平库拉索队。中国裁判员马宁、周飞、傅明分别担任本场比赛的主裁判、第一助理裁判员和视频助理裁判员(VAR)。(央视体育)
6. 广西商人海上漂流获救
广西商人秦剑平5月27日于海口不慎落水,无救生设备漂流7天6夜后,6月2日在澄迈被渔民救起。其靠雨水、求生技巧与意志力存活,奇迹生还引发关注。事件警示滨海安全,救援渔民获见义勇为表彰。