Flink源码-Task执行

本文围绕Flink展开,介绍了Flink的JobManager和TaskManager组件,JobManager启动时包含WebMonitorEndpoint、Dispatcher和ResourceManager;TaskManager负责本机slot资源管理与task执行。还详细阐述了TaskExecutor#submitTask方法,涉及Task的实例化与线程启动,以及后续代码加载和实例化逻辑。

上一节我们分析到了Execution的生成,然后调用taskManagerGateway.submitTask方法提交task,提交的时候会将executionVertex封装成TaskDeploymentDescriptor,task的提交与执行涉及到了flink多个组件的配合,之前没有详细讲过,可能有的小伙伴有点不太清楚,这里我们花点时间介绍一下。

1.Flink各个组件介绍

1.JobManager

在JobManager启动的时候会启动三个比较重要的组件:

1. WebMonitorEndpoint: 里面有大约六七十个handler,如果客户端使用fink run的方式来提交一个job,最终会由WebMonitorEndpoint的submitJobHandler来处理。

2. Dispatcher:  负责接收用户提交的jobGraph,然后启动Jobmaster。

3. ResourceManager: Flink集群的资源管理器,关于slot的管理和申请工作都由他负责。

2.TaskManager

TaskManager:是flink的worker节点,它是负责flink中本机slot资源的管理以及task的执行。TaskManager上基本的资源单位时slot,一个作业的task最终会在TaskManager上的slot上运行,TaskManager负责维护本地的slot资源列表,并和jobMaster进行通信。

2.TaskExecutor#submitTask

上节我们在execution中看到它调用了taskManagerGateway.submitTask方法提交task,taskManagerGateway是一个接口,我们点进它的子类RpcTaskManagerGateway中可以看到它调用了TaskExecutorGateway的submitTask方法。

TaskExecutorGateway也是一个接口,我们可以点进它的子类TaskExecutor,然后我们找到他的submitTask方法

