Flink源码学习(6)StreamTask的初始化和执行

Stream初始化

taskExecutor执行一个Task

当taskExecutor接受提交Task执行的请求,会调用:
CompletableFuture<Acknowledge> submitTask(
        TaskDeploymentDescriptor tdd, JobMasterId jobMasterId, @RpcTimeout Time timeout);
提交Task到TM
提交Job过来的JobManager和现在Active JobManager不是同一个的时候,就拒绝提交
初始化task的时候,内部初始化一个执行线程,就是task类启动,把TDD变成Task
Task task =
        new Task(
                jobInformation,
                taskInformation,
                tdd.getExecutionAttemptId(),
                tdd.getAllocationId(),
                tdd.getProducedPartitions(),
                tdd.getInputGates(),
                memoryManager,
                sharedResources,
                taskExecutorServices.getIOManager(),
                taskExecutorServices.getShuffleEnvironment(),
                taskExecutorServices.getKvStateService(),
                taskExecutorServices.getBroadcastVariableManager(),
                taskExecutorServices.getTaskEventDispatcher(),
                externalResourceInfoProvider,
                taskStateManager,
                taskManagerActions,
                inputSplitProvider,
                checkpointResponder,
                taskOperatorEventGateway,
                aggregateManager,
                classLoaderHandle,
                fileCache,
                taskManagerConfiguration,
                taskMetricGroup,
                partitionStateChecker,
                getRpcService().getScheduledExecutor(),
                channelStateExecutorFactoryManager.getOrCreateExecutorFactory(jobId));
  1. task的构造方法

    1. 封装一个TaskInfo,把task在执行过程中必备的描述信息放入
      this.taskInfo =
              new TaskInfo(
                      taskInformation.getTaskName(),
                      taskInformation.getMaxNumberOfSubtasks(),
                      executionAttemptID.getSubtaskIndex(),
                      taskInformation.getNumberOfSubtasks(),
                      executionAttemptID.getAttemptNumber(),
                      String.valueOf(slotAllocationId));

       

    2. 创建shuffle context
      final ShuffleIOOwnerContext taskShuffleContext =
              shuffleEnvironment.createShuffleIOOwnerContext(
                      taskNameWithSubtaskAndId, executionId, metrics.getIOMetricGroup());

       

    3. 初始化ResultPartition和ResultSubPartition
  1. 一个Task的执行有输入和输出,关于输出的抽象ResultPartition和ResultSubPartition
  2. 具体实现是resultPartition
  3. 批处理创建一个ReleaseOnConsumptionResultPartition,流处理创建ResultPartition
  4. subPartition的数量等于下游task的个数
  1. 输入的抽象是InputGate和InputChannel,也会init
    1.   singleInputGate创建一个给inputGate

        创建inputChannel数组,有两种情况,createUnknownInputChannel也可能是createKnownInputChannel,正常情况是known的。当前是本地获取数据的话localRecoveredInputChannel,正常是remote

  2. 初始化一个thread,task的构造方法
  3. sourceStreamTask和streamTask初始化
    1. 创建recordWriter
    2. 处理输入streamTask.processInput=new mailboxProcess
    3. 创建状态后端stateBackend
    4. 通过stateBackend创建checkpointStorage
    5. 获取分流器
      1. 用于调整并行度,如果上下游streamNode的并行度一致就用forwardPartition分发策略
      2. 如果不一致就使用RebalancePartition实现

    

提交job到standalone集群运行的时候,在client构建streamGraph顶点式streamNode,边是streamEdge的时候,根据生成的transformation为streamGraph生成stramNode,生成Node的hi后判断如果该operator是streamSource的话,就会指定该streamTask的invokableClass为sourceStreamTask
 
task.Run
流式引擎,上游task执行完一条数据计算,就会发送结果给下游task,规则由streamPartitioner来指定
一条数据在一个task执行完毕之后,就要发送给下游另外一个task,这个过程,网络数据传输过程,由netty支持的,具体是由inputChannel实现的
  1. 状态从created、改为deploying
  2. 拉起resultPartitionWriter和inputGate
    1. 构造task的时候,就已经初始化过了
    2. 注册result Partition Writer
    3. 如果注册过了就报错
    4. inputChannel分配buffer
  3. 包装task的各种组件 environment
  4. 通过反射实例化streamTask
    1. sourceStreamTask
      1. 是flink job最开始的task,对接source,有一个专门的线程接受数据
      2. source用于产生data的一个线程
    2. oneInputStreamTask
  5. 状态从deploying改为running
  6. 启动streamTask
  7. streamTask正常结束处理buffer数据
  8. 状态从running改为finished
state管理源码剖析
flink具有有状态计算的特点
state是flink job的task运行过程中产生的中间数据,辅助task执行计算,同时存储中间状态帮助flink job的重启恢复。保存状态非常重要
state要配合checkpoint机制保证flink失败之后正确的回复错误
flink自己周期性的快照叫checkpoint,手动保存叫savepoint
flink状态分类
keyedState具体的key绑定,只能在keyedStream上的函数和算子中使用
OperatorState和operator的一个特定的并行实例绑定,例如kafka connector
Keyed state也可以看作是operator state的一种分区partition形式,每一个key都关联一个状态分区state-partition
无论是operator state还是keyed state都有两种形式:Managed state和raw state。
所有跟state有关的都由stateBackend完成,核心有abstractStateBackend,三种存储类型
FileSystem将state存储在taskmanager的内存中,checkpoint存储在文件系统内存中,适合存储量大,文件系统中需要序列化反序列化的开销速度慢点,但是比memory好
Memory 保存在内存中,很快,适合小state任务,不能上生产。存储在内存中
RocksDB,基于内存的数据库系统,把状态存储在reocksDB,ckeckpoint存在文件系统,比memory快,GC少,支持异步snapshot持久化,用于存储state量大的,window窗口很长的一些job合适
 
 
  1. StreamTask运行

 

  1. beforeInvoke
    1. operatorChain的初始化,recoveredChannelState初始化
    2. 当第一个operator执行完毕的时候就有collector收集计算结果再去调用第二个operator执行processElement,通过output收集处理之后的结果数据
      1. userFunction.run:function->transformation->streamOperator,headOperator的run方法
      2. socket连接读数据
      3. channelSelector确定目标channel决定record被分发到哪一个分区
  2. runMailboxLoop
不停的处理mail
  1. afterInvoke
完成task结束之前的操作
  1. cleanUpInvoke

 

posted @ 2024-05-03 12:36  Heinrich♣  阅读(42)  评论(0编辑  收藏  举报