按照前一篇文章

《GraalVM —— 让Java变得再次强大》

末尾提到的计划,本来这篇文章是想写一下GraalVM的后续《深耕云原生的Java应用框架 —— Quarkus》。

其实介绍Quarkus的文章前几天我已经写了一大半,但是后来我觉得光介绍这些技术的文章实在是太无聊了,所以先暂停了。

我认为技术相关的文章,很容易变得非常枯燥,所以,对于技术相关的文章,最好是能融入到实际场景中,融入到故事中。不光是要讲怎么做,还要讲清为什么要这么做。

所以,我虚构了一个场景“皮皮调度”来讲接下来的故事。

本文作为《皮皮调度》系列文章的开篇,先简单介绍一下故事背景。

历程1:从BI到简单调度

之前的工作主要是在商业智能(Business Intelligence,简称BI)领域。

最早在外企工作时,对于BI的理解比较片面,认为BI主要是基于已经加工好的数据,针对业务场景,进行各种高端的建模和可视化。而对于底层数据怎么加工,则认为那是“数仓”的职责,两者分工明确、各司其职。这时候,很像是生活在“象牙塔”中。

而加入创业公司后,则深深的感觉到整个数据生态的步骤是环环相扣的。数据分析要想做的好,离不开底层的数据处理。这时候,像是回到了有烟火气息的“人间”。

所以,我们的BI系统很早就有一个“数据处理”功能(我们叫它SmartETL)。其功能主要是:通过“拖拉拽”的界面配置出数据处理的流程,等到真正执行的时候,我们的系统自动把这个流程翻译成具体的Apache Spark任务并执行。可以把它简单的理解为:把一个或者多个现有的数据集(输入数据集),通过SmartETL的流程,生成一个或者多个新的“输出数据集”。

当然,既然我们在“人间”,那么,我们就会遇到各种各样的问题等着去解决。首先,

唯一不变的,就是”变化“本身

我们的数据也是一直在变化的,首先我们就要解决一个数据更新的问题。

在我们没有SmartETL前,我们的数据集都是一个个单独的个体,其更新可以采用最简单的”定时触发“方式。具体的实现为:我们可以为每个数据集设置一个CRON表达式来代表其更新的时刻, 而服务器负责在该CRON触发的时刻执行该数据集的更新。

当我们有了SmartETL后,第一版本,我们可以使用最简单的”依赖触发“策略:即任何一个”输入数据集“更新后,自动触发SmartETL的执行,从而来更新后续”输出数据集“。

历程2:从简单调度到Airflow

”依赖触发“,以其简单易于理解得到了广泛的应用。

但是,真实的世界从来都不是这么简单的。很快我们遇到了一些问题, 这里只举一个小的场景。

我们的一个客户,他的数据是存储在”分库分表”的16个MySQL数据库中,我们要汇总这16个数据库中的数据,并进行后续的SmartETL处理。基于“依赖触发”的简单实现,我们可以有如下方式:

方式1:最直接的方式,对于16个库,分别建立不同的16个数据集,定时运行。最后再做一个SmartETL,把这16张表合并为一个结果表。但是这样做的问题是:我们的SmartETL将会被触发16次(当然我们可以优化并合并减少一些次数),系统资源浪费严重,并且更可怕的是,系统有很多中间状态,数据总是只有部分数据。

方式2:我们的系统对于SmartETL做个简单的增强,对于16个数据集,我们可以选择只有某一个特定的数据集更新后才触发SmartETL更新。但是问题是我们不知道具体哪个数据集是最后一个执行的。所以,我们又想想其它的“聪明”策略,比如:我们对于其它的15个数据集,都设置其更新时间为凌晨2点,而对于最后一个数据集,我们设置其凌晨3点更新。但是这个仍是有风险的,万一某一天前15个数据集有个更新非常慢,超过了“收尾”数据集,那么我们就会面临最终输出数据集数据错误的严重问题了。

这些方式都不是很好用。究其原因:无论是中间流程节点(SmartETL),还是各个输入数据集, 它们都只是整个数据流程的一部分,其单独是无法解决这个执行顺序问题的。所以,我们需要有个统筹的“调度”模块,来协调各个子组件的执行顺序。

当时就想我们能不能参考和利用一些成熟的开源软件呢?答案是肯定的。

