Flink源碼(一):Actor系統(tǒng)創(chuàng)建流程1

利用碎片時間閱讀了一下Flink的源碼,選擇Flink主要出發(fā)點還是了解一個穩(wěn)定的分布式計算系統(tǒng)的實現(xiàn),另外也是由于Flink相對更加成熟的Spark有其獨到的優(yōu)勢,相信其在下一代分布式計算中也會占有重要的地位。Flink的主要概念可以在官網(wǎng)了解

Flink系統(tǒng)作業(yè)的提交和調(diào)度都是利用AKKA的Actor通信,因此也是由此作為切入點,首先理清整個系統(tǒng)的啟動以及作業(yè)提交的流程和數(shù)據(jù)流。

flink basic concepts

圖中可以看到,一個完整的Flink系統(tǒng)由三個Actor System構(gòu)成,包括Client、JobManager(JM)以及TaskManager(TM)。下面對三個Actor系統(tǒng)的創(chuàng)建進行分析。

JM ActorSystem

JM是Flink系統(tǒng)的調(diào)度中心,這部分除了會看到JM ActorSystem的創(chuàng)建,還會了解到整個Flink系統(tǒng)的各個模塊的初始化與運行。

先找程序入口,從啟動腳本可以追溯到,每一個啟動腳本最終都會運行flink_deamon.sh 腳本,查看該腳本:

...
...

case $DAEMON in
    (jobmanager)
        CLASS_TO_RUN=org.apache.flink.runtime.jobmanager.JobManager
    ;;

    (taskmanager)
        CLASS_TO_RUN=org.apache.flink.runtime.taskmanager.TaskManager
    ;;

    (zookeeper)
        CLASS_TO_RUN=org.apache.flink.runtime.zookeeper.FlinkZooKeeperQuorumPeer
    ;;

    (*)
        echo "Unknown daemon '${DAEMON}'. $USAGE."
        exit 1
    ;;
esac


$JAVA_RUN $JVM_ARGS ${FLINK_ENV_JAVA_OPTS} "${log_setting[@]}" -classpath "`manglePathList "$FLINK_TM_CLASSPATH:$INTERNAL_HADOOP_CLASSPATHS"`" ${CLASS_TO_RUN} "${ARGS[@]}" > "$out" 2>&1 < /dev/null &
...
...

由此找到JM的程序入口:org.apache.flink.runtime.jobmanager.JobManager.scala,代碼中可以找到main函數(shù),調(diào)用runJobManager方法:

def runJobManager(
      configuration: Configuration,
      executionMode: JobManagerMode,
      listeningAddress: String,
      listeningPort: Int)
    : Unit = {


    //startActorSystemAndJobManagerActors返回jobManagerSystem
    val (jobManagerSystem, _, _, webMonitorOption, _) = startActorSystemAndJobManagerActors(
      configuration,
      executionMode,
      listeningAddress,
      listeningPort,
      classOf[JobManager],
      classOf[MemoryArchivist],
      Option(classOf[StandaloneResourceManager])
    )

    // 阻塞,直到系統(tǒng)退出
    jobManagerSystem.awaitTermination()

    webMonitorOption.foreach{
      webMonitor =>
        try {
          webMonitor.stop()
        } catch {
          case t: Throwable =>
            LOG.warn("Could not properly stop the web monitor.", t)
        }
    }
  }

runJobManager方法邏輯比較簡單,調(diào)用startActorSystemAndJobManagerActors方法中創(chuàng)建ActorSystem和JMActor,然后阻塞等待系統(tǒng)退出,看具體的JM創(chuàng)建過程:

