Flink源码学习一
Flink RPC
Flink RPC底层基于Scala的网络编程库Akka实现。Akka具有如下特点:
1. 它是对并发模型进行了更高的抽象
2. 它是异步、非阻塞、高性能的事件驱动编程模型
3. 它是轻量级事件处理(1GB内存可容纳百万级别个Actor)
Akka的通信模型如下图:

关于AKka的理解可以从ActorSystem和Actor的角度理解,以下几个方面有助于我们理解Akka。
1、ActorSystem是管理Actor生命周期的组件,Actor是负责通信的组件
2、每个Actor都有一个mailbox,别的Actor发送给它的消息都首先储存在MailBox中,通过这种方式可以实现异步通信
3、每个Actor是单线程的处理方式,不断的从MailBox中拉取消息执行处理,所以对于Actor的消息处理,不适合调用阻塞的处理方法
4、Actor可以改变它自身的状态,可以接受消息,也可以发送消息,还可以生成新的Actor
5、每一个ActorSystem和Actor都在启动的时候会给定一个Name。如果要从ActorSystem中,获取一个Actor,则可以通过以下的方式来进行Actor的获取:akka.tcp://actorsystem_name@master:9527/user/actor_name来进行定位
6. 如果一个Actor要和另外一个Actor进行通信,则必须先获取对方Actor的ActorRef对象,然后通过该对象发送消息即可
7. 通过tell发送异步消息,不接受响应,通过ask发送异步消息,得到Future返回,通过异步会到返回处理结果
使用Akka模拟实现Flink stadalone
代码如下:
JopManager:
package org.spiral.akka
import akka.actor.{
Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory
import scala.collection.mutable
/**
* 注释: 集群主节点抽象
* 1、receive 方法 接收其他 actor 发送过来的消息,然后进行模式匹配,进行消息处理,有可能返回消息
* 2、preStart() 方法 对象在构建成功之后,就会触发执行 preStart
* 3、postStop 方法 在对象销毁之前,会执行一次
* -
* 必须了解的知识:
* 1、伴生类 class A 和 伴生对象 object A(定义的方法,都是静态方法)
* 2、关于 scala 中定义的一个类的构造方法:
* 构造器: 类名后面的括号
* 代码实现: {} 中的一切能执行的代码
* 变量的初始化
* 代码块
* 静态代码块
* 不能执行的代码: 定义的方法(未调用, 内部类)
*
* @author spiral
* @since : 2021/7/6 1:26
*
*/
class MyJobManager(var hostName: String, var port: Int) extends Actor {
var id2TaskManagerInfo = new mutable.HashMap[String, TaskManagerInfo]()
var taskMangerInfos = new mutable.HashSet[TaskManagerInfo]()
override def preStart(): Unit = {
import scala.concurrent.duration._
import context.dispatcher
context.system.scheduler.schedule(0 millis, 5000 millis, self, CheckTimeOut)
}
override def receive: Receive = {
case RegisterTaskManager(nodeManagerId, memory, cpu) => {
val nodeManagerInfo = new TaskManagerInfo(nodeManagerId, memory, cpu)
println(s"节点 ${nodeManagerId}上线")
id2TaskManagerInfo.put(nodeManagerId, nodeManagerInfo)
taskMangerInfos += nodeManagerInfo
sender() ! RegisteredTaskManager(hostName + ":" + port)
}
case Heartbeat(nodeManagerId) => {
val concurrentTime = System.currentTimeMillis()
val nodeManagerInfo = id2TaskManagerInfo(nodeManagerId)
nodeManagerInfo.lastHeartBeatTime = concurrentTime
id2TaskManagerInfo(nodeManagerId) = nodeManagerInfo
taskMangerInfos += nodeManagerInfo
sender() !Heartbeat(hostName)
}
case CheckTimeOut => {
val currentTime = System.currentTimeMillis()
taskMangerInfos.filter(nm =>{
val heartbeatTimeout= 15000
val bool = currentTime - nm.lastHeartBeatTime > heartbeatTimeout
if (bool) {
println(s"节点${nm.taskmanagerid} 下线")
}
bool
}).foreach(deadNodeManager=>{
taskMangerInfos -= deadNodeManager
id2TaskManagerInfo.remove(deadNodeManager.taskmanagerid)
})
println("当期注册成功的节点数"+ taskMangerInfos.size+"\t 分别是:"+ taskMangerInfos.map(x => x.toString)

本文深入探讨Flink源码,重点关注Flink的RPC机制,包括Akka的使用、JobManager的ResourceManager、TaskManager的TaskExecutor,以及Flink的选举、监听和心跳机制。通过对关键组件和流程的分析,揭示了Flink如何实现高效稳定的分布式计算。
最低0.47元/天 解锁文章
1287

被折叠的 条评论
为什么被折叠?



