从WordCount学习Flink源码-1

本文介绍了如何从初识WordCount开始学习Flink,包括代码结构、源码分析,重点讲解了source算子、转换算子(如map和sum)和sink算子(如Print)的底层实现。

1.初识WordCount

        近几年实时数据处理和流式数据处理的框架Flink越来越火热,特别是这两年从Flink 1.13开始Flink做成了流批一体,他的火热程度就更不言而喻了。而我们学习Flink都是从WordCount开始的,WordCount对于现在的我们来说可能来说非常简单,但对初学者来说当时可能是我们噩梦的开始,特别是Flink的API名字相对来说都比较长,对于初学者的我们来说很容易把我们给烦死,于是我发明了这款防烦恼辅助器,设计非常的银杏,感到烦恼的小伙伴们可以对自己头上来一下就再也不会感到烦恼了(哈哈.....最近抖音刷多了,开个小玩笑)。

钉头锤_360百科

 下面我们再简单回顾一下WordCount的代码:

StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        DataStream<String> text = env.readTextFile("E:\\tmp\\hudi_flink\\src\\main\\resources\\a.txt");

        SingleOutputStreamOperator<Tuple2<String, Integer>> sumDS = text.map(new MapFunction<String, Tuple2<String, Integer>>() {
            @Override
            public Tuple2<String, Integer> map(String value) throws Exception {
                return new Tuple2<>(value, 1);
            }
        }).keyBy(new KeySelector<Tuple2<String, Integer>, String>() {
            @Override
            public String getKey(Tuple2<String, Integer> value) throws Exception {
                return value.f0;
            }
        }).sum(1);

        sumDS.print();


        env.execute();

 可以看到代码大概分为三部分:

1.第一部分是我们创建了一个StreamExecutionEnvironment,这个是flink的执行环境。

2.第二部分就是我们写的业务代码从env.readTextFlie到sumDS.print。

3.第三部分是env.execute方法

这三部分我们都耳熟能祥了,所有的flink代码基本也是由着三部分组成的,相信了解过Flink的兄弟们都知道Flink的算子分为,分为:source算子,转换算子,sink算子。

2.Source算子源码分析

source算子也有挺多种类例如:

env.readTextFile()

env.sockerTextStream()

env.fromCollection()

env.addSource()

看似很多,其实底层调用的都是env.addSource,所以我们自定义数据源的时候可以直接使用env.addSource,下面我们简单看一下env.readTextFile()底层的源码是如何调用的

 

 由于下面这个代码比较长,我们直接粘贴过来,可以看到里面除了校验参数,然后就是创建了一个监控函数,一个连续读文件算子的工厂,监控模式,最后调用了add.source方法。

 private <OUT> DataStreamSource<OUT> createFileInput(
            FileInputFormat<OUT> inputFormat,
            TypeInformation<OUT> typeInfo,
            String sourceName,
            FileProcessingMode monitoringMode,
            long interval) {

        Preconditions.checkNotNull(inputFormat, "Unspecified file input format.");
        Preconditions.checkNotNull(typeInfo, "Unspecified output type information.");
        Preconditions.checkNotNull(sourceName, "Unspecified name for the source.");
        Preconditions.checkNotNull(monitoringMode, "Unspecified monitoring mode.");

        Preconditions.checkArgument(
                monitoringMode.equals(FileProcessingMode.PROCESS_ONCE)
                        || interval >= ContinuousFileMonitoringFunction.MIN_MONITORING_INTERVAL,
                "The path monitoring interval cannot be less than "
                        + ContinuousFileMonitoringFunction.MIN_MONITORING_INTERVAL
                        + " ms.");

        ContinuousFileMonitoringFunction<OUT> monitoringFunction =
                new ContinuousFileMonitoringFunction<>(
                        inputFormat, monitoringMode, getParallelism(), interval);

        ContinuousFileReaderOperatorFactory<OUT, TimestampedFileInputSplit> factory =
                new ContinuousFileReaderOperatorFactory<>(inputFormat);

        final Boundedness boundedness =
                monitoringMode == FileProcessingMode.PROCESS_ONCE
                        ? Boundedness.BOUNDED
                        : Boundedness.CONTINUOUS_UNBOUNDED;

        SingleOutputStreamOperator<OUT> source =
                addSource(monitoringFunction, sourceName, null, boundedness)
                        .transform("Split Reader: " + sourceName, typeInfo, factory);

        return new DataStreamSource<>(source);
    }

3.转换算子源码分析

转换算子的种类非常丰富,像我们这个案例中我们就用到了map,sum算子。虽然我们flink也写了很多代码,但是我们有没有详细观察过这些算子底层是调用了那些方法,今天我们就一起来看看他的底层调用是怎么样的。

1.Map算子

 

 

从上面我们可以看到 map方法经过一系列的调用最终从function-->streamOperator-->transformation了,最终调用transformations.add方法。transformations是env的一个成员变量,是一个list集合,专门用来放transformation,至于他的作用我们后面再说。

2.sum算子

 sum算子从aggregate function --> reduce function --> transformation,最终还是调用transformations.add方法,其他算子我这边就不举例了,所有transform算子最终都是调用transformations.add方法,这样flink才可以从env中拿到我们作业的血缘依赖。

3.sink算子源码分析

1.Print算子

 

 print算子通过调用addSink -->  addOperator -->add 方法,最终也加入到了transformation中

 2.addSink算子

没想到addSink算子更简单,直接一步到位..

 

 好辣,今天就写这么多吧,明天继续写transformations获取到这些作业的血缘依赖该怎么处理把他交给flink来变成我们非常熟悉的streamGraph.

<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] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值