def startActorSystemAndJobManagerActors(
      configuration: Configuration,
      executionMode: JobManagerMode,
      listeningAddress: String,
      listeningPort: Int,
      jobManagerClass: Class[_ <: JobManager],
      archiveClass: Class[_ <: MemoryArchivist],
      resourceManagerClass: Option[Class[_ <: FlinkResourceManager[_]]])
    : (ActorSystem, ActorRef, ActorRef, Option[WebMonitor], Option[ActorRef]) = {

    LOG.info("Starting JobManager")

    // Bring up the job manager actor system first, bind it to the given address.
    val hostPortUrl = NetUtils.hostAndPortToUrlString(listeningAddress, listeningPort)
    LOG.info(s"Starting JobManager actor system at $hostPortUrl")

    val jobManagerSystem = try {
      val akkaConfig = AkkaUtils.getAkkaConfig(
        configuration,
        Some((listeningAddress, listeningPort))
      )
      if (LOG.isDebugEnabled) {
        LOG.debug("Using akka configuration\n " + akkaConfig)
      }
      
      AkkaUtils.createActorSystem(akkaConfig)//創(chuàng)建ActorSystem全局僅有一個
    }
    catch {
       ...
       ...
    }

    ...
    ...//此處省略webMonitor的創(chuàng)建
    
    try {
      // bring up the job manager actor
      LOG.info("Starting JobManager actor")
      val (jobManager, archive) = startJobManagerActors(
        configuration,
        jobManagerSystem,
        jobManagerClass,
        archiveClass)

      // start a process reaper that watches the JobManager. If the JobManager actor dies,
      // the process reaper will kill the JVM process (to ensure easy failure detection)
      LOG.debug("Starting JobManager process reaper")
      jobManagerSystem.actorOf(
        Props(
          classOf[ProcessReaper],
          jobManager,
          LOG.logger,
          RUNTIME_FAILURE_RETURN_CODE),
        "JobManager_Process_Reaper")

      // bring up a local task manager, if needed
      if (executionMode == JobManagerMode.LOCAL) {
        LOG.info("Starting embedded TaskManager for JobManager's LOCAL execution mode")

        val taskManagerActor = TaskManager.startTaskManagerComponentsAndActor(
          configuration,
          ResourceID.generate(),
          jobManagerSystem,
          listeningAddress,
          Some(TaskManager.TASK_MANAGER_NAME),
          None,
          localTaskManagerCommunication = true,
          classOf[TaskManager])

        LOG.debug("Starting TaskManager process reaper")
        jobManagerSystem.actorOf(
          Props(
            classOf[ProcessReaper],
            taskManagerActor,
            LOG.logger,
            RUNTIME_FAILURE_RETURN_CODE),
          "TaskManager_Process_Reaper")
      }
      ...
      ...

      (jobManagerSystem, jobManager, archive, webMonitor, resourceManager)
    }
    ...
    ...
  }

這里可以看到startActorSystemAndJobManagerActors方法中利用AkkaUtils和flinkConfig創(chuàng)建了全局的ActorSystem,AkkaUtils也是對Actor創(chuàng)建的簡單封裝,這里不再贅述。緊接著利用剛創(chuàng)建的jobManagerSystem和jobManager的類名:jobManagerClass創(chuàng)建jobManager。除了jobManager以外,該方法中還創(chuàng)建了Flink的其他重要模塊,從返回值中可以清楚看到。另外本地模式啟動方式下,還會創(chuàng)建本地的啟動本地的taskManagerActor。繼續(xù)深入到startJobManagerActors,該方法接收jobManagerSystem等參數(shù),創(chuàng)建jobManager和archive并返回:

def startJobManagerActors(
      configuration: Configuration,
      actorSystem: ActorSystem,
      jobManagerActorName: Option[String],
      archiveActorName: Option[String],
      jobManagerClass: Class[_ <: JobManager],
      archiveClass: Class[_ <: MemoryArchivist])
    : (ActorRef, ActorRef) = {

    val (executorService: ExecutorService,
    instanceManager,
    scheduler,
    libraryCacheManager,
    restartStrategy,
    timeout,
    archiveCount,
    leaderElectionService,
    submittedJobGraphs,
    checkpointRecoveryFactory,
    savepointStore,
    jobRecoveryTimeout,
    metricsRegistry) = createJobManagerComponents(
      configuration,
      None)

    val archiveProps = Props(archiveClass, archiveCount)

    // start the archiver with the given name, or without (avoid name conflicts)
    val archive: ActorRef = archiveActorName match {
      case Some(actorName) => actorSystem.actorOf(archiveProps, actorName)
      case None => actorSystem.actorOf(archiveProps)
    }

    val jobManagerProps = Props(
      jobManagerClass,
      configuration,
      executorService,
      instanceManager,
      scheduler,
      libraryCacheManager,
      archive,
      restartStrategy,
      timeout,
      leaderElectionService,
      submittedJobGraphs,
      checkpointRecoveryFactory,
      savepointStore,
      jobRecoveryTimeout,
      metricsRegistry)

    val jobManager: ActorRef = jobManagerActorName match {
      case Some(actorName) => actorSystem.actorOf(jobManagerProps, actorName)
      case None => actorSystem.actorOf(jobManagerProps)
    }

    (jobManager, archive)
 }

