暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

RPC | 让远程方法调用变得像调用本地方法一样简单

海豚调度 2023-08-22
385



点击蓝字 关注我们





 


大家好,我是吴小飞,目前是开源社区的贡献者。从我毕业开始参加工作,Apache DolphinScheduler就一直伴随着我,算是一个长期的开源社区践行者。今天我将分享关于Apache DolphinScheduler RPC的源码剖析和二次开发的实战案例。


|吴小飞
编辑整理 曾辉


讲师介绍


吴小飞
社区贡献者


01

 RPC核心架构的演进设计



首先,让我们来讨论RPC核心架构的演进设计。RPC本身就是一种常用的技术,无论是Java开发还是大数据开发,都会经常使用,尽管不同的人可能使用方式不同。


简单来说,RPC的目标就是让远程方法调用变得像调用本地方法一样简单。与常用的HTTP等协议相比,RPC的本质区别在于它可以基于自定义的通信协议实现直观的远程过程调用,是一种简化调用的通信框架而非简单理解的协议。

在RPC的演进过程中,首先要实现从客户端到服务端的调用,需要具备网络通信信道和通信协议。通信协议可以自定义以标准化请求和响应的数据。


在具备通信和协议之后,需要对数据进行编解码,以实现原始数据的序列化和反序列化,以便通过网络传输序列化后的二进制数据。

在有了编解码后,可以基于编解码实现数据的发送和接收,客户端需要具备网络客户端,服务端需要具备相应的接收端。通过这些基础构建的网络通信框架,可以实现最基本的网络编程。

然后,为了简化开发者的使用,RPC框架一般会使用动态代理机制,将客户端与服务端的网络通信进行屏蔽,并提供同步、单向调用、异步调用和回调等机制。通过动态代理,开发者不需要手动编写客户端连接服务端的网络通信代码。

常用的RPC框架,如Dubbo,都是基于这种模式,在这种基础上,通过动态代理实现了对请求协议对象的屏蔽,并借助反射机制调用真实的业务方法。

通过这个演进过程,基本上实现了一个完整的RPC框架。然而,开发者不需要手动编写客户端与服务端的网络通信代码,因此引入服务治理的功能,即注册中心。服务提供者启动时,会将自身的元数据注册到注册中心,并及时通知给客户端,客户端订阅服务列表,通过负载均衡策略发现服务端并进行调用。

上述内容是RPC框架的一般设计模式,不论是gRPC还是Dubbo等RPC框架都遵循这样的设计思路,核心是客户端和服务端的通信、序列化和负载均衡。下面我们将看一下Apache DolphinScheduler是如何实现这些模块的。

在Apache DolphinScheduler中,整个调用链路可以分为多个抽象的RPC模块。首先,我们可以看到网络传输、协议和编解码这三个部分都是在远程模块中实现的。编解码使用常见的序列化框架,如Python的pickle或者Protobuf,通过网络通信传输数据。客户端的网络请求屏蔽使用了动态代理的方式,尽管没有使用JDK的动态代理,可能是基于字节码的动态代理,如ByteBuddy、CGLIB、Javaassist等。注册中心的实现也是通过SPI的方式,支持不同的注册中心,例如ZooKeeper、Etcd等。

负载均衡也是类似的,通过SPI扩展机制,选择合适的负载均衡策略。在DolphinScheduler中,默认的负载均衡策略是基于服务端的资源消耗情况,如CPU和内存负载来选择相应的工作节点。


通过这些模块的实现,Apache DolphinScheduler构建了一个完整的RPC框架。

02

RPC代码剖析



我们将看到调用链路的具体组成以及涉及的RPC模块。主要包括入口的执行调度器、主机管理器、执行器管理器、Netty通信、编解码等。


这些模块在不同的组件中进行协同工作,形成了一个闭环,实现了RPC的调用和执行逻辑。

根据我们对RPC框架设计的认知,再次回顾Apache DolphinScheduler中的负载均衡设计。我们将看到它的设计遵循了RPC框架的基本原则。


