Flink源码走读(一):Flink工程目录

 Flink工程目录结构是怎样的?

 Flink源码中有哪些主要模块?

 如何理解Flink的工程目录设计?

导语 | Flink已经成为未来流计算趋势,目前在很多大厂已经有了大规模的使用。最近在学习Flink源码,就想把自己学习的过程分享出来,希望能帮助到志同道合的朋友。开始阅读源码,说明读者已经对flink的基本概念有一些了解,这里就不再重复介绍Flink了。本文作为学习过程的第一章,首先对Flink的工程目录做一个解读,了解了工程下各个模块的作用,才能在遇到问题时准确定位到代码,进一步学习。

一. Flink工程下的一级目录

用IDEA打开Flink的工程,可以看到图一所示的这些子工程目录,这一小节会简要介绍下各个模块的作用,其中像example和test的目录就跳过了,对于Flink比较重要的两个模块flink-runtime和flink-table会分别在第二节和第三节分别介绍。

图一 Flink工程目录

图一 Flink工程目录

  • flink-annotations: Flink自定义的一些注解,用于配置、控制编译等功能。
  • flink-clients: Flink客户端,用于向Flink集群提交任务、查询状态等。其中org.apache.flink.client.cli.CliFrontend就是执行./flink run的入口。
  • flink-connectors: Flink连接器,相当于Flink读写外部系统的客户端。这些连接器指定了外部存储如何作为Flink的source或sink。例如对于kafka来说,flink-connector-kafka-xx定义了FlinkKafkaConsumer和FlinkKafkaProducer类分别作为Flink的source和sink,实现了对kafka消费和生产的功能。从图二可以看出,flink 1.9目前支持的外部存储有Cassandra、ES、Kafka、Hive等一些开源外部存储。

图二 Flink Connectors

图二 Flink Connectors

  • flink-container: Flink对docker和kubernetes的支持。
  • flink-contrib: 社区开发者提供的一些新特性。
  • flink-core: Flink核心的API、类型的定义,包括底层的算子、状态、时间的实现,是Flink最重要的部分。Flink内部的各种参数配置也都定义在这个模块的configuration中。(这部分代码还没怎么看过,就不细讲了)。
  • flink-dist: Flink编译好之后的jar包会放在这个文件夹下,也就是网上下载的可执行的版本。其中也包括集群启动、终止的脚本,集群的配置文件等。
  • flink-docs: 这个模块并不是Flink的文档,而是Flink文档生成的代码。其中org.apache.flink.docs.configuration.ConfigOptionsDocGenerator是配置文档的生成器,修改相关配置的key或者默认值,重新运行这个类就会更新doc文件夹下的html文件。同样org.apache.flink.docs.rest.RestAPIDocGenerator是Flink RestAPI文档的生成器。
  • flink-fliesystems: Flink对各种文件系统的支持,包括HDFS、Azure、AWS S3、阿里云OSS等分布式文件系统
  • flink-formats: Flink对各种格式的数据输入输出的支持。包括Json、CSV、Avro等常用的格式。
  • flink-java: Flink java的API,就是写flink应用时用到的map、window、keyBy、State等类或函数的实现。
  • flink-jepsen: 对Flink分布式系统正确性的测试,主要验证Flink的容错机制。
  • flink-libraries: Flink的高级API,包括CEP(复杂事件处理)、Gelly图处理库等。
  • flink-mesos: Flink对mesos集群管理的支持。
  • flink-metrics: Flink监控上报。支持上报到influxdb、prometheus等监控系统。具体的使用配置可以在flink-core模块的org.apache.flink.configuration.MetricOptions中找到。
  • flink-python: Flink对python的支持,目前还比较弱。
  • flink-queryable-state: Flink对可查询状态的支持,其中flink-queryable-state-runtime子模块实现了StateClientProxy和StateServer。这两部分都运行在TaskManager上,StateClientProxy负责接收外部请求,StateServe负责管理内部的queryable state。flink-queryable-state-client-java子模块实现了QueryableStateClient,作为外部系统访问queryable state的客户端。
  • flink-runtime: flink运行时核心代码,在第二节细说。
  • flink-runtime-web: Flink Web Dashboard的实现。默认启动standalone集群后,访问http://localhost:8081 出现的界面。
  • flink-scala: Flink scala的API。
  • flink-scala-shell: Flink提供的scala命令行交互接口。
  • flink-state-backends: flink状态存储的方式,目前这个模块中只有RocksDBStateBackend,未来可能会支持更多种的状态存储,以适应不同的业务场景。MemoryStateBackend和FsStateBackend的实现并不在这个目录下,而是在flink-runtime目录下。
  • flink-streaming-java: Flink Streaming的java API。
  • flink-streaming-scala: Flink Streaming的scala API。
  • flink-table: Flink Table API,在第三小节中细说。
  • flink-yarn: Flink对yarn集群管理的支持。
