1、JobManager源码分析
JobManager 是 Flink 集群的主节点,它包含三大重要的组件
1、ResourceManager
Flink的集群资源管理器,只有一个,关于slot的管理和申请等工作,都由他负责
2、Dispatcher
负责接收用户提交的 JobGragh, 然后启动一个 JobManager, 类似于 YARN 集群中的
AppMaster 角色,类似于 Spark Job 中的 Driver 角色
3、WebMonitorEndpoint
里面维护了很多很多的Handler,如果客户端通过 flink run 的方式来提交一个 job 到 flink
集群,最终,是由 WebMonitorEndpoint 来接收,并且决定使用哪一个 Handler 来执行处理
submitJob ===> SubmitJobHandler
JobMaster(Dispatcher中创建)
负责一个具体的 Job 的执行,在一个集群中,可能会有多个 JobMaster同时执行,类似于 YARN
集群中的 AppMaster 角色,类似于 Spark Job 中的 Driver 角色
flink job执行总结:
Flink 集群的主节点内部运行着:ResourceManager 和 Dispatcher,当 client 提交一个 job 到
集群运行的时候(客户端会把该 Job 构建成一个 JobGragh 对象),Dispatcher 负责拉起
JobMaster来负责这个 Job 内部的 Task 的执行,执行Task所需要的资源,JobMaster向
ResourceManager 申请。
StandaloneSessionClusterEntrypoint
ClusterEntrypoint.runClusterEntrypoint-> startCluster -> ClusterEntrypoint.runCluster
private void runCluster(Configuration configuration, PluginManager pluginManager) throws Exception {
synchronized(lock) {
/**
* TODO ->
* 注释: 初始化服务,如 JobManager 的 Akka RPC 服务,HA 服务,心跳检查服务,metric service
* 这些服务都是 Master 节点要使用到的一些服务
* 1、commonRpcService: 基于 Akka 的 RpcService 实现。RPC 服务启动 Akka 参与者来接收从 RpcGateway 调用 RPC
* 2、haServices: 提供对高可用性所需的所有服务的访问注册,分布式计数器和领导人选举
* 3、blobServer: 负责侦听传入的请求生成线程来处理这些请求。它还负责创建要存储的目录结构 blob 或临时缓存它们
* 4、heartbeatServices: 提供心跳所需的所有服务。这包括创建心跳接收器和心跳发送者。
* 5、metricRegistry: 跟踪所有已注册的 Metric,它作为连接 MetricGroup 和 MetricReporter
* 6、archivedExecutionGraphStore: 存储执行图ExecutionGraph的可序列化形式。
*/
initializeServices(configuration, pluginManager);
// TODO 注释: 将 jobmanager 地址写入配置
// write host information into configuration
configuration.setString(JobManagerOptions.ADDRESS, commonRpcService.getAddress());
configuration.setInteger(JobManagerOptions.PORT, commonRpcService.getPort());
/*************************************************
* TODO
* 注释: 初始化一个 DefaultDispatcherResourceManagerComponentFactory 工厂实例
* 内部初始化了四大工厂实例
* 1、DispatcherRunnerFactory = DefaultDispatcherRunnerFactory
* 2、ResourceManagerFactory = StandaloneResourceManagerFactory
* 3、RestEndpointFactory(WenMonitorEndpoint的工厂) = SessionRestEndpointFactory
* 返回值:DefaultDispatcherResourceManagerComponentFactory
* 内部包含了这三个工厂实例,就是三个成员变量
* -
* 再补充一个:dispatcherLeaderProcessFactoryFactory = SessionDispatcherLeaderProcessFactoryFactory
*
* --> StandaloneSessionClusterEntrypoint.createDispatcherResourceManagerComponentFactory
*
*/
final DispatcherResourceManagerComponentFactory dispatcherResourceManagerComponentFactory =
createDispatcherResourceManagerComponentFactory(configuration);
/*************************************************
* TODO
* 注释:启动关键组件:Dispatcher 和 ResourceManager。
* 1、Dispatcher: 负责用于接收作业提交,持久化它们,生成要执行的作业管理器任务,并在主任务失败时恢复它们。
* 此外, 它知道关于 Flink 会话集群的状态。负责为这个新提交的作业拉起一个新的 JobManager 服务
* 2、ResourceManager: 负责资源的分配和记帐。在整个 Flink 集群中只有一个 ResourceManager,资源相关的内容都由这个服务负责
* registerJobManager(JobMasterId, ResourceID, String, JobID, Time) 负责注册 jobmaster,
* requestSlot(JobMasterId, SlotRequest, Time) 从资源管理器请求一个槽
* 3、WebMonitorEndpoint: 服务于 web 前端 Rest 调用的 Rest 端点,用于接收客户端发送的执行任务的请求
*
* --> DefaultDispatcherResourceManagerComponentFactory.create
*/
clusterComponent = dispatcherResourceManagerComponentFactory
.create(configuration, ioExecutor, commonRpcService, haServices,
blobServer, heartbeatServices, metricRegistry,
archivedExecutionGraphStore,
new RpcMetricQueryServiceRetriever(metricRegistry.getMetricQueryServiceRpcService()),
this);
/*************************************************
* TODO
* 注释:集群关闭时的回调
*/
clusterComponent.getShutDownFuture().whenComplete((ApplicationStatus applicationStatus, Throwable throwable) -> {
if(throwable != null) {
shutDownAsync(ApplicationStatus.UNKNOWN, ExceptionUtils.stringifyException(throwable), false);
} else {
// This is the general shutdown path. If a separate more specific shutdown was
// already triggered, this will do nothing
shutDownAsync(applicationStatus, null, true);
}
});
}
}
1、 initializeServices
-> commonRpcService = AkkaRpcServiceUtils.createRemoteRpcService -> createAndStart
-> new AkkaRpcService -> supervisor = startSupervisorActor();
SupervisorActor是个actor (class SupervisorActor extends AbstractActor extends Actor)
-> final ActorRef actorRef = SupervisorActor.startSupervisorActor(actorSystem, terminationFutureExecutor);
-> Supervisor.create(actorRef, terminationFutureExecutor) -> new Supervisor()
2、 创建和启动WebMonitorEndpoint,ResourceManager,Dispatcher
--> clusterComponent = dispatcherResourceManagerComponentFactory.create
-> DefaultDispatcherResourceManagerComponentFactory.create(
创建和启动WebMonitorEndpoint,ResourceManager,Dispatcher)
2.1 启动 webMonitorEndpoint
-> webMonitorEndpoint.start() -> RestServerEndpoint.start
-> (2.1.1) 初始化handler(包括: JobSubmitHandler)
handlers = initializeHandlers -> DispatcherRestEndpoint.initializeHandlers
-> super.initializeHandlers ->
/*************************************************
* TODO
* 注释: Handler 容器初始化
*
* ChannelInboundHandler channelRead0() 方法,这个方法会自动被 Netty 去调用执行
* 不管是这里初始化的那个 Handler, 里面都有一个 handleRequest 的方法
* channelRead0() 的底层,最终调用的就是 Hnadler.handleRequest() 方法
* 将来我们提交 Job 的时候,最终,由 WebMonitorEndpoint(DispatcherRestEndpoint) 接收到,
* 跳转到使用 JobSubmitHandler 来执行 最终执行请求的就是 JobSubmitHandler.handleRequest()
* 这些 Handler 的作用,其实就对应到 Flink web 页面的 rest 服务, Handler == Servlet 如 bigdata02:port/list
*/
ArrayList<Tuple2<RestHandlerSpecification, ChannelInboundHandler>> handlers = new ArrayList<>(30);
-> new JobSubmitHandler(将来客户端提交应用程序上来,由 JobManager 中的 Netty 服务端的 JobSubmitHandler 来执行处理)
->(2.1.2) 启动 Netty 服务端,添加所有初始化好的handler -> bootstrap = new ServerBootstrap();
-> bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(initializer);
->(2.1.3) 启动 startInternal -> WebMonitorEndpoint.startInternal
选举通用套路
/*************************************************
* TODO
* 注释: 选举 ZooKeeperLeaderElectionService
* this 很重要,哪个对象进行选举操作就是那个对象 这里是WebMonitorEndpoint
* 选举成功后会调用该对象的grantLeaderShip方法
* 不管你在那个地方见到这种格式的代码:leaderElectionService.start(this);
* 一定要记住,最终,
* 1、参与选举的 某个获胜的角色会调用:
* leaderElectionService.isLeader() ==> leaderContender.grantLeaderShip()
* 2、参与选举的 某个失败的角色会调用: leaderElectionService.notLeader()
*/
leaderElectionService.start(this);
-> ZooKeeperLeaderElectionService.start(){
/*************************************************
* TODO
* 注释: Fink 的 选举,和 HBase 一样都是通过 ZooKeeper 的 API 框架 Curator 实现的
* 1、leaderLatch.start(); 事实上就是举行选举
* 2、leaderLatch.addListener 添加了监听器 当选举结束的时候:
* 如果监听到成功了: isLeader()
* 如果监听到失败了: notLeader()
*/
leaderLatch.addListener(this);
leaderLatch.start();
}
-> isLeader(){
/*************************************************
* TODO
* 注释: 分配 LeaderShip
* leaderContender = JobManagerRunnerImpl
* leaderContender = ResourceManager
* leaderContender = DefaultDispatcherRunner
* leaderContender = WebMonitorEndpoint
* 当前是WebMonitorEndpoint,后续 哪个组件进行选举就执行那个组件的grantLeadership方法
*
* leaderElectionService.start(this);
* leaderContender = this
*/
leaderContender.grantLeadership(issuedLeaderSessionID);
}
--> WebMonitorEndpoint.grantLeadership(){
* TODO
* 注释: 确认 Leader
*/
leaderElectionService.confirmLeadership(leaderSessionID, getRestBaseUrl());
}
2.2 创建 StandaloneResourceManager 实例对象和SlotManager
DefaultDispatcherResourceManagerComponentFactory.create()
resourceManager = resourceManagerFactory.createResourceManager -> ResourceManagerFactory.createResourceManager
--> (2.2.1) 创建SlotManager
createResourceManagerRuntimeServices -> ResourceManagerRuntimeServices.fromConfiguration
-> SlotManager slotManager = new SlotManagerImpl
--> (2.2.2) 创建 ResourceManager 实例
createResourceManager -> StandaloneResourceManagerFactory.createResourceManager
-> new StandaloneResourceManager -> super -> ResourceManager -> super -> FencedRpcEndpoint -super
-> RpcEndpoint(){
this.rpcService = checkNotNull(rpcService, "rpcService");
this.endpointId = checkNotNull(endpointId, "endpointId");
/*************************************************
* TODO
* 注释: 启动 ResourceManager 的 RPCServer 服务
* 这里启动的是 ResourceManager 的 Rpc 服务端。
* 接收 TaskManager启动好了而之后, 进行注册和心跳,来汇报 Taskmanagaer 的资源情况
* 通过动态代理的形式构建了一个Server、
*
* --> AkkaRpcService.startServer
*/
this.rpcServer = rpcService.startServer(this);
/*************************************************
* TODO
* 注释: 线程池的初始化
*/
this.mainThreadExecutor = new MainThreadExecutor(rpcServer, this::validateRunsInMainThread);
}
-> rpcService.startServer(this); -> AkkaRpcService.startServer(){
/*************************************************
* TODO 通过代理的方式来获取一个 ActorRef 对象
* 注释: RpcServer 实现类
* JDK 提供的动态代理: Proxy InvocationHandler
*/
akkaInvocationHandler = new AkkaInvocationHandler(akkaAddress, hostname, actorRef, configuration.getTimeout(),
configuration.getMaximumFramesize