为了账号安全,请及时绑定邮箱和手机立即绑定

Apache Flink 源码解析(二)系统架构, 启动与注册

标签:
Flink

概述

这篇文章侧重于分析JobManager和TaskManager的启动过程以及注册,还有Flink的implementation中所用到的设计模式。本文从本地与standalone模式进行解析。

Akka 简介

  • 因为组件之间的信息传递是通过Akka工具包,所以在这儿我做一个简单的解释

  • 首先参考Akka官方文档给出的一个抽象的图


    webp

    image

  • 如图就是对ActorSystem的一个高度抽象,所有的Actor成树状,user actor的子孙就是用户创建的Actor,system下面是Akka的监管与支持的Actor,往往不需要用户过多参与

  • Actor之间如果持有对方的ActorRef则可以向对方发送消息

  • 父Actor负责监管子Actor抛出的异常能被父Actor处理,则父Actor可以重启或者废弃它,如果不能处理,会继续向上抛异常。一个Actor如果推出,那么它的所有子Actor都会退出。

  • 它们共同组成了一个ActorSystem

Flink的架构

  • 首先上一张从Flink官方文档拿来的架构图


    webp

    process-model.png

  • 这次我会从JobManager和TaskManager着手来解析Flink的启动过程

  • Flink中JobManager与TaskManager,JobManager与Client的交互是基于Akka工具包的,是通过消息驱动,这样就把中心放到了消息的接收,发送与处理,而且由于对每个Akka中的Actor来说,消息是同步的,排在一个队列中,极大地简化了多线程程序设计的复杂度,关于Akka的一些学习资料我会放在文章最后

  • 下面的启动过程我会分为入口,ActorSystem的创建,JobManager的启动,TaskManager的启动和注册这几块来讲

    入口

    ActorSystem创建

    JobManager

    TaskManager

    TaskManager的注册

    • AcknowledgeRegistration注册成功,如果isConnected为true则是已连接,判断该消息是否由当前链接的JobManager发送并写入日志,如果未连接,调用associateWithJobManager进行接收消息钱的准备工作(后续会深入解析)


      webp

      ackRegistration.png

    • AlreadyRegistered重复注册,写入日志,逻辑与 AcknowledgeRegistration消息的处理相同

    • RefuseRegistration注册失败,如果JobManager地址存在,则发送新的TriggerTaskManagerRegistration, 重复到TaskManager注册部分的福州,如果没有地址,则验证如果发送消息的JobManager是否是当前已连接的JobManager写入日志,对结果没有影响

    • 根据消息找到相应的TaskManager地址

    • 一旦JobManager接收到RegisterTaskManager消息,先想ResourceManager注册(这边不做介绍,这边的?是Akka里面发送ask消息并期望得到一个返回值),如果Resource注册失败则向发送ReconnectResourceManager消息进行重试

    • 如果该TaskManager已经注册在instanceManager中,则发送AlreadyRegistered消息给相应的TaskManager

    • 如果还未注册,则向instanceManager注册该TaskManager,并发送AcknowledgeRegistration给相应的TaskManager

    • 出现异常则拒绝注册,发送RefuseRegistration消息

    • 在handleJobManagerLeaderAddress中触发了triggerTaskManagerRegistration注册函数

    • 在该函数中,提取超时信息设置,以及当前尝试的ID,清空已经在调度器中应该被废弃的注册消息,并向自身发送尝试次数为第一次的TriggerTaskManagerRegistration消息


      webp

      triggerTaskManagerRegistration.png

    • 因为TriggerTaskManagerRegistration是在TaskManager Actor接收到RegistrationMessage的子类,所以在接收到该消息时,根据RegistrationMessage来匹配,并调用handleRegistrationMessage方法


      webp

      handleRegistrationMessage.png

    • 匹配到TriggerTaskManagerRegistration消息后,先判断该消息有没有失效,如果没有,则有三种情况


      webp

      handleTriggerTaskManagerRegistration.png

    • 如果已连接成功,写入日志

    • 如果超时,写入日志并推出

    • 除此之外,进行下一次尝试,向JobManager Actor发送RegisterTaskManager消息,并在调度其中注册下一次TriggerTaskManagerRegistration的消息的发送,知道出现第一种情况注册成功或第二种情况注册失败为止

    • 在TaskManager的注册中,设计了与JobManager的消息交互,所以单独分开来讲

    • TaskManager中的发送注册请求

    • JobManager接收到注册请求消息


      webp

      handleRegisterTaskManager.png

    • TaskManager接到返回消息



    • TaskManager Actor一旦接收到该Message要不就是刚启动,要不就是JobManager的Leader发生了改变,调用handleJobManagerLeaderAddress函数

      webp

      handleGrantLeadershipMessage.png

    • 在handleJobManagerLeaderAddress函数中,先断开连接,然后出发TaskManager的注册操作


      webp

      handleJobManagerLeaderAddressMessage.png

    • 首先启动leaderRetrievalService,和LeaderElection一样使用了策略模式来处理是否高可用两种情况,观察者模式来接收对象变化并调用callback方法


      webp

      startLeaderRetrievalService.png

    • 这边同样关注Standalone版本的Implementation,在start中调用TaskManager的notifyLeaderAddress回调方法,并将jobManager地址作为参数传入


      webp

      ldeaderRetrievalServiceStart.png

    • 在TaskManager实现的notifyLeaderAddress方法中发送JobManagerLeaderAddress消息给自己


      webp

      notifyLeaderAddress.png

    • 如果为本地模式,则直接调用startTaskManagerComponentAndActor方法,如果是用脚本启动,则会进入TaskManager的main函数

    • 对于standalone模式

    • 在startTaskManagerComponentsAndActor创建ioManager,network,leaderRetrievalService等创建TaskManager所需要的参数,通过actorSystem来创建TaskManager Actor


      webp

      createTaskManager.png

    • 在main函数中解析完命令行参数并生成配置文件对象后,会生成resourceID作为身份


      webp

      resourceIDGenerate.png

    • 接下来会新建一个Callable对象并调用selectNetworkInterfaceAndRunTaskManager方法


      webp

      selectNetworkAndRunTaskManager.png

    • 在selectNetworkInterfaceAndRunTaskManager方法中,先绑定地址与端口号,建立远程ActorSystem,然后调用runTaskManager方法


      webp

      runTaskManager1.png

    • 在runTaskManager方法中通过调用startTaskManagerComponentsAndActor并传入远程ActorSystem,至此与local模式的启动一致,区别在于ActorSystem是与JobManager一致还是远程另外一个ActorSystem,但对于开发者来说对Actor之间的消息传递方法并没有任何区别


      webp

      startTaskManagerComponentsAndActorRemote.png

    • TaskManager Actor创建

    • prestart

    • handleMessage(启动相关)

    • 根据消息的类型进行匹配,当接收到GrantLeadership的Message后,会匹配到如下代码


      webp

      handleGrantLeadershipMessage.png


      首先确认身份,再判断是否为高可用模式,如果是高可用模式还需要发送恢复任务的消息,如果不是,JobManager的启动已完成

    • 启动leaderElectionService,将JobManager本身作为参数传入


      webp

      startLeaderElectionService.png


      这边值得一提的是设计模式,策略模式与观察者模式,因为leaderElectionService是一个Java的接口,在生产环境中有非高可用(单点失败)的Implementation与基于Zookeeper的高可用模式,可以再运行时更改该接口的行为。JobManager还实现了LeaderContender接口,实现了多个CallBack方法,当leaderElectionService被修改时,会通知JobManager来调整,典型的观察者模式,适用于在高可用模式下作为Leader的JobManager被更改的情况。

    • 接着是启动SubmittedJobGraph服务,失败恢复服务与Metrics,这些会在以后讲到

    • 在这儿调用了leaderElectionService,对高可用模式的解析可能会在以后补上,现在侧重于Standalone模式下的解析,在StandaloneLeaderElectionService中,因为只有一个JobManager,所以直接在start时调用LeaderContentder中的callback方法,也就是JobManager的grantLeadership方法


      webp

      grantLeadership Method.png

    • 在该方法中向JobManager Actor本身发送了一条消息,从而在handleMessage中进行接收处理(!在Scala的Akka包中是发送消息的方法)

    • 对于JobManager与TaskManager的启动与关闭,会有三个环节,preStart,handleMessage与postStop

    • 对于每一个Actor,必须Override抽象方法handleMessage,也就是Actor针对收到的message做的业务逻辑,可以选择Override preStart和postStop方法,做一些启动前准备与结束时的清理

    • (关于Scala的多重继承,以及菱形继承的问题我这边不做过多讨论,网上有一些帖子,也可以通过阅读Scala In Depth来获得更深入了解,这对Java程序员来说是一个新的概念)

    • 首先是启动前准备preStart

    • handleMessage(启动相关)



    • 在这里Flink做了一个Akka的工具类来简化逻辑,本质上就是从Configuration配置文件类中提取Akka启动所需配置信息,并根据配置建立ActorSystem,ActorSystem可以是本机的,也可以是跨多台机器的,具体逻辑都在AkkaUtils中,有兴趣可以研究

      webp

      startJobManagerSystem.png

    • 建立JobManager的可视化WebMonitor,这里不做介绍

    • 重点出现,在这里通过ActorSystem建立了JobManager的Actor,并建立了一个JobManager process reaper来做简单的失败检测


      webp

      createJobManager.png

    • (*)如果实在Local模式下的话,则启动一个内嵌的TaskManager,如果不是,则需要在另一个JVM中启动TaskManager,通过taskmanager.sh脚本来完成


      webp

      localTaskManager.png

    • 针对每一个TaskManager Actor再启动一个WebMonitor可视化界面

    • 如果看过该系列上一篇文章,应该知道怎么找到在Local和Standalone模式下程序的入口

    • 这里我直接给出来,就是org.apache.flink.runtime.jobmanager 中的main方法

    • main方法主要可以分为,一是启动环境的准备


      webp

      JobManager Startup.png

    • 二是处理输入的命令行参数,并准备好包含配置信息的Configuration对象,以及host地址与端口号,还有运行模式


      webp

      configuration prepare.png

    • 三是新建一个Callable对象,在另一个线程上运行runJobManager方法


      webp

      mainRunJobManager.png

    • runJobManager有 个重载方法,第一个方法中绑定了端口号并建立了socket链接,并调用第二个重载方法


      webp

      bindport.png

    • 第二个重载方法根据本机硬件情况建立futureExecutor(对Future类不了解的话可以简单理解成Java中带返回值的Runnable,细节不做讨论), ioExecutor,并调用startActorSystemAndJobManagerActors方法建立ActorSystem并等待结束


      webp

      startActorSystem.png

总结

至此,JobManager和TaskManager的启动过程以及TaskManager的注册过程解析已经完成。解析中没有办法做到面面俱到,把自己觉得重要的点挑了出来,主要是能再时间上形成一个线,方便理解。
下面还有一个根据时间线来做的思维导图,侧重于Local模式下的启动,虚线代表调用或者是消息。


webp

Flink start up.jpg



作者:铛铛铛clark
链接:https://www.jianshu.com/p/0cdfa2a05ebd


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消