二. flink-runtime模块

flink-runtime模块是Flink最核心的模块之一,实现了Flink的运行时框架。图三1和图四2分别是Flink运行时框架和作业调度框架,图中标识的几乎所有模块,在flink-runtime下都有对应的实现,如JobManager、TaskManager、ResourceManager、Scheduler、Checkpoint Coordinator等。有些部分看了目录的名字就很好理解,但有些目录与图中的模块无法对应上,官网文档也没有这些名词的介绍,本节就重点介绍下这些目录。

图三 Flink运行时框架

图三 Flink运行时框架

图四 Flink作业调度框架

图四 Flink作业调度框架

1. task-executor和task-manager

Flink文档中并没有描述TaskExecutor这个模块,只是说有TaskManager作为任务执行和运行资源管理的服务。实际上图四中的TaskManager是task-executor和task-manager这两个目录下的代码实现的,而且主要的功能还是在task-executor中,因此,我觉得这个TaskManager还不如直接叫做TaskExecutor。

task-executor中org.apache.flink.runtime.taskexecutor.TaskManagerRunner就是TaskManager进程的入口。

代码语言:txt

AI代码解释

package org.apache.flink.runtime.taskexecutor;

public class TaskManagerRunner implements FatalErrorHandler, AutoCloseableAsync {
public static void main(String[] args) throws Exception {
		// startup checks and logging
		EnvironmentInformation.logEnvironmentInfo(LOG, "TaskManager", args);
		SignalHandler.register(LOG);
		JvmShutdownSafeguard.installAsShutdownHook(LOG);

		long maxOpenFileHandles = EnvironmentInformation.getOpenFileHandlesLimit();
		if (maxOpenFileHandles != -1L) {
			LOG.info("Maximum number of open file descriptors is {}.", maxOpenFileHandles);
		} else {
			LOG.info("Cannot determine the maximum number of open file descriptors");
		}

		final Configuration configuration = loadConfiguration(args);
		FileSystem.initialize(configuration, PluginUtils.createPluginManagerFromRootFolder(configuration));
		SecurityUtils.install(new SecurityConfiguration(configuration));
		try {
			SecurityUtils.getInstalledContext().runSecured(new Callable<Void>() {
				@Override
				public Void call() throws Exception {
					runTaskManager(configuration, ResourceID.generate());
					return null;
				}
			});
		} catch (Throwable t) {
			final Throwable strippedThrowable = ExceptionUtils.stripException(t, UndeclaredThrowableException.class);
			LOG.error("TaskManager initialization failed.", strippedThrowable);
			System.exit(STARTUP_FAILURE_RETURN_CODE);
		}
	}
}

从main函数看进去,进程启动首先加载了配置(flink-conf.yaml),然后就调用了runTaskManager(),这个函数里最终调用了rpcServer.start(),就相当于启动了一个后台服务进程,等待JobManager给它分配Task了。