首先,开源调度领域最有名的应该就是 Apache Airflow了, https://github.com/apache/airflow, 通过学习其官方文档:https://airflow.apache.org/docs/stable/, 发现确实不错。

于是,简单实现了一个上传数据到BI系统的 operator, 组装一个DAG定时任务来把上面的16个库按照一定的并发来导入到BI平台中,并只在最后触发一次SmartETL更新。完美收工!

整体体验:Airflow整体还是不错的,虽然那时有些bug:比如CPU经常100%,却长时间无人修复等, 但是不得不说:使用Python代码来作为DAG的描述的方式对于软件研发人员来说确实体验不错,也更容易结合git进行版本控制。

历程3:从Airflow到DolphinScheduler

Airflow对于相对熟悉Python的人来说确实不错(比如我),但是当我想推广给公司的顾问同事使用, 用来帮助客户构建轻型数仓时,却遇到了非常大的挑战。

具体的功能不完善等小的挑战就不再赘述了(这些都可以通过扩展增强解决的),不过最麻烦的一点是: Airflow强依赖于Python, 而在非技术人员的眼里, Python代码和很多偏技术的概念都比较难以理解。

于是,我开始寻找一个更利于非技术人员使用的调度工具。感谢这次探索,我发现了Apache DolphinScheduler(在贡献给Apache前,叫做 EasyScheduler),其吸引我的几个点:

  • Apache License

  • Process/Task的definition 和 instance 分离, 支持补数据, 概念清晰. 路走对了, 就不怕远

  • 有还不错的图形化配置界面, 而不是什么都要写json配置, 或者python设置DAG等

  • 基于JVM, 以后方便Java Shop来扩展

并通过一系列的贡献,有幸成为了其PPMC(孵化项目管理委员会)成员,具体的内容就不在这里赘述了, 感兴趣的朋友可以参考我之前在“DolphinScheduler第一届用户大会”上的分享:

《观点 | 观远首席架构师分享「从开源使用者到Apache PPMC之路」》

反思1:Airflow和DolphinScheduler是否有本质区别?

前些天,看到了一篇CernerWorks公司使用Airflow的文章:

《Building a Production-Level ETL Pipeline Platform Using Apache Airflow – Using Apache Airflow to Manage Data Workflows in CernerWorks》:https://towardsdatascience.com/building-a-production-level-etl-pipeline-platform-using-apache-airflow-a4cf34203fbd

有些新的体会,当我们想到Airflow,可能第一印象是,其用户需要也了解Python,但是其实不一定,比如该文中就列出了一个中间层:yaml, 用户只需要写yaml文件,然后就能调度了,而无需关注具体Airflow的Python文件DAG是怎么编写的。文中的yaml例子如下:

对于DolphinScheduler也是一个参考,也许DolphinScheduler也可以中间抽取来一层Yaml来代表工作流 (无需关注屏幕上每个节点的布局坐标):

  1. 可以既支持 图形化拖拽方式配置,也支持手写Yaml。

  2. 把ApiServer和MasterServer等逻辑独立出来。MasterServer等无需关注数据库等

  3. 方便写UnitTest等

  4. 同时,DolphinScheduler生成的工作流yaml,也可以支持:可以选择在DolphinScheduler里跑,也可以选择发布到Airflow中跑

所以有了中间的yaml层,其实,我们就可以把一个系统分为前台,中台,后台了。

  • 前台:可以是像DolphinScheduler那样的图形化、拖拽式地配置DAG工作流, 也可以是直接在IDE中编写中台需要的yaml文件

  • 中台:yaml文件层,把所有的操作都转为一个标准的yaml文件,作为打通前台和后台的统一标准语言

  • 后台:具体定时调度,执行工作流的引擎,这个引擎可以是 Airflow,可以是DolphinScheduler,或者是别的单机程序

反思2:调度系统的主体程序应该只提供平台核心功能,通过插件来造就生态

之前一个人的分享说:他用Airflow多年的收获就是不用任何其它operator,而是只用kubernetes-operator,Airflow只负责串起来任务,和调度,不负责具体的执行。

所以,我也在想:是不是调度系统本身不应该直接提供太多的实现逻辑,而只是把核心的基础打好。在夯实的底层基础上,提供一套方便插件开发的SDK层。