這里首先createJobManagerComponents方法創(chuàng)建了jobManager的重要組成模塊,包括了存儲、備份等策略的組件實現(xiàn),還包括以后會遇到的scheduler、submittedJobGraphs,分別負責job的調(diào)度和作業(yè)的提交,這里暫不深入。
jobManagerActor已經(jīng)成功創(chuàng)建,但是Scala中一個Actor會繼承Actor類,并重寫receive方法接受信息并處理,由此可以發(fā)現(xiàn).JobManager類繼承FlinkActor,再看FlinkActor:

trait FlinkActor extends Actor {
  val log: Logger

  override def receive: Receive = handleMessage

  /** Handle incoming messages
    * @return
    */
  def handleMessage: Receive 

  def decorateMessage(message: Any): Any = {
    message
  }
}

可以看到receive方法被重寫,并賦值為handleMessage,所以處理消息的操作被放在FlinkActor子類Jobmanager的handleMessage方法中:

override def handleMessage: Receive = {

    ...
    ...
    case SubmitJob(jobGraph, listeningBehaviour) =>
      val client = sender()

      val jobInfo = new JobInfo(client, listeningBehaviour, System.currentTimeMillis(),
        jobGraph.getSessionTimeout)

      submitJob(jobGraph, jobInfo)

    ...
    ...

handleMessage方法中處理的消息很多,包括了諸如作業(yè)恢復,leader決策,TM注冊,作業(yè)的提交、恢復與取消,這里暫時只關(guān)注消息SubmitJob(jobGraph, listeningBehaviour),消息的定義很簡單,不再追溯。而SubmitJob消息的主要獲取Client傳來的jobGraph以及l(fā)isteningBehaviour。Flink的作業(yè)最后都會抽象為jobGraph交給JM處理。關(guān)于jobGraph的生成,會在后面的Job生成的過程中進行分析。
JM對job的處理函數(shù)submitJob(jobGraph, jobInfo),參數(shù)jobInfo中包括了Client端的ActorRef,用以Job處理結(jié)果的返回,該函數(shù)中實現(xiàn)了JM對作業(yè)的提交與處理的細節(jié),為突出重點,放在作業(yè)處理部分分析。但從該方法的注釋來看:

 /**
   * Submits a job to the job manager. The job is registered at the libraryCacheManager which
   * creates the job's class loader. The job graph is appended to the corresponding execution
   * graph and the execution vertices are queued for scheduling.
   *
   * @param jobGraph representing the Flink job
   * @param jobInfo the job info
   * @param isRecovery Flag indicating whether this is a recovery or initial submission
   */

在該方法中將Job注冊到libraryCacheManager,并將Job執(zhí)行餓的DAG加入到調(diào)度隊列。

小結(jié)

這里僅僅就JM Actor的創(chuàng)建過程對flink的源碼進行了分析,主要了解到flink系統(tǒng)JM部分ActorSystem的組織方式,main函數(shù)最終創(chuàng)建JM 監(jiān)聽客戶端的消息,并對作業(yè)進行調(diào)度和Job容錯處理,最終交由TaskManager進行處理。對于具體的調(diào)度和處理策略,JM和TM的通信會在以后進行分析。接下來首先看Client端的邏輯。

原創(chuàng)文章,原文到我的博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內(nèi)容

  • 簡單之美 | Apache Flink:特性、概念、組件棧、架構(gòu)及原理分析http://shiyanjun.cn/...
    葡萄喃喃囈語閱讀 7,450評論 0 27
  • 介紹 概述 Apache Flink是一個面向數(shù)據(jù)流處理和批量數(shù)據(jù)處理的可分布式的開源計算框架,它基于同一個Fli...
    stephen_k閱讀 51,207評論 0 22
  • 說后來也許有些遙遠。其實認識你不過一周有余。 只是相見恨晚。 當然我從沒冒然的去問過你,是否也是如此,我怕你不回消...
    凌阿深閱讀 1,063評論 10 15
  • 作者 言嘉 四月的春正濃 樹樹櫻花熱烈地開著 幾片飄飛的花瓣 完美地點綴了明媚的春 似少...
    言嘉閱讀 201評論 0 2