Talend“作业设计模式”和最佳实践
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Talend“作业设计模式”和最佳实践
作为Talend开发者,不管是⼊门新⼿还是资深⼈⼠,常常要处理同⼀个的问题:“在编写这项作业时,哪种⽅式最好?”我们知道,通常应当⾼效、易读易写,并且尤其(多数情况下)要易于维护。
我们也知道,Talend Studio好⽐⾃由形态的“画布”,有全⾯⽽丰富的组件、存储库对象、元数据和链接选项,我们可以运⽤这些来“绘制”代码。
那么,如何确定在创建作业设计时使⽤的是最佳实践?
作业设计模式
⾃Talend版本3.4起,在每次使⽤时我都体会到作业设计对我的重要性。
起初我在开发作业时并未思考模式。
之前我⽤过Microsoft SSIS和其他类似⼯具,所以像Talend这样的可视化编辑器对我来说并不陌⽣。
相反,我关注的主要是基本功能、代码可重⽤性;其次是画布布局;最后是命名规则。
现如今,针对各种⽤例我已经开发了数百项Talend作业,我发现代码变得更加精巧,可重⽤性更⾼,⼀致性也更好,此时,模式的意义才逐渐显露出来。
加⼊Talend后,我有很多机会看到由客户开发的作业,得以证实⾃⼰的看法:对于每位开发者,每个⽤例都有多种解决⽅案。
我认为这⼀点是不少⼈的问题所在。
我们作为开发者的确都这么认为,但是在开发特定作业时,往往认为⾃⼰的⽅式是最佳或者唯⼀选择,但实际上也知道“或许还有更好的⽅式”,这种声⾳反复萦绕于⽿际。
在此情况下,我们期待或寻觅最佳实践,也就是作业设计模式!
制定基本规范
考虑实现最佳作业代码所需元素时,通常⽤到⼀些基本法则。
这些法则源于多年来从失败中汲取的教训以及积累的成功经验。
它们⾄关重要,为构建代码奠定坚实基础。
我个⼈认为应该引起⾼度重视。
我认为这些法则包括(重要程度不分先后):
- 可读性:创建明⽩易懂的代码
- 可写性:在最短时间内创建简洁明了的代码
- 可维护性:确定适当的复杂性,同时最⼤限度减少变更带来的影响
- 功能性:创建满⾜要求的代码
- 可重⽤性:创建可共享对象和原⼦⼯作单元
- 符合性:创建跨团队、项⽬、存储库和代码的真正规则
- 易适应性:创建可以变通⽽不致破坏的代码
- 可扩展性:创建可根据需要调整吞吐量的弹性模块
- ⼀致性:确定所有内容之间的共性
- 效率:创建优化的数据流和组件利⽤率
- 分区:创建服务于单⼀⽬标的原⼦化重点模块
- 优化:使⽤最少代码创建最多功能
- 性能:创建提供最快吞吐量的有效模块
重中之重是如何真正平衡这些法则,特别是前三条,因为这三者总是相互⽭盾,满⾜其中两条往往要牺牲另外⼀条。
如果可以,尝试按重要性对这些法则进⾏排序。
指导原则并⾮硬性标准,主要是为了有章可循!
在真正深⼊研究作业设计模式之前,结合刚刚阐述的基本法则,我们⾸先要确保了解⼀些其他值得考虑的细节。
我发现很多时候标准过于严苛,并未针对与其相悖的⾮预期场景留出⾜够余量。
⽽另外⼀些时候则相反。
不同开发者如出⼀辙地遵循刻板粗糙、有失协调的规范,更有甚者在作业设计中不连贯、缺乏规划甚⾄毫⽆章法,形成不良风⽓。
坦率说来,我认为这样过于草率并会造成误导,其实想要避免这些并不困难。
出于上述以及其他相当明显的原因,⾸先要制定成⽂的“指南”,⽽⾮建⽴“标准”。
其中包含基本法则并随附细则。
参与SDLC(软件开发⽣命周期)过程的所有团队创建并采⽤“开发指南”⽂档之后,这些基本法则即可为开发中的结构、定义和上下⽂⽅⾯提供⽀持。
对这⼀环节的投⼊具有长远意义,⽇后所有相关⼈员都将从中获益。
以下建议要点,您可根据⾃⾝情况予以采纳(仅作指导参考,欢迎⾃⾏修改扩充)。
1. ⽅法:其中应详细说明希望如何构建
1. 数据建模
1. 整体/概念/逻辑/物理
2. 数据库、NoSQL、EDW、⽂件
2. SDLC流程控制
1. 瀑布式或敏捷式/Scrum
2. 要求和规范
3. 错误处理和审计
4. 数据治理与管理
2. 技术:其中应列出各种⼯具(内部⼯具和外部⼯具)以及各⼯具间如何相互关联
1. 操作系统和基础架构拓扑
2. 数据库管理系统
3. NoSQL系统
4. 加密和压缩
5. 第三⽅软件集成
6. Web服务接⼝
7. 外部系统接⼝
3. 最佳实践:其中应说明要遵循特定指南的内容和时间
1. 环境 (DEV/QA/UAT/PROD)
2. 命名规则
3. 项⽬、作业和⼩作业
4. 存储库对象
5. 记录、监测和通知
6. 作业返回代码
7. 代码 (Java) 例程
8. 上下⽂组和全局变量
9. 数据库和NoSQL连接
10. 源/⽬标数据和⽂件架构
11. 作业切⼊和退出点
12. 作业⼯作流程和布局
13. 组件利⽤率
14. 并⾏化
15. 数据质量
16. ⽗/⼦任务和⼩作业
17. 数据交换协议
18. 持续集成和部署
1. 集成源代码控制 (SVN/GIT)
2. 发布管理和版本控制
3. ⾃动化测试
4. 项⽬存储库和提升
19. 管理与运营
1. 配置
2. ⽤户安全和授权
3. ⾓⾊和权限
4. 项⽬管理
5. 作业任务、计划和触发器
20. 存档和灾难恢复
我认为应当开发和维护的⼀些其他⽂件包括:
- 模块库:描述所有可重⽤的项⽬、⽅法、对象、⼩作业和上下⽂组
- 数据字典:描述所有数据模式和相关的存储过程
- 数据访问层:描述与连接和操作数据相关的所有事项
诚然,创建这样的⽂档需要时间,但与之在整个⽣命周期中发挥的价值相⽐,这些成本物超所值。
⽂档应尽可能简明扼要、直截了当并与时俱进(不必具有声明性质),它将有助于⼤幅减少开发错误(否则⽇后会为此付出⾼昂代价),为您所有的项⽬取得成功⼤有助益。
是时候探讨作业设计模式了吧?
当然!但⾸先还要说明⼀点。
我认为,每位开发者在编写代码时都可能形成或好或坏的习惯。
所以培养良好的习惯⾄关重要。
可以从⼀些简单的习惯开始,⽐如为每个组件添加标签。
这会让代码更具可读性,并且便于理解(我们的基本法则之⼀)。
⼈⼈都养成这样的习惯后,确保所有作业都有序组织到存储库⽂件夹中,并且使⽤的名称对项⽬有⼀定意义(也即符合性)。
然后让每个⼈都采⽤相同的⽇志记录消息样式,⽐⽅说对于 System.out.PrintLn() 函数采⽤通⽤⽅法封装器,并且对于作业代码建⽴共同的切⼊/退出点标准(其中包含替代要求选项)。
这两者都有助于快速实现多个法则。
随着时间的推移,由于开发团队采⽤并充分利⽤定义明确的开发指南,项⽬代码将变得更易读写,并且可由团队中任何⼈进⾏维护(这也是我最期望的效果)。
作业设计模式和最佳实践
在我看来,Talend作业设计模式可为我们提供建议的模板或框架布局,其中涉及关注特定⽤例的重要和/或必需的元素。
模式通常可重⽤于类似作业创建,如此⼀来,我们可以快速启动代码开发作业。
如您预期,多个不同⽤例也可引⼊通⽤模式,经过正确识别和实施,能够增强整体代码库、压缩作业量并减少重复或相似的代码。
我们下⾯就此展开探讨。
以下是要考虑的7项最佳实践:
画布⼯作流程和布局
可通过多种⽅法在作业画布上放置组件,并将这些组件相互关联。
我偏好的做法⼤体是⾸先“⾃上⽽下”,然后“从左⾄右”,其中左侧边界流程通常是错误路径,右侧边界和/或下⽅边界流程则为期望的或正常的路径。
理想情况下应尽可能避免连线交叉,⾃6.0.1版开始引⼊巧妙的弧线连接,很好地体现了这种策略。
我⾃⼰不太认同“之”字型模式,也就是组件按顺序“从左到右”放置,到达最右边界后即向下排列,随后再返回到左侧边界,依次类推。
感觉这种模式既不⽅便也不好维护,不过的确容易编写。
如果必须要⽤这种模式,执⾏的作业可能较之前会增多,并且可能⽆法得以正确组织。
原⼦作业模块 ~ ⽗/⼦作业
简⾔之,包含⼤量组件的⼤型作业很难理解和维护。
要避免这种情况,建议尽可能将⼤型作业分解为较⼩作业或⼯作单元。
之后以⼦作业形式执⾏(使⽤tRunJob组件),其⽬的即对他们加以控制和执⾏。
这么做也便于更好地处理错误和后续事件。
请记住,杂乱的作业可能难以理解,难以调试/修复,并且⼏乎⽆法维护。
⽽简单的⼩型作业具有明确⽬的,通过画布即可确定意图,绝⼤多数易于调试/修复,维护也相对轻⽽易举。
创建嵌套的⽗/⼦作业层次结构虽然完全可以接受,但需要考虑实际限制。
根据作业内存利⽤率、传递的参数、测试/调试问题以及并⾏化技术(如下所述),良好的作业设计模式不应超过3级嵌套tRunJob⽗/⼦调⽤。
嵌套再深可能更安全,但我有充分理由认为,对于任何⽤例5级⾜矣。
tRunJob与⼩作业
确定⼦作业与使⽤⼩作业之间的简单区别在于,⼦作业是从作业中“调⽤”,⽽⼩作业“包含”在作业中。
两者都提供创建可重⽤和/或通⽤代码模块的机会,在任何作业设计模式中结合使⽤两者都是⼀种⾮常有效的策略。
切⼊和退出点
所有Talend作业都需要在某个地⽅开始和结束。
Talend提供两个基本组件,即tPreJob和tPostJob,⽬的是帮助控制执⾏作业内容前后发⽣的情况。
在我的代码中,“初始化”和“收卷”步骤相当于这两个组件。
如您预期,⾸先执⾏tPreJob,然后执⾏实际代码,最后执⾏tPostJob代码。
请注意,⽆论代码正⽂中是否存在设计的退出(例如tDie组件,或者组件复选框选项“错误结束"),都将执⾏tPostJob代码。
关于作业切⼊和退出点,也应考虑使⽤tWarn和tDie组件。
这些组件提供对作业完成位置和⽅式的可编程控制,还⽀持改进错误处理、⽇志记录和恢复机会。
在作业设计模式中,我常使⽤tPreJob初始化上下⽂变量,建⽴连接并记录重要信息。
对于tPostJob,则关闭连接和其他重要清理以及更多记录。
相当简单对吗?您是这么做的吧?
错误处理和⽇志记录
这⼀项⾮常重要,或者说⾄关重要,如果可以正确创建通⽤的作业设计模式,⼏乎所有项⽬都能建⽴⾼度可重⽤的机制。
我的作业模式是针对任何作业可能包含的具有⼀致性和可维护性的记录处理器,创建“logPROCESSING”⼩作业,再附加包含具有符合性、可重⽤性和⾼效性的明确定义的“返回代码”。
其中的附加项易于编写、易于阅读且易于维护。
我相信,如果您能以⾃⼰独有的成熟⽅式来处理和记录项⽬作业的错误,则必将收获事半功倍的喜悦。
建议合理借鉴,善加利⽤!
最新版Talend增加了对Log4j和⽇志服务器使⽤的⽀持。
只需启⽤“项⽬设置 > Log4j”菜单选项,然后在TAC中配置Log Stash服务器即可。
强烈建议您在作业中纳⼊这项基本功能,实践证明其效果卓越。
“On SubJob正常/错误”与“On Component正常/错误”(及Run If)组件链接
有时候,Talend开发⼈员对于“On SubJob”或“On Component”链接之间的差异⼼存⼀丝困惑。
“正常”与“错误”的区别显⽽易见,那么这些“触发连接”差异何在,如何影响作业设计流程?
组件之间的”触发连接”可定义处理序列和数据流,其中组件之间的依赖关系存在于⼦作业中。
⼦作业的特点是所⽤组件有⼀个或多个组件与其链接,从⽽处理当前数据流。
单个作业中可能存在多个⼦作业,默认情况下所有相关⼦作业组件周围带有蓝⾊⾼亮⽅框(可在⼯具栏予以开启/关闭)。
⼦作业中的所有组件完成处理后,“On SubJob正常/错误”触发器将继续处理下⼀个“链接”⼦作业。
仅可从该⼦作业中的起始组件处使⽤。
在该特定组件完成处理后,“On Component正常/错误”触发器将继续处理下⼀个“链接”组件。
如果继续处理的下⼀个“链接”组件基于可编程java表达式,则“Run If”触发器会⾮常有⽤。
何为作业循环?
对于⼏乎每种作业设计模式,代码中的“主循环”和“辅助循环”都⾮常重要。
这些点⽤于控制作业执⾏的潜在退出位置。
“主循环”通常表现为数据流结果集的最顶层处理,完成主循环之后,作业即告完成。
“辅助循环”嵌套在更⾼阶循环中,且通常需借助重要控制才可确保作业正确退出。
我每次会确定“主循环”并确保向控制组件添加tWarn和tDie组件。
tDie通常设置为⽴即退出JVM(但请注意,即便如此tPostJob代码也会执⾏)。
这些顶层出⼝点使⽤简单的代码,“0”表⽰成功,“1”表⽰失败返回,不过遵循⾃⼰制定的“返回代码”指南再好不过了。
“辅助循环”(以及流程中的其他关键组件)中⼗分适合纳⼊其他tWarn和tDie组件(其中tDie未设置为“⽴即退出 JVM”)。
上⾯讨论的⼤多数作业设计模式最佳实践如下图所⽰。
请注意我⽤到了实⽤的组件标签,不过仍对组件放置规则稍作变通。
⽆论如何,最终结果是作业具有⾼度可读性、可维护性并易于编写。
结语
⾄此,虽说并未悉数解答您关于作业设计模式的疑问(实际上也不可能),但这总归是良好的开端。
我们介绍了⼀些基础知识,提供了⽅向,并作了⼩结。
希望这些有所帮助,并且能为诸位读者带来⼀些有益的启⽰。