TaskManagerRunner最重要的成员就是 taskManager,而它实际上是一个TaskExecutor类型的对象。再看下TaskExecutor的成员,可以看到有TaskSlotTable,就是图四中每个TaskManager中维护的多个TaskSlot;有TaskManagerServices,其中包括MemoryManager、IOManager;有各种Connection,用来维护与其他模块的连接。因此TaskManager实际上对应的是TaskExecutor这个类。

代码语言:txt

AI代码解释

package org.apache.flink.runtime.taskexecutor;

 * TaskExecutor implementation. The task executor is responsible for the execution of multiple
 * {@link Task}.
 */
public class TaskExecutor extends RpcEndpoint implements TaskExecutorGateway {
	public static final String TASK_MANAGER_NAME = "taskmanager";
	/** The access to the leader election and retrieval services. */
	private final HighAvailabilityServices haServices;
	private final TaskManagerServices taskExecutorServices;
	/** The task manager configuration. */
	private final TaskManagerConfiguration taskManagerConfiguration;
	private final HeartbeatServices heartbeatServices;
	/** The fatal error handler to use in case of a fatal error. */
	...
	// --------- TaskManager services --------
	/** The connection information of this task manager. */
	private final TaskManagerLocation taskManagerLocation;
	private final TaskManagerMetricGroup taskManagerMetricGroup;
	/** The state manager for this task, providing state managers per slot. */
	private final TaskExecutorLocalStateStoresManager localStateStoresManager;
	/** The network component in the task manager. */
	private final ShuffleEnvironment<?, ?> shuffleEnvironment;
	/** The kvState registration service in the task manager. */
	private final KvStateService kvStateService;
	// --------- job manager connections -----------
	private final Map<ResourceID, JobManagerConnection> jobManagerConnections;
	// --------- task slot allocation table -----------
	private final TaskSlotTable taskSlotTable;
	private final JobManagerTable jobManagerTable;
	private final JobLeaderService jobLeaderService;
	...
	// --------- resource manager --------
	@Nullable
	private ResourceManagerAddress resourceManagerAddress;
	@Nullable
	private EstablishedResourceManagerConnection establishedResourceManagerConnection;
	@Nullable
	private TaskExecutorToResourceManagerConnection resourceManagerConnection;
	...
}
2. entrypoint、jobmanager和jobmaster

图四中可以看出,Flink中Client、TaskManager和JobManager都是独立的进程,本文前面已经分别说明了Client和TaskManager的入口在哪里,那JobManager的入口在哪里呢?

图三中的AM其实是一个单独的进程,入口在entrypoint目录下的org.apache.flink.runtime.entrypoint.ClusterEntrypoint。该类中有一个DispatcherResourceManagerComponent对象,就是对应AM中的Dispatcher和ResourceManager两个模块。Dispatcher中有一个JobManagerRunnerFactory的对象,当用户通过客户端向AM提交任务时,就由Dispatcher创建一个JobManagerRunner对象,其中包括JobGraph和JobMasterService,用来创建运行时的JobMaster。而图四中JobManager中的各个小模块,实际上是在JobMaster这个类中:包括JobGraph、Scheduler、CheckpointCoordinator(来自JobMasterGateway接口)。

代码语言:txt

AI代码解释

package org.apache.flink.runtime.jobmaster;