例如,负载均衡模块的设计遵循了统一的UML结构,首先实现自定义的选择器,选择不同的负载均衡策略,然后根据实时的主机信息进行综合判断,计算得出权重,并选择最小权重的主机进行调度。

通过这样的设计,Apache DolphinScheduler实现了高效的负载均衡。

03

二开实战案例



一般来说,针对Apache DolphinScheduler的二次开发主要包含两个方面的工作,即核心组件和数据源插件。

在DolphinScheduler中,核心组件体现在其Worker端的调度能力上。实际上,如果没有这些组件,DolphinScheduler本身是没有任何能力的。因此,所有的能力都是建立在这些组件的基础上的。

一般来说,公司在进行二次开发时,会根据自身需求来结合这些组件并进行相应的开发工作。

此外,对于数据源插件来说,Apache DolphinScheduler默认支持常见的JDBC模式。但是,如果你希望扩展其他数据源,也可以基于这种方式进行。因为不论是组件还是数据源,它们都基于SPI(Service Provider Interface)的模式,因此扩展起来比较方便。


下面举个简单的例子来说明,比如你想要扩展一个数据治理的组件。在这种实际案例中,你需要实现前端的一些功能,比如左侧菜单中能正常显示数据治理组件的图标样式。为了实现这一点,你需要修改任务标签(task Tab),增加一个PNG图标文件,并在index中添加相应的图像,这样它就能正常显示了。


然而,仅仅显示图标还不够,你还需要实现弹窗功能。在弹窗中,你需要添加一些部件,以在任务编辑框中显示。为了实现这些,你需要在task plugin中新增一个子模块,并根据核心的几个类进行开发。这其中包括通道(channel)、通道工厂(channel factory)以及任务组件task等。通过这三个核心扩展,你可以通过通道与底层插件进行解耦。如果你想使用这些扩展,需要在task all模块中添加你自定义的扩展模块。



除了上述扩展之外,还有一些优化方面的工作。例如,在数据同步中,许多人可能会选择阿里巴巴的DataX组件进行批量采集,因为DataX支持跨源的数据同步。在这种情况下,你可以对DolphinScheduler中与数据源相关的组件进行优化。


比如,针对PostgreSQL的writer,你可以进行写入改进。另外,你还可以对SQL组件进行增强,以杜绝删除和清除客户表数据的操作。

关于数据源插件的扩展,你可以将DolphinScheduler的数据源模块抽离出来,作为一个独立的模块引入项目中。


你可以将其作为一个公共模块,包括SPI和Service等常见的公共类。在plugin模块中进行扩展,实现自定义的数据库连接池。这是因为你要实现一个数据源的客户端,借助数据源的API,在服务器启动时通过注册机制安装插件,并将插件缓存到内存中。

此外,通过Processor的帮助,你可以在创建数据源时使用数据源的参数,根据数据源的ID找到缓存的插件,然后执行相应的操作。


04

总结



接下来是一个接近尾声的环节。在此之前,我想大致提一些问题,可能还有其他许多相关的问题。这些问题具有代表性,而我在几年前就提出了这些问题,但一直没有真正着手解决,因为目前我认为它们可能并不是核心问题。


我只是想分享这个主题,作为一个个人的建议,我个人认为目前是当前的问题。我们刚刚讨论了组件扩展,事实上后端扩展相对较容易和方便。但是在前端方面,我在讲述时大家也可以注意到,需要修改前端源代码的方式我认为不符合常见的开放原则。

因此,我的建议是引入CMS的低代码重构方式,使得前端能够像后端一样无缝扩展,无需修改源码,通过配置或其他方式实现相应的组件扩展。

第二个问题是我个人与进勇讨论过的,即我认为部署和运维并不够方便高效。无论是我们采用Standalone还是独立部署,还是使用Docker或K8s,我个人认为都不够方便。因为在进行大数据运维部署时,我们考虑了一站式部署,即如何与Spark等进行结合。即使现在要使用DolphinScheduler来运行一个Spark任务,你肯定也需要在其中安装数据分区或其他相关技术环境。

所以,如何与现有的大数据平台(如CDH或TDH)进行集成?因为之前TDH似乎也有自己的工作流插件,类似于Workflow可以替代它。我们应该如何通过大数据平台进行集成,并统一进行运维管理?当然,这可能不一定是我的建议,但可以作为一个标准。

