Flink Stream API 源码走读 - socketTextStream

概述

本文深入分析了 Flink 中 socketTextStream() 方法的源码实现,从用户API调用到最终返回 DataStream 的完整流程。

核心知识点

1. socketTextStream 方法重载链

java 复制代码
// 用户调用入口
env.socketTextStream("hostname", 9999)
    ↓ 补充分隔符参数
env.socketTextStream("hostname", 9999, "\n") 
    ↓ 补充重试次数参数
env.socketTextStream("hostname", 9999, "\n", 0)
    ↓ 创建 SocketTextStreamFunction
addSource(new SocketTextStreamFunction(hostname, port, delimiter, maxRetry), "Socket Stream")

重载过程分析:

  • 第一层:补充分隔符参数(默认 "\n")
  • 第二层:补充重试次数参数(默认 0)
  • 最终:创建 SocketTextStreamFunction 并调用 addSource

2. SourceFunction 的重要说明

java 复制代码
@Deprecated
public class SocketTextStreamFunction implements SourceFunction<String>

⚠️ 重要提醒:

  • SourceFunction 已被标记为 @Deprecated(过时)
  • 官方建议使用新的 Source API
  • 基于 SourceFunction 的架构是老架构
  • 新架构基于 org.apache.flink.api.connector.source.Source

3. addSource 方法的重载链

addSource(function, sourceName) addSource(function, sourceName, null) addSource(function, sourceName, typeInfo, CONTINUOUS_UNBOUNDED) 核心处理逻辑

参数补充过程:

  1. addSource(function, "Socket Stream")
  2. addSource(function, "Socket Stream", null) - 补充 TypeInformation 为 null
  3. addSource(function, "Socket Stream", null, CONTINUOUS_UNBOUNDED) - 补充有界性

4. 核心处理逻辑分析

java 复制代码
private <OUT> DataStreamSource<OUT> addSource(
        final SourceFunction<OUT> function,
        final String sourceName,
        @Nullable final TypeInformation<OUT> typeInfo,
        final Boundedness boundedness) {
    
    // 1. 非空检查
    checkNotNull(function);
    checkNotNull(sourceName);
    checkNotNull(boundedness);
    
    // 2. 抽取类型信息
    TypeInformation<OUT> resolvedTypeInfo = 
        getTypeInfo(function, sourceName, SourceFunction.class, typeInfo);
    
    // 3. 判断是否并行
    boolean isParallel = function instanceof ParallelSourceFunction;
    
    // 4. 序列化检查
    clean(function);
    
    // 5. Function → Operator
    final StreamSource<OUT, ?> sourceOperator = new StreamSource<>(function);
    
    // 6. 返回 DataStreamSource
    return new DataStreamSource<>(
        this, resolvedTypeInfo, sourceOperator, isParallel, sourceName, boundedness);
}

5. 四个核心概念的转换

Function
用户逻辑 Operator
算子封装 Transformation
转换操作 DataStream
用户API

概念解释:

  1. Function: 用户的业务逻辑封装

    • SocketTextStreamFunction - Socket连接和数据读取逻辑
    • 继承自 SourceFunction<String>
  2. Operator: 算子的抽象

    • StreamSource<OUT, ?> - 将Function包装成算子
    • 继承自 AbstractUdfStreamOperator
  3. Transformation: 转换操作的封装

    • LegacySourceTransformation - 包装Operator和相关元信息
    • 包含类型信息、并行度、有界性等
  4. DataStream: 面向用户的流式API

    • DataStreamSource - 继承自 DataStream
    • 支持链式调用(map、filter、keyBy等)

6. 重要参数说明

TypeInformation(类型信息)
java 复制代码
// 为什么需要 TypeInformation?
// Java 泛型在编译后会被类型擦除,Flink需要显式的类型信息来:
// 1. 创建序列化器/反序列化器
// 2. 根据不同类型产生不同的序列化机制
TypeInformation<OUT> resolvedTypeInfo = getTypeInfo(function, sourceName, SourceFunction.class, typeInfo);
Boundedness(有界性)
java 复制代码
// CONTINUOUS_UNBOUNDED 表示无界流
// 在翻译成物理执行计划时会用到这个信息
// 有界流和无界流会生成不同的执行计划
Boundedness.CONTINUOUS_UNBOUNDED
并行性检查
java 复制代码
// 检查是否为并行源函数
boolean isParallel = function instanceof ParallelSourceFunction;
// SocketTextStreamFunction 不是 ParallelSourceFunction,所以 isParallel = false