public class JobMaster extends FencedRpcEndpoint<JobMasterId> implements JobMasterGateway, JobMasterService {
	/** Default names for Flink's distributed components. */
	public static final String JOB_MANAGER_NAME = "jobmanager";
	// ------------------------------------------------------------------------
	private final JobMasterConfiguration jobMasterConfiguration;
	private final ResourceID resourceId;
	private final JobGraph jobGraph;
	private final Time rpcTimeout;
	private final HighAvailabilityServices highAvailabilityServices;
	private final BlobWriter blobWriter;
	private final HeartbeatServices heartbeatServices;
	private final JobManagerJobMetricGroupFactory jobMetricGroupFactory;
	private final ScheduledExecutorService scheduledExecutorService;
	private final OnCompletionActions jobCompletionActions;
	private final FatalErrorHandler fatalErrorHandler;
	private final ClassLoader userCodeLoader;
	private final SlotPool slotPool;
	private final Scheduler scheduler;
	private final SchedulerNGFactory schedulerNGFactory;
	// --------- BackPressure --------
	private final BackPressureStatsTracker backPressureStatsTracker;
	// --------- ResourceManager --------
	private final LeaderRetrievalService resourceManagerLeaderRetriever;
	// --------- TaskManagers --------
	private final Map<ResourceID, Tuple2<TaskManagerLocation, TaskExecutorGateway>> registeredTaskManagers;
	private final ShuffleMaster<?> shuffleMaster;
	...
}
三. flink-table模块

图五 flink-table模块目录

图五 flink-table模块目录

flink-table模块属于Flink的上层API,包括java和scala版本的table-api,以及SQL的解析和SQL的执行。

图六3展示了flink-table中子模块的架构。在Flink 1.9之前,Flink只有一个table-planner(flink-table-planner模块)用来将SQL转化成流计算的执行任务,而且流和批的Table API也不是统一的,因此有StreamTableEnvironment和BatchTableEnvironment两个运行环境,分别用来处理流和批的任务执行。

随着Flink SQL越来越受重视,flink-table从flink-libraries中移了出来,成为了独立的一级目录。Flink 1.9中,阿里把blink-planner开源了出来,这样整个flink-table中就有了2个planner。从长期来看,流批的统一是一个趋势,因此blink-planner只使用了StreamTableEnvironment中相关的API,而没有使用BatchTableEnvironment,将批当做一个有限的流来处理,希望通过这种方式实现流和批的统一。由于blink-table-planner更好的支持流批统一,且性能更好,在未来的版本中,很有可能完全替代flink-table-planner的功能,而flink-table-planner可能将会被移除。

图六 flink-table模块架构

图六 flink-table模块架构

flink-table中还实现了一个命令行的SQL Client,方便开发者学习和调试。其中org.apache.flink.table.client.SqlClient就是这个客户端的入口。

四. 总结

本文大致介绍了一下Flink工程下各个模块的功能,并对flink-runtime和flink-table模块做了进一步的介绍,希望能帮助读者更快的了解Flink代码。最后推荐一个github的仓库,里面有很多关于Flink的视频讲座,https://github.com/flink-china/flink-training-course ,也希望能帮助到大家。

参考文献

1 高赟, Flink Runtime 核心机制剖析, https://files.alicdn.com/tpsservice/7bb8f513c765b97ab65401a1b78c8cb8.pdf.

2 Flink docs, https://ci.apache.org/projects/flink/flink-docs-release-1.9/concepts/runtime.html.

3 贺小令, 深度探索 Flink SQL, https://files.alicdn.com/tpsservice/6f069ca9f2930400a577cc90323de326.pdf.