@Override
	public CompletableFuture<Acknowledge> submitTask(
			TaskDeploymentDescriptor tdd,
			JobMasterId jobMasterId,
			Time timeout) {

		try {
			//获取jobid和尝试次数id
			final JobID jobId = tdd.getJobId();
			final ExecutionAttemptID executionAttemptID = tdd.getExecutionAttemptId();
			//获取jobmanager的连接
			final JobTable.Connection jobManagerConnection = jobTable.getConnection(jobId).orElseThrow(() -> {
				final String message = "Could not submit task because there is no JobManager " +
					"associated for the job " + jobId + '.';

				log.debug(message);
				return new TaskSubmissionException(message);
			});

			if (!Objects.equals(jobManagerConnection.getJobMasterId(), jobMasterId)) {
				final String message = "Rejecting the task submission because the job manager leader id " +
					jobMasterId + " does not match the expected job manager leader id " +
					jobManagerConnection.getJobMasterId() + '.';

				log.debug(message);
				throw new TaskSubmissionException(message);
			}

			if (!taskSlotTable.tryMarkSlotActive(jobId, tdd.getAllocationId())) {
				final String message = "No task slot allocated for job ID " + jobId +
					" and allocation ID " + tdd.getAllocationId() + '.';
				log.debug(message);
				throw new TaskSubmissionException(message);
			}

			// re-integrate offloaded data:
			try {
				tdd.loadBigData(blobCacheService.getPermanentBlobService());
			} catch (IOException | ClassNotFoundException e) {
				throw new TaskSubmissionException("Could not re-integrate offloaded TaskDeploymentDescriptor data.", e);
			}

			// deserialize the pre-serialized information
			final JobInformation jobInformation;
			final TaskInformation taskInformation;
			try {
				//反序列化获取task信息和Job信息
				jobInformation = tdd.getSerializedJobInformation().deserializeValue(getClass().getClassLoader());
				taskInformation = tdd.getSerializedTaskInformation().deserializeValue(getClass().getClassLoader());
			} catch (IOException | ClassNotFoundException e) {
				throw new TaskSubmissionException("Could not deserialize the job or task information.", e);
			}

			if (!jobId.equals(jobInformation.getJobId())) {
				throw new TaskSubmissionException(
					"Inconsistent job ID information inside TaskDeploymentDescriptor (" +
						tdd.getJobId() + " vs. " + jobInformation.getJobId() + ")");
			}
			//将task相关信息加入到taskMetricGroup
			TaskMetricGroup taskMetricGroup = taskManagerMetricGroup.addTaskForJob(
				jobInformation.getJobId(),
				jobInformation.getJobName(),
				taskInformation.getJobVertexId(),
				tdd.getExecutionAttemptId(),
				taskInformation.getTaskName(),
				tdd.getSubtaskIndex(),
				tdd.getAttemptNumber());

			InputSplitProvider inputSplitProvider = new RpcInputSplitProvider(
				jobManagerConnection.getJobManagerGateway(),
				taskInformation.getJobVertexId(),
				tdd.getExecutionAttemptId(),
				taskManagerConfiguration.getTimeout());

			final TaskOperatorEventGateway taskOperatorEventGateway = new RpcTaskOperatorEventGateway(
				jobManagerConnection.getJobManagerGateway(),
				executionAttemptID,
				(t) -> runAsync(() -> failTask(executionAttemptID, t)));

			TaskManagerActions taskManagerActions = jobManagerConnection.getTaskManagerActions();
			CheckpointResponder checkpointResponder = jobManagerConnection.getCheckpointResponder();
			GlobalAggregateManager aggregateManager = jobManagerConnection.getGlobalAggregateManager();

			LibraryCacheManager.ClassLoaderHandle classLoaderHandle = jobManagerConnection.getClassLoaderHandle();
			ResultPartitionConsumableNotifier resultPartitionConsumableNotifier = jobManagerConnection.getResultPartitionConsumableNotifier();
			PartitionProducerStateChecker partitionStateChecker = jobManagerConnection.getPartitionStateChecker();

			//本地状态存储
			final TaskLocalStateStore localStateStore = localStateStoresManager.localStateStoreForSubtask(
				jobId,
				tdd.getAllocationId(),
				taskInformation.getJobVertexId(),
				tdd.getSubtaskIndex());

			final JobManagerTaskRestore taskRestore = tdd.getTaskRestore();

			final TaskStateManager taskStateManager = new TaskStateManagerImpl(
				jobId,
				tdd.getExecutionAttemptId(),
				localStateStore,
				taskRestore,
				checkpointResponder);

			MemoryManager memoryManager;
			try {
				memoryManager = taskSlotTable.getTaskMemoryManager(tdd.getAllocationId());
			} catch (SlotNotFoundException e) {
				throw new TaskSubmissionException("Could not submit task.", e);
			}
			
			//在实例化方法中构造InputGate和ResultPartition
			Task task = new Task(
				jobInformation,
				taskInformation,
		
<think> 我们正在讨论Flink源码相关的内容,用户之前询问了Spark源码,现在转向Flink。根据用户提供的引用,我们可以从几个方面来回答: 1. 如何获取、编译和调试Flink源码(参考引用[1]) 2. Flink的启动流程(参考引用[2]中start-cluster.sh脚本的解析) 3. Flink source原理(参考引用[3]) 4. Flink watermark的源码(参考引用[4]) 用户当前的问题是“请问Flink源码”,这是一个比较宽泛的问题。由于用户之前询问了Spark源码的解析,我们可以推测用户可能希望了解Flink源码的结构、核心模块或者如何阅读和调试Flink源码。 因此,我们可以从以下几个方面组织回答: 1. Flink源码的获取与编译(参考引用[1]) 2. Flink核心模块的源码结构(结合引用[2][3][4]) 3. 如何调试Flink源码(参考引用[1]) 4. 提供进阶学习资源 同时,根据引用[1]我们可以知道,导入Flink源码到IDEA并配置CheckStyle是第一步。引用[2]展示了Flink启动脚本的解析,引用[3]解释了Flink source的原理,引用[4]则详细分析了watermark的源码。 我们按照以下结构回答: ### 一、Flink源码获取与编译 1. **获取源码**: - 从GitHub克隆:`git clone https://github.com/apache/flink.git` - 切换分支(如release-1.17):`git checkout release-1.17` 2. **编译源码**(引用[1]): ```bash mvn clean package -DskipTests ``` 3. **导入IDEA与配置CheckStyle**(引用[1]): - 导入后,配置CheckStyle插件,使用Flink自带的`tools/maven/checkstyle.xml`规则。 ### 二、Flink核心模块源码解析 #### 1. **启动流程(从脚本到核心)**(引用[2]) - `start-cluster.sh`脚本解析:负责启动JobManager和TaskManager。 - 核心入口:`org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypoint`(独立集群模式入口)。 #### 2. **Source原理**(引用[3]) - SQL层转换:将SQL语句转化为`DynamicTableSource`(通过SPI机制加载工厂类)。 - 示例:Kafka source的创建过程(`KafkaDynamicTableFactory`创建`KafkaDynamicSource`)。 #### 3. **Watermark机制**(引用[4]) - Watermark结构:`org.apache.flink.streaming.api.watermark.Watermark`(仅含时间戳)。 - 传播机制:通过`WatermarkGenerator`生成,在算子间传递。 ### 三、调试Flink源码 1. **本地调试**: - 在IDEA中运行`StandaloneSessionClusterEntrypoint`启动本地集群。 2. **远程调试YARN集群**: ```bash bin/flink run -m yarn-cluster -yn 2 \ -Denv.java.opts="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" \ examples/streaming/WordCount.jar ``` ### 四、进阶资源 1. **官方文档**:[Flink Architecture](https://nightlies.apache.org/flink/flink-docs-stable/docs/concepts/flink-architecture/) 2. **书籍**:《Stream Processing with Apache Flink》 ### 附:Flink任务执行流程简图 ```mermaid graph LR A[Source] -->|事件+Watermark| B(Operator) B --> C[Sink] C --> D[外部存储] ``` §§相关问题§§ 1. Flink的Checkpoint机制在源码中是如何实现的? 2. 如何通过源码分析Flink的Exactly-Once语义保障? 3. Flink的容错机制(如TaskManager故障恢复)在源码中如何处理? 注意:我们引用了用户提供的四个引用,在回答中适当位置添加引用标记[^1][^2][^3][^4]。 </think> 以下是关于Flink源码的详细解析及学习指南,结合核心机制和官方资源整理: --- ### 一、Flink源码核心模块解析 #### 1. **启动流程(从脚本到内核)** - **入口脚本**:`bin/start-cluster.sh`(引用[2]) ```bash # 启动JobManager "$FLINK_BIN_DIR"/jobmanager.sh start # 启动TaskManager TMSlaves start ``` - 通过`config.sh`加载配置,根据HA模式(如ZooKeeper)决定集群启动方式[^2]。 - **内核入口**:`org.apache.flink.runtime.entrypoint.StandaloneSessionClusterEntrypoint` ```java public static void main(String[] args) { new StandaloneSessionClusterEntrypoint().startCluster(); } ``` #### 2. **Source原理(数据源层)** - **SQL到运行时转换**(引用[3]): 1. SQL解析生成`CatalogTable` 2. SPI动态加载`DynamicTableSourceFactory`(如`KafkaDynamicTableFactory`) 3. 工厂类创建`FlinkKafkaConsumer`作为实际运行时 - **核心接口**: ```java public interface SourceFunction<T> extends Serializable { void run(SourceContext<T> ctx) throws Exception; // 数据生成逻辑 void cancel(); // 取消任务 } ``` #### 3. **Watermark机制(时间语义)** - **Watermark结构**(引用[4]): ```java public final class Watermark implements Serializable { private final long timestamp; // 唯一字段 } ``` - **传播流程**: 1. 通过`assignTimestampsAndWatermarks()`设置策略 2. `WatermarkGenerator`生成水位线 3. 当`watermark > 窗口结束时间`时触发计算[^4] #### 4. **容错机制(Checkpoint)** - **关键类**:`org.apache.flink.runtime.checkpoint.CheckpointCoordinator` - **执行逻辑**: 1. JobManager定时触发Barrier注入 2. Barrier随数据流传播,对齐时执行快照 3. 状态持久化到后端(如HDFS) --- ### 二、Flink源码获取与调试 #### 1. **源码获取** - **GitHub仓库**:[https://github.com/apache/flink](https://github.com/apache/flink) - 推荐版本:`release-1.17`(稳定分支) #### 2. **编译与导入** - **编译命令**: ```bash mvn clean package -DskipTests # 跳过测试加速编译 ``` - **IDEA导入**(引用[1]): 1. 导入项目时启用`CheckStyle`插件 2. 配置规则文件:`tools/maven/checkstyle.xml`[^1] #### 3. **调试技巧** - **本地集群调试**: ```java // 在IDE中直接运行MiniCluster MiniClusterWithClientResource cluster = new MiniClusterWithClientResource(...); cluster.before(); ``` - **远程调试YARN任务**: ```bash bin/flink run -m yarn-cluster \ -Denv.java.opts="-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005" \ app.jar ``` --- ### 三、核心目录结构 | 路径 | 说明 | |------|------| | `flink-runtime/src/main/java` | 运行时核心(Task管理、调度) | | `flink-streaming-java/src/main/java` | 流处理API(DataStream、算子) | | `flink-table/flink-table-planner` | SQL优化器(Catalyst实现) | | `flink-connectors` | 数据源/汇实现(Kafka、JDBC等) | --- ### 四、进阶学习资源 1. **官方文档**: [Flink Architecture](https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/concepts/flink-architecture/) 2. **调试案例**: [Flink源码调试指南](https://flink.apache.org/contributing/debugging.html) 3. **书籍推荐**: 《Stream Processing with Apache Flink》(含源码分析) --- ### 附:Flink任务执行流程 ```mermaid graph LR A[Source] -->|数据+Watermark| B(Operator) B -->|Checkpoint Barrier| C[StateBackend] B -->|结果数据| D[Sink] ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值