第三个问题,我个人认为从规模上游和使用方的角度来看,许多程序员可能更喜欢使用代码调用的方式,而不是通过拖拽界面方式。事实上,我参与过的阿里派(Alibaba PAI)项目,无论是构建机器学习平台还是常见的业务工作流调度平台,核心都是需要一个客户端SDK来集成上游模块。因为在页面上进行操作不太实用,除非完全采用Dolphin提供的功能,但很多公司的场景可能更适合通过代码的方式进行集成。

因此,我认为目前虽然有Python的SDK和通过Java中的HTTP调用的方式,但远远不够。我们需要一种统一的跨语言SDK客户端,就像使用RPC客户端一样简单,通过几行代码就能实现调用。我认为后续可以考虑这种客户端,将Python和Java等语言进行统一。

当然,还有其他一些问题,包括在开始分享时,进勇也提到了一些优化工作,实际上是一些极端情况下的问题,我们在各个公司中或多或少都会遇到。我稍微补充一下,可能在很多公司中也非常关注的是当数据失败时是否需要重试。

实际上,这个问题并不简单,因为你必须考虑任务是否具备重试的幂等性,以免出现重复运行的情况。因此,在调度中应该考虑到这个问题。因此,对于调度本身来说,仅仅运行任务并不复杂,或者说门槛不是很高。或者通过这种方式相对容易。但是它的难点和门槛在于其稳定性,在处理大数据量的情况下,调度平台能否承载大量业务。我们不要谈论虚无之词,事实上,稳定性是它的核心调度特性,应该在后续的贡献中得到重视。

好了,今天就不多讲了,感谢我们这次主办方Apache Dolphinscheduler和白鲸开源的邀请,感谢各位远道而来的同学!

参与贡献


随着国内开源的迅猛崛起,Apache DolphinScheduler 社区迎来蓬勃发展,为了做更好用、易用的调度,真诚欢迎热爱开源的伙伴加入到开源社区中来,为中国开源崛起献上一份自己的力量,让本土开源走向全球。


参与 DolphinScheduler 社区有非常多的参与贡献的方式,包括:


贡献第一个PR(文档、代码) 我们也希望是简单的,第一个PR用于熟悉提交的流程和社区协作以及感受社区的友好度。


社区汇总了以下适合新手的问题列表:https://github.com/apache/dolphinscheduler/issues/5689


非新手问题列表:https://github.com/apache/dolphinscheduler/issues?q=is%3Aopen+is%3Aissue+label%3A%22volunteer+wanted%22


如何参与贡献链接:https://dolphinscheduler.apache.org/zh-cn/community/development/contribute.html


来吧,DolphinScheduler开源社区需要您的参与,为中国开源崛起添砖加瓦吧,哪怕只是小小的一块瓦,汇聚起来的力量也是巨大的。


参与开源可以近距离与各路高手切磋,迅速提升自己的技能,如果您想参与贡献,我们有个贡献者种子孵化群,可以添加社区小助手微信(Leonard-ds) ,手把手教会您( 贡献者不分水平高低,有问必答,关键是有一颗愿意贡献的心 )。

添加社区小助手微信(Leonard-ds,好友申请注明“入交流群+姓名+公司+职位信息“,群里是实名制,仅用于验证身份) 



添加小助手微信时请说明想参与贡献。


来吧,开源社区非常期待您的参与。



< 🐬🐬 >
更多精彩推荐

优秀用户案例有奖征集 | 活动火热开启,快来投稿!

用一杯星巴克的钱,训练自己私有化的ChatGPT

社区星力量 | 平等、包容、耐性,这对贡献小白来说很重要

☞去年办了这么多场Meetup都没有你,2023年赶紧安排起来!

线上 Meetup 讲师报名火热进行中!快来“秀”出你的才华和肌肉

Apache DolphinScheduler 荣获“掘进技术引力榜”「2023 年度 ROBUST 开源项目」奖项!



欢迎点赞在看

文章转载自海豚调度,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论