反思3:Java和Python在调度系统中的定位

Java是企业软件开发领域的王者,Python是数据科学领域的霸主。

Java的特点:

  • 有着各种成熟企业应用框架

  • 强类型检查,方便提早在编译时发现问题

  • 但是相对Python更加偏重些

Python的特点:

  • 有着各种灵活的数据分析库:numpy、pandas、matplotlib、scikit-learn等

  • 脚本语言,开发、修改某个小的功能非常方便,不用重新打包

  • 弱类型语言,开发复杂的企业应用相对容易产生更多的问题

结合调度系统,我认为:比较适合用Java来搭建底层的调度平台,而Python可以用于实现各种具体功能插件。

小梦想:实现”个人智能助手“系统

我有一个小的梦想,实现辅助个人决策的”个人智能助手“系统。(注:不是某著名P8所招聘的私人生活助理,而是电脑上运行的智能程序)。

而智能系统的第一步是:需要一个协调各个未来系统的中央调度器。这个系统就是 —— ”皮皮调度“!

“皮皮调度”名字的来历:我个人非常不擅长起名字,在给我心中的个人调度系统想名字的时候,第一个冒出来的词就是我儿子的小名——皮皮。

”皮皮调度“的期望:

  • 定位为”个人智能助手“的指挥官,需要时时刻刻都在运行

  • 具有定时功能,不光提示我一些重要备忘时刻,还要帮我定时爬取一些数据并做自动汇总分析等

  • 省钱,希望”皮皮调度“能跑在我的 1核CPU、1G内存的云主机上,并且使用内存小于100M

有了上面的期望和限制,(顺便说一下,在开发程序的时候,我喜欢更多的限制,只有足够的限制,才能让你的程序聚焦,以及更加极致), ”皮皮调度“的实现方向如下:

  • 底层平台使用Java开发, 各种插件主要利用Python

  • 对于底层用Java实现的平台,使用 GraalVM 的 native-image 编译为原生程序,只用这样才能使得其运行时内存 < 100M

  • 用Python编写的插件,要充分利用Python的各种库,使得用非常短的时间就可以开发一款新的插件。方便我来快速的探索各个新的领域

接下来,让我们一起来进入”皮皮调度“的探索之旅吧!(背景音乐:朴树的《平凡之路》响起……)

戳原文,立刻奔向 DolphinScheduler 的官网一起玩耍~

最新文章

  1. 函数也是对象,本片介绍函数的属性、方法、Function()狗仔函数。
  2. Java Servlet(五):GenericServlet与Servlet、HttpServlet之间的关系(jdk7+tomcat7+eclipse)
  3. [Eclipse] - 集成JBoss7热加载和自动发布
  4. Jmeter代理录制脚本
  5. WAMP Server助你在Windows上快速搭建PHP集成环境
  6. android 使用两个surfaceview 在摄像机画面上绘图
  7. 命令行创建AVD
  8. Linux Kernel ‘perf’ Utility 本地提权漏洞
  9. 游戏开发设计模式之状态模式 &amp; 有限状态机 &amp; c#委托事件(unity3d 示例实现)
  10. Centos common software install
  11. mysql explain用法和结果的含义
  12. Android proguard (混淆)
  13. Oracle DataBase 编码格式
  14. 【十二】jvm 性能调优工具之 jhat (JVM Heap Analysis Tool)
  15. tp5 Excel导入
  16. CloudStack 4.1快照测试
  17. 【CSS-flex】圣杯布局(Holy Grail Layout)、输入框的布局、悬挂式布局、固定的底栏
  18. Android——android weight 属性(百度)
  19. oracle 内存分配和调优 总结
  20. Hadoop序列化与Writable接口(一)

热门文章

  1. IDEA快捷生成循环♻️
  2. Stream.toList()和Collectors.toList()的性能比较
  3. C++primer第二章
  4. Pycharm连接远程服务器并保持文件夹同步
  5. MySQL - 数据库的隔离级别
  6. Linux文件拷贝脚本
  7. java编程用大小写字母及数字输出五位数验证码
  8. 【Redis】事件驱动框架源码分析(多线程)
  9. python+anaconda+pycharm的使用
  10. Proxmox-VE虚拟环境