7. DataStreamSource 的构造

java 复制代码
public DataStreamSource(
    StreamExecutionEnvironment environment,
    TypeInformation<T> outTypeInfo, 
    StreamSource<T, ?> operator,
    boolean isParallel,
    String sourceName,
    Boundedness boundedness) {
    
    // 调用父类构造,创建 LegacySourceTransformation
    super(environment, new LegacySourceTransformation<>(
        sourceName, operator, outTypeInfo, 
        environment.getParallelism(), boundedness));
    
    // 如果不是并行的,设置并行度为1
    if (!isParallel) {
        setParallelism(1);
    }
}

8. 继承关系分析

DataStream<T> SingleOutputStreamOperator<T> DataStreamSource<T> 包含所有流式API
map, filter, keyBy, window等

重要理解:

  • DataStreamSource 本质上就是一个 DataStream
  • 所有的链式调用API都定义在 DataStream
  • SingleOutputStreamOperator 这个命名容易误导,它实际上是个 DataStream

9. DataStream 的内部结构

java 复制代码
public class DataStream<T> {
    // 两个最重要的成员
    protected final StreamExecutionEnvironment environment;  // 执行环境
    protected final Transformation<T> transformation;        // 转换操作
}

关系链:

  • DataStream 包含 Transformation
  • Transformation 包含 Operator
  • Operator 包含 Function

10. 链式调用的实现

java 复制代码
DataStream<String> stream = env.socketTextStream("localhost", 9999)
    .map(...)           // 返回 SingleOutputStreamOperator (实际是DataStream)
    .filter(...)        // 返回 SingleOutputStreamOperator  
    .keyBy(...)         // 返回 KeyedStream
    .window(...)        // 返回 WindowedStream
    .sum(...)           // 返回 SingleOutputStreamOperator
    .print();          // 返回 DataStreamSink

流程:
DataStreamSource → 各种变换 → DataStreamSink

总结

核心流程回顾

  1. 用户调用 env.socketTextStream(hostname, port)
  2. 参数补全 通过重载方法逐步补充参数
  3. Function创建 创建 SocketTextStreamFunction
  4. addSource调用 进入核心处理逻辑
  5. 类型推断 抽取输出数据的类型信息
  6. 并行性检查 判断是否为并行源函数
  7. Function→Operator 封装成 StreamSource
  8. Operator→Transformation 创建 LegacySourceTransformation
  9. 返回DataStream 创建 DataStreamSource

设计模式体现

  • 装饰器模式: Function → Operator → Transformation → DataStream
  • 建造者模式: 通过重载方法逐步构建完整对象
  • 模板方法模式: addSource的处理流程

关键技术点

  • 类型擦除处理: 通过 TypeInformation 解决Java泛型擦除问题
  • 序列化机制: 根据类型信息创建对应的序列化器
  • 并行度控制: 非并行源强制设置并行度为1
  • 有界性标识: 为后续执行计划生成提供信息

下节预告

Flink Stream API 源码走读 map和 flatmap


注意 : 基于 Flink 1.18 版本,SourceFunction 已被标记为过时,实际项目中建议使用新的 Source API。

相关推荐
珠海西格电力15 分钟前
零碳园区数据应用的具体场景有哪些?
大数据·人工智能·算法·架构·能源
Ganttable30 分钟前
项目基线项目使用指南
大数据
阿乔外贸日记1 小时前
意大利进口主力产品及主要合作供应国
大数据·人工智能·物联网·搜索引擎·云计算
TTBIGDATA1 小时前
【Ambari Plus】15.Livy 安装
大数据·运维·hadoop·ambari·hdp·cdh·bigtop
YangYang9YangYan2 小时前
2026仓库文员学数据分析的价值
大数据
EMBA寰球网2 小时前
互动展厅设计核心逻辑、实施路径与落地实施要点专业解析:名瑞展览展陈行业实践深度洞察
大数据·人工智能
lin9902122 小时前
内容矩阵批量分发实战
大数据·人工智能·矩阵
我登哥MVP3 小时前
Hadoop成长史-从Nutch子项目到大数据生态王者
java·大数据·hadoop·分布式·云原生·云计算
dunge20264 小时前
# GPT 与 Codex:软件正在从“静态程序”演化为“持续推理系统”
大数据·gpt
ganbingfenxiang4 小时前
太原干冰定制
大数据·python