<think>好的,我需要帮这位用户制定个详细的学习计划,目标是在年内从有1年CRUD经验的Java开发者成长为阿里P6级架构师。用户每天最多能投入6小时,偏好项目驱动学习,需要包含AI和高并发设计能力。首先,我得分析阿里P6架构师的要求,然后结合用户当前水平,制定合理的阶段计划。 首先,P6架构师通常需要扎实的Java基础、系统设计能力、高并发处理经验、分布式系统知识,以及定的技术领导力。用户提到还没完全掌握Java基础,这可能是第个需要加强的地方。虽然用户有年CRUD经验,但可能需要深入理解JVM、多线程、框架原理等。 接下来,项目驱动学习是关键。用户偏好通过项目来学习,所以每个阶段都应该有实际的项目来应用所学知识。同时,AI和高并发是重点,需要将这两个领域融入项目中。 考虑到时间安排,年大约52周,可以分为几个阶段:打基础、进阶提升、系统设计、架构实战、AI整合、综合强化。每个阶段大约8-10周,逐步深入。 第阶段需要巩固Java基础,包括JVM、集合框架、多线程、IO/NIO、反射和设计模式。同时开始接触高并发的基础,比如锁机制、线程池。每周安排理论学习加小项目,比如用多线程实现爬虫,确保基础扎实。 第二阶段进阶,学习Spring框架原理、分布式系统基础(CAP理论、服务发现、负载均衡)、数据库优化(索引、分库分表)、消息队列(Kafka、RocketMQ)。项目方面可以设计个分布式电商系统,应用这些技术。 第三阶段系统设计,学习微服务架构(Spring Cloud、Dubbo)、容器化(Docker、K8s)、高并发设计(限流、熔断、降级)、缓存策略(Redis集群、分布式锁)。项目可以是个高并发的秒杀系统,使用这些技术解决实际问题。 第四阶段架构实战,深入分布式事务、分库分表中间件、监控系统(Prometheus、SkyWalking)、压力测试(JMeter)。项目可以是全链路压测平台,整合之前的技能,进行性能优化。 第五阶段整合AI,学习机器学习基础、TensorFlow/PyTorch、推荐系统、自然语言处理。项目方面,可以做个基于用户行为的推荐系统,或者智能客服系统,将AI融入后端服务。 最后阶段综合强化,复习所有内容,模拟面试,参与开源项目,总结项目经验。同时准备架构设计案例,提升沟通和团队协作能力。 需要确保每周有明确的学习目标和验证方式,比如代码Review、压力测试结果、项目部署等。技术验证方案要包括代码审查、压测报告、线上问题排查、架构图设计、数据评估和面试模拟,确保每步都有实际成果。 可能遇到的问题包括时间安排过紧,导致某些阶段无法深入,或者项目复杂度高难以完成。因此,每个阶段的项目需要合理设计,既挑战又可行,逐步提升难度。同时,保持持续的学习和反馈,及时调整计划。</think>我将为您拆解为期52周的分阶段成长计划(附技术验证方案)。以下为符合P6能力模型的核心技术栈及学习路径: --- ### **、基础夯实阶段(Week 1-8)** **目标**:补足Java核心短板 + 构建高并发认知框架 **每日投入**:2小时基础 + 1小时并发 + 3小时项目 ```markdown Week 1-2: - 核心重点:JVM内存模型/GC算法/字节码增强技术(Javassist实操) - 高并发基础:synchronized锁升级过程/CAS底层实现 - 验证项目:实现线程安全的高速缓存库(对比HashMap/ConcurrentHashMap性能) Week 3-4: - 源码级理解:AQS体系(ReentrantLock/Semaphore源码走读) - 网络编程:Netty核心线程模型(Boss-Worker分组实践) - 验证项目:基于Netty实现HTTP压测工具(对比Tomcat线程模型) Week 5-6: - 存储层优化:MySQL索引实现原理(B+树实操解析) - 分布式基石:Paxos算法推导(自制简易分布式锁服务) - 验证项目:设计分库分表路由中间件(支持致性哈希策略) Week 7-8: - 消息队列:Kafka ISR机制与零拷贝实现 - 性能调优:Arthas诊断线程死锁/JVM内存泄漏 - 验证项目:搭建订单超时取消系统(Kafka延迟队列+Redis过期监听) ``` --- ### **二、架构设计阶段(Week 9-20)** **目标**:掌握复杂系统设计方法论 + 构建高可用架构思维 **每日投入**:2小时原理 + 2小时设计 + 2小时实战 ```markdown Week 9-12:微服务架构 - 服务治理:Dubbo SPI扩展机制/Spring Cloud Alibaba体系对比 - 容错设计:Sentinel熔断规则动态配置实战 - 验证项目:搭建电商系统(服务拆分/分布式事务/灰度发布) Week 13-16:高并发体系 - 流量控制:令牌桶/漏桶算法在Sentinel中的实现差异 - 缓存策略:Redis多级缓存架构(Caffeine+Redis+本地缓存) - 验证项目:设计秒杀系统(库存预热/限流削峰/扣减防超卖) Week 17-20:云原生架构 - 容器编排:K8s Operator开发实践(自定义CRD) - 服务网格:Istio流量镜像在压测场景中的应用 - 验证项目:构建A/B测试平台(Envoy Filter+Prometheus监控) ``` --- ### **三、AI工程化阶段(Week 21-32)** **目标**:实现传统系统与AI能力融合 **每日投入**:3小时算法 + 2小时工程 + 1小时调优 ```markdown Week 21-24:基础能力建设 - 机器学习:特征工程处理(使用Apache Spark处理TB级日志) - 模型部署:TensorFlow Serving动态加载模型实践 - 验证项目:用户画像系统(Flink实时特征计算+LR模型预测) Week 25-28:智能决策系统 - 强化学习:Q-Learning在库存调度中的实践 - 模型优化:ONNX格式转换与推理加速 - 验证项目:智能客服系统(BERT意图识别+规则引擎融合) Week 29-32:大规模推理优化 - 异构计算:GPU资源池化方案(K8s Device Plugin开发) - 服务治理:模型版本热更新与流量切换 - 验证项目:搭建推荐系统(召回排序链路全流程实现) ``` --- ### **四、综合实战阶段(Week 33-52)** **目标**:全链路架构设计 + 技术影响力建设 **每日投入**:3小时复杂系统设计 + 2小时源码研究 + 1小时输出 ```markdown Week 33-36:混沌工程体系 - 建设故障注入平台(基于ChaosBlade扩展自定义场景) - 验证项目:实现自动化的容灾演练系统 Week 37-40:架构演进设计 - 分析淘宝单元化架构演进路径 - 验证项目:设计异地多活方案(数据同步冲突解决策略) Week 41-44:性能极致优化 - JIT编译优化分析(使用JITWatch研究热点代码) - 验证项目:实现百万QPS网关(DPDK+用户态协议栈) Week 45-52:技术影响力塑造 - 输出3篇深度技术文章(发表在InfoQ/阿里云社区) - 参与开源项目贡献(如Apache Dubbo/Sentinel) - 构建个人技术雷达图(定期更新技术认知地图) ``` --- ### **五、技术验证方案** 1. **代码级验证** - 每周Git提交可运行的核心代码片段 - 关键算法实现需通过LeetCode Hard级别测试用例 $$T(n) \leq O(n \log n) \text{ 需数学证明复杂度}$$ 2. **压力测试标准** - 高并发系统需达到: $$QPS \geq 10万 \quad \text{且} \quad P99 \leq 50ms$$ 使用JMeter生成测试报告并分析火焰图 3. **线上问题诊断** - 每月模拟1次生产事故(CPU飙高/Full GC频繁) - 输出包含根本原因分析(RCA)的完整报告 4. **架构设计评审** - 每阶段输出系统架构图(使用C4模型规范) - 通过SWOT分析法评估技术选型 5. **AI效果评估** - 分类模型需达到: $$\text{F1-score} \geq 0.85 \quad \text{在测试集上}$$ - 推荐系统CTR提升需有AB测试数据支撑 --- ### **六、学习资源推荐** 1. 源码级教材:《深入理解Java虚拟机(第三版)》 2. 架构范式:《数据密集型应用系统设计》 3. 工程实践:《Kubernetes in Action》 4. AI工程:《机器学习系统设计》(附真实案例代码) 建议每周日进行2小时学习复盘,使用OKR工具跟踪进展。关键是要建立「设计-实现-压测-优化」的完整闭环,这将直接符合阿里P6要求的「复杂问题系统性解决能力」。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值