全网第一 | Flink学习面试灵魂40问答案,文末有福利!


640?wx_fmt=jpeg

大数据技术与架构
点击右侧关注,大数据开发领域最强公众号!

640?wx_fmt=png

暴走大数据
点击右侧关注,暴走大数据!

来源:王知无
做者:王知无


By 暴走大数据

场景描述:这是一份Flink学习面试指北。看看你搞清楚本身的定位没有?

关键词:Flink 学习 面试

《大数据技术与架构》和《暴走大数据》读者拥有本文的优先阅读权。
转载请联系做者本人。

 

概念和基础篇html

1. 简单介绍一下Flink 

Flink核心是一个流式的数据流执行引擎,其针对数据流的分布式计算提供了数据分布、数据通讯以及容错机制等功能。基于流执行引擎,Flink提供了诸多更高抽象层的API以便用户编写分布式任务:
DataSet API, 对静态数据进行批处理操做,将静态数据抽象成分布式的数据集,用户能够方便地使用Flink提供的各类操做符对分布式数据集进行处理,支持Java、Scala和Python。
DataStream API,对数据流进行流处理操做,将流式的数据抽象成分布式的数据流,用户能够方便地对分布式数据流进行各类操做,支持Java和Scala。
Table API,对结构化数据进行查询操做,将结构化数据抽象成关系表,并经过类SQL的DSL对关系表进行各类查询操做,支持Java和Scala。
此外,Flink还针对特定的应用领域提供了领域库,例如:
Flink ML,Flink的机器学习库,提供了机器学习Pipelines API并实现了多种机器学习算法。
Gelly,Flink的图计算库,提供了图计算的相关API及多种图计算算法实现。
2. Flink相比Spark Streaming有什么区别?
这个问题问的很大,分几个方面回答:
架构模型上:Spark Streaming 的task运行依赖driver 和 executor和worker,固然driver和excutor还依赖于集群管理器Standalone或者yarn等。而Flink运行时主要是JobManager、TaskManage和TaskSlot。另一个最核心的区别是:Spark Streaming 是微批处理,运行的时候须要指定批处理的时间,每次运行 job 时处理一个批次的数据;Flink 是基于事件驱动的,事件能够理解为消息。事件驱动的应用程序是一种状态应用程序,它会从一个或者多个流中注入事件,经过触发计算更新状态,或外部动做对注入的事件做出反应。 640?wx_fmt=png
640?wx_fmt=png
任务调度上:Spark Streaming的调度分为构建 DGA 图,划分 stage,生成 taskset,调度 task等步骤而Flink首先会生成 StreamGraph,接着生成 JobGraph,而后将 jobGraph 提交给 Jobmanager 由它完成 jobGraph 到 ExecutionGraph 的转变,最后由 jobManager 调度执行。
640?
640?wx_fmt=png

时间机制上:flink 支持三种时间机制事件时间,注入时间,处理时间,同时支持 watermark 机制处理滞后数据。Spark Streaming 只支持处理时间,Structured streaming则支持了事件时间和watermark机制。

容错机制上:两者保证exactly-once的方式不一样。spark streaming 经过保存offset和事务的方式;Flink 则使用两阶段提交协议来解决这个问题。

3. Flink的组件栈是怎么样的

Flink是一个分层架构的系统,每一层所包含的组件都提供了特定的抽象,用来服务于上层组件。Flink分层的组件栈以下图所示:
640?wx_fmt=png
Deployment层
该层主要涉及了Flink的部署模式,Flink支持多种部署模式:本地、集群(Standalone/YARN)、云(GCE/EC2)。
Runtime层
Runtime层提供了支持Flink计算的所有核心实现,好比:支持分布式Stream处理、JobGraph到ExecutionGraph的映射、调度等等,为上层API层提供基础服务。
API层
API层主要实现了面向无界Stream的流处理和面向Batch的批处理API,其中面向流处理对应DataStream API,面向批处理对应DataSet API。
Libraries层
该层也能够称为Flink应用框架层,根据API层的划分,在API层之上构建的知足特定应用的实现计算框架,也分别对应于面向流处理和面向批处理两类。面向流处理支持:CEP(复琐事件处理)、基于SQL-like的操做(基于Table的关系操做);面向批处理支持:FlinkML(机器学习库)、Gelly(图处理)。

4. Flink的基础编程模型了解吗? 

Flink 程序的基础构建单元是流(streams)与转换(transformations)。DataSet API 中使用的数据集也是一种流。数据流(stream)就是一组永远不会中止的数据记录流,而转换(transformation)是将一个或多个流做为输入,并生成一个或多个输出流的操做。
执行时,Flink程序映射到 streaming dataflows,由流(streams)和转换操做(transformation operators)组成。每一个 dataflow 从一个或多个源(source)开始,在一个或多个接收器(sink)中结束。
详细参考:https://www.cnblogs.com/cxhfuujust/p/10925843.html

5. 说说Flink架构中的角色和做用?
640?wx_fmt=png
JobManager:
JobManager是Flink系统的协调者,它负责接收Flink Job,调度组成Job的多个Task的执行。同时,JobManager还负责收集Job的状态信息,并管理Flink集群中从节点TaskManager。
TaskManager:
TaskManager也是一个Actor,它是实际负责执行计算的Worker,在其上执行Flink Job的一组Task。每一个TaskManager负责管理其所在节点上的资源信息,如内存、磁盘、网络,在启动的时候将资源的状态向JobManager汇报。
Client:
当用户提交一个Flink程序时,会首先建立一个Client,该Client首先会对用户提交的Flink程序进行预处理,并提交到Flink集群中处理,因此Client须要从用户提交的Flink程序配置中获取JobManager的地址,并创建到JobManager的链接,将Flink Job提交给JobManager。Client会将用户提交的Flink程序组装一个JobGraph, 而且是以JobGraph的形式提交的。一个JobGraph是一个Flink Dataflow,它由多个JobVertex组成的DAG。其中,一个JobGraph包含了一个Flink程序的以下信息:JobID、Job名称、配置信息、一组JobVertex等。

6. 说说Flink中经常使用的算子?用过哪些?

举一些经常使用的例子:
flink中提供的大量的算子,下面将介绍经常使用的算子操做方式:
map
DataStream --> DataStream:输入一个参数产生一个参数,map的功能是对输入的参数进行转换操做。
flatMap
DataStream --> DataStream:输入一个参数,产生0、1或者多个输出,这个多用于拆分操做
filter
DataStream --> DataStream:结算每一个元素的布尔值,并返回为true的元素
keyBy
DataSteam --> DataStream:逻辑地将一个流拆分红不相交的分区,每一个分区包含具备相同key的元素,在内部以hash的形式实现的。以key来分组。
注意:如下类型没法做为key
  • POJO类,且没有实现hashCode函数面试

  • 任意形式的数组类型算法

reduce
KeyedStream --> DataStream:滚动合并操做,合并当前元素和上一次合并的元素结果。
fold
KeyedStream --> DataStream:用一个初始的一个值,与其每一个元素进行滚动合并操做。
aggregation
KeyedStream --> DataStream:分组流数据的滚动聚合操做:min和minBy的区别是min返回的是一个最小值,而minBy返回的是其字段中包含的最小值的元素(一样元原理适用于max和maxBy)
window
KeyedStream --> DataStream:windows是在一个分区的KeyedStreams中定义的,windows根据某些特性将每一个key的数据进行分组(例如:在5s内到达的数据)。
windowAll
DataStream --> AllWindowedStream:Windows能够在一个常规的DataStream中定义,Windows根据某些特性对全部的流(例如:5s内到达的数据)。
注意:这个操做在不少状况下都不是并行操做的,全部的记录都会汇集到一个windowAll操做的任务中
window apply
WindowedStream --> DataStream
AllWindowedStream --> DataStream:将一个通用的函数做为一个总体传递给window。
window reduce
WindowedStream --> DataStream:给窗口赋予一个reduce的功能,并返回一个reduce的结果。
window fold
WindowedStream --> DataStream:给窗口赋予一个fold的功能,并返回一个fold后的结果。
aggregation on windows
WindowedStream --> DataStream:对window的元素作聚合操做,min和minBy的区别是min返回的是最小值,而minBy返回的是包含最小值字段的元素。(一样原理适用于max和maxBy)
union
DataStream --> DataStream:对两个或两个以上的DataStream作union操做,产生一个包含全部的DataStream元素的新DataStream。
注意:若是将一个DataStream和本身作union操做,在新的DataStream中,将看到每一个元素重复两次
window join
DataStream,DataStream --> DataStream:根据给定的key和window对两个DataStream作join操做
window coGroup
DataStream,DataStream --> DataStream:根据一个给定的key和window对两个DataStream作CoGroups操做。
connect
DataStream,DataStream --> ConnectedStreams:链接两个保持们类型的数据流。
coMap、coFlatMap
ConnectedStreams --> DataStream:做用于connected数据流上,功能与map和flatMap同样。
split
DataStream --> SplitStream:根据某些特征把一个DataStream拆分红两个或多个DataStream
select
SplitStream --> DataStream:从一个SplitStream中获取一个或多个DataStream
iterate
DataStream --> IterativeStream --> DataStream:在流程中建立一个反馈循环,将一个操做的输出重定向到以前的操做,这对于定义持续更新模型的算法来讲颇有意义的。
extract timestamps
DataStream --> DataStream:提取记录中的时间戳来跟须要事件时间的window一块儿发挥做用。
参考:https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/batch/

7. Flink中的分区策略有哪几种?

GlobalPartitioner: DataStream => DataStream
GlobalPartitioner,GLOBAL分区。将记录输出到下游Operator的第一个实例。
ShufflePartitioner: DataStream => DataStream
ShufflePartitioner,SHUFFLE分区。将记录随机输出到下游Operator的每一个实例。
RebalancePartitioner: DataStream => DataStream
RebalancePartitioner,REBALANCE分区。将记录以循环的方式输出到下游Operator的每一个实例。
RescalePartitioner: DataStream => DataStream
RescalePartitioner,RESCALE分区。基于上下游Operator的并行度,将记录以循环的方式输出到下游Operator的每一个实例。举例: 上游并行度是2,下游是4,则上游一个并行度以循环的方式将记录输出到下游的两个并行度上;上游另外一个并行度以循环的方式将记录输出到下游另两个并行度上。若上游并行度是4,下游并行度是2,则上游两个并行度将记录输出到下游一个并行度上;上游另两个并行度将记录输出到下游另外一个并行度上。
BroadcastPartitioner: DataStream => DataStream
BroadcastPartitioner,BROADCAST分区。广播分区将上游数据集输出到下游Operator的每一个实例中。适合于大数据集Join小数据集的场景。
ForwardPartitioner
ForwardPartitioner,FORWARD分区。将记录输出到下游本地的operator实例。ForwardPartitioner分区器要求上下游算子并行度同样。上下游Operator同属一个SubTasks。
KeyGroupStreamPartitioner(HASH方式):
KeyGroupStreamPartitioner,HASH分区。将记录按Key的Hash值输出到下游Operator实例。
CustomPartitionerWrapper
CustomPartitionerWrapper,CUSTOM分区。经过Partitioner实例的partition方法(自定义的)将记录输出到下游。

8. Flink的并行度有了解吗?Flink中设置并行度须要注意什么?

Flink程序由多个任务(Source、Transformation、Sink)组成。任务被分红多个并行实例来执行,每一个并行实例处理任务的输入数据的子集。任务的并行实例的数量称之为并行度。
Flink中人物的并行度能够从多个不一样层面设置:
操做算子层面(Operator Level)、执行环境层面(Execution Environment Level)、客户端层面(Client Level)、系统层面(System Level)。
Flink能够设置好几个level的parallelism,其中包括Operator Level、Execution Environment Level、Client Level、System Level
在flink-conf.yaml中经过parallelism.default配置项给全部execution environments指定系统级的默认parallelism;在ExecutionEnvironment里头能够经过setParallelism来给operators、data sources、data sinks设置默认的parallelism;若是operators、data sources、data sinks本身有设置parallelism则会覆盖ExecutionEnvironment设置的parallelism。 

9. Flink支持哪几种重启策略?分别如何配置? 

重启策略种类:
固定延迟重启策略(Fixed Delay Restart Strategy)
故障率重启策略(Failure Rate Restart Strategy)
无重启策略(No Restart Strategy)
Fallback重启策略(Fallback Restart Strategy)
详细参考:https://www.jianshu.com/p/22409ccc7905

10. Flink的分布式缓存有什么做用? 如何使用? 

Flink提供了一个分布式缓存,相似于hadoop,可使用户在并行函数中很方便的读取本地文件,并把它放在taskmanager节点中,防止task重复拉取。

此缓存的工做机制以下:程序注册一个文件或者目录(本地或者远程文件系统,例如hdfs或者s3),经过ExecutionEnvironment注册缓存文件并为它起一个名称。

当程序执行,Flink自动将文件或者目录复制到全部taskmanager节点的本地文件系统,仅会执行一次。用户能够经过这个指定的名称查找文件或者目录,而后从taskmanager节点的本地文件系统访问它。

详细参考:https://www.jianshu.com/p/7770f9aec75d

11. Flink中的广播变量,使用广播变量须要注意什么事项?  

在Flink中,同一个算子可能存在若干个不一样的并行实例,计算过程可能不在同一个Slot中进行,不一样算子之间更是如此,所以不一样算子的计算数据之间不能像Java数组之间同样互相访问,而广播变量Broadcast即是解决这种状况的。
咱们能够把广播变量理解为是一个公共的共享变量,咱们能够把一个dataset 数据集广播出去,而后不一样的task在节点上都可以获取到,这个数据在每一个节点上只会存在一份。
https://www.jianshu.com/p/3b6698ec10d8 

12. Flink中对窗口的支持包括哪几种?说说他们的使用场景 

640?wx_fmt=png
详细参考:https://www.jianshu.com/p/0ad104778bcd

13. Flink 中的 State Backends是什么?有什么做用?分红哪几类?说说他们各自的优缺点?

Flink流计算中可能有各类方式来保存状态:
  • 窗口操做apache

  • 使用了KV操做的函数编程

  • 继承了CheckpointedFunction的函数windows

  • 当开始作checkpointing的时候,状态会被持久化到checkpoints里来规避数据丢失和状态恢复。选择的状态存储策略不一样,会致使状态持久化如何和checkpoints交互。后端

  • Flink内部提供了这些状态后端:数组

  • MemoryStateBackend缓存

  • FsStateBackend网络

  • RocksDBStateBackend

  • 若是没有其余配置,系统将使用MemoryStateBackend。

详细参考:https://www.cnblogs.com/029zz010buct/p/9403283.html

14. Flink中的时间种类有哪些?各自介绍一下?

Flink中的时间与现实世界中的时间是不一致的,在flink中被划分为事件时间,摄入时间,处理时间三种。
若是以EventTime为基准来定义时间窗口将造成EventTimeWindow,要求消息自己就应该携带EventTime
若是以IngesingtTime为基准来定义时间窗口将造成IngestingTimeWindow,以source的systemTime为准。
若是以ProcessingTime基准来定义时间窗口将造成ProcessingTimeWindow,以operator的systemTime为准。
参考:https://www.jianshu.com/p/0a135391ff41

15. WaterMark是什么?是用来解决什么问题?如何生成水印?水印的原理是什么?

Watermark是Apache Flink为了处理EventTime 窗口计算提出的一种机制,本质上也是一种时间戳。
watermark是用于处理乱序事件的,处理乱序事件一般用watermark机制结合window来实现。
详细参考:
https://www.jianshu.com/p/1c2542f11da0

16. Flink的table和SQL熟悉吗?Table API和SQL中TableEnvironment这个类有什么做用? 

TableEnvironment是Table API和SQL集成的核心概念。它负责:
A)在内部catalog中注册表
B)注册外部catalog
C)执行SQL查询
D)注册用户定义(标量,表或聚合)函数
E)将DataStream或DataSet转换为表
F)持有对ExecutionEnvironment或StreamExecutionEnvironment的引用 

17. Flink如何实现SQL解析的呢? 

640?wx_fmt=png
StreamSQL API的执行原理以下:
一、用户使用对外提供Stream SQL的语法开发业务应用;
二、用calcite对StreamSQL进行语法检验,语法检验经过后,转换成calcite的逻辑树节点;最终造成calcite的逻辑计划;
三、采用Flink自定义的优化规则和calcite火山模型、启发式模型共同对逻辑树进行优化,生成最优的Flink物理计划;
四、对物理计划采用janino codegen生成代码,生成用低阶API DataStream 描述的流应用,提交到Flink平台执行
详细参考:https://cloud.tencent.com/developer/article/1471612


 

进阶篇


1. Flink是如何作到批处理与流处理统一的?

Flink设计者认为:有限流处理是无限流处理的一种特殊状况,它只不过在某个时间点中止而已。Flink经过一个底层引擎同时支持流处理和批处理。
详细参考:https://cloud.tencent.com/developer/article/1501348

2. Flink中的数据传输模式是怎么样的?

在一个运行的application中,它的tasks在持续交换数据。TaskManager负责作数据传输。
TaskManager的网络组件首先从缓冲buffer中收集records,而后再发送。也就是说,records并非一个接一个的发送,而是先放入缓冲,而后再以batch的形式发送。这个技术能够高效使用网络资源,并达到高吞吐。相似于网络或磁盘 I/O 协议中使用的缓冲技术。
详细参考:https://www.cnblogs.com/029zz010buct/p/10156836.html

3. Flink的容错机制

Flink基于分布式快照与可部分重发的数据源实现了容错。用户可自定义对整个Job进行快照的时间间隔,当任务失败时,Flink会将整个Job恢复到最近一次快照,并从数据源重发快照以后的数据。

640?wx_fmt=png
详细参考:https://www.jianshu.com/p/1fca8fb61f86

4. Flink中的分布式快照机制是怎么样的
Flink容错机制的核心就是持续建立分布式数据流及其状态的一致快照。这些快照在系统遇到故障时,充当能够回退的一致性检查点(checkpoint)。Lightweight Asynchronous Snapshots for Distributed Dataflows 描述了Flink建立快照的机制。此论文是受分布式快照算法 Chandy-Lamport启发,并针对Flink执行模型量身定制。
能够参考:
https://zhuanlan.zhihu.com/p/43536305
https://blog.csdn.net/u014589856/article/details/94346801

5. Flink是如何实现Exactly-once的?
Flink经过状态和两次提交协议来保证了端到端的exactly-once语义。
详细请看:https://www.jianshu.com/p/9d875f6e54f2

6. Flink的Kafka-connector是如何作到向下兼容的呢?
在新的链接器中,Flink提供了一个基础connector模块,它是实现全部connector的核心模块,全部的connector都依赖于基础connector。
Kafka社区也改写了Java clients底层的网络客户端代码,里面会自动地判断链接的broker端所支持client请求的最高版本,并自动建立合乎标准的请求。
详细参考:
https://www.cnblogs.com/Springmoon-venn/p/10690531.html
https://www.cnblogs.com/huxi2b/p/6784795.html
关于flink-kafka-connector的实现参考:
https://www.cnblogs.com/0x12345678/p/10463539.html

7. Flink中的内存管理是如何作的?

Flink 并非将大量对象存在堆上,而是将对象都序列化到一个预分配的内存块上,这个内存块叫作 MemorySegment,它表明了一段固定长度的内存(默认大小为 32KB),也是 Flink 中最小的内存分配单元,而且提供了很是高效的读写方法。每条记录都会以序列化的形式存储在一个或多个MemorySegment中。
Flink堆内存划分:
640?wx_fmt=png
Network Buffers: 必定数量的32KB大小的缓存,主要用于数据的网络传输。在 TaskManager启动的时候就会分配。默认数量是2048个,能够经过 taskmanager.network.numberOfBuffers来配置。
Memory Manager Pool:这是一个由MemoryManager管理的,由众多MemorySegment组成的超大集合。Flink中的算法(如 sort/shuffle/join)会向这个内存池申请MemorySegment,将序列化后的数据存于其中,使用完后释放回内存池。默认状况下,池子占了堆内存的70% 的大小。
Remaining (Free) Heap: 这部分的内存是留给用户代码以及TaskManager 的数据结构使用的,能够把这里当作的新生代。
Flink大量使用堆外内存。
详细参考:
https://www.cnblogs.com/ooffff/p/9508271.html

8. Flink中的序列化是如何作的?

Flink实现了本身的序列化框架,Flink处理的数据流一般是一种类型,因此能够只保存一份对象Schema信息,节省存储空间。又由于对象类型固定,因此能够经过偏移量存取。
Java支持任意Java或Scala类型,类型信息由TypeInformation类表示,TypeInformation支持如下几种类型:
BasicTypeInfo:任意Java 基本类型或String类型。
BasicArrayTypeInfo:任意Java基本类型数组或String数组。
WritableTypeInfo:任意Hadoop Writable接口的实现类。
TupleTypeInfo:任意的Flink Tuple类型(支持Tuple1 to Tuple25)。Flink tuples 是固定长度固定类型的Java Tuple实现。
CaseClassTypeInfo: 任意的 Scala CaseClass(包括 Scala tuples)。
PojoTypeInfo: 任意的 POJO (Java or Scala),例如,Java对象的全部成员变量,要么是 public 修饰符定义,要么有 getter/setter 方法。
GenericTypeInfo: 任意没法匹配以前几种类型的类。
针对前六种类型数据集,Flink皆能够自动生成对应的TypeSerializer,能很是高效地对数据集进行序列化和反序列化。对于最后一种数据类型,Flink会使用Kryo进行序列化和反序列化。每一个TypeInformation中,都包含了serializer,类型会自动经过serializer进行序列化,而后用Java Unsafe接口写入MemorySegments。以下图展现 一个内嵌型的Tuple3<integer,double,person> 对象的序列化过程:
640?wx_fmt=png
操纵二进制数据:
Flink提供了如group、sort、join等操做,这些操做都须要访问海量数据。以sort为例:首先,Flink会从MemoryManager中申请一批 MemorySegment,用来存放排序的数据。
640?wx_fmt=png
这些内存会分为两部分,一个区域是用来存放全部对象完整的二进制数据。另外一个区域用来存放指向完整二进制数据的指针以及定长的序列化后的key(key+pointer)。将实际的数据和point+key分开存放有两个目的。
第一,交换定长块(key+pointer)更高效,不用交换真实的数据也不用移动其余key和pointer;
第二,这样作是缓存友好的,由于key都是连续存储在内存中的,能够增长cache命中。排序会先比较 key 大小,这样就能够直接用二进制的 key 比较而不须要反序列化出整个对象。访问排序后的数据,能够沿着排好序的key+pointer顺序访问,经过 pointer 找到对应的真实数据。
详细参考:https://www.cnblogs.com/ooffff/p/9508271.html

9.Flink中的RPC框架选型是怎么样的?

对于Flink中各个组件(JobMaster、TaskManager、Dispatcher等),其底层RPC框架基于Akka实现。若是你akka不了解,那么参考:https://www.cnblogs.com/letsfly/p/10853341.html

10. Flink在使用Window时出现数据倾斜,你有什么解决办法?

注意:这里window产生的数据倾斜指的是不一样的窗口内积攒的数据量不一样,主要是由源头数据的产生速度致使的差别。
核心思路:1.从新设计key 2.在窗口计算前作预聚合
能够参考这个:
https://blog.csdn.net/it_lee_j_h/article/details/88641894

11. Flink SQL在使用Groupby时出现热点数据,如何处理?

对于开源的Flink,能够参考:https://help.aliyun.com/knowledge_detail/68645.html

12. Flink任务,delay极高,请问你有什么调优策略?

首先要肯定问题产生的缘由,找到最耗时的点,肯定性能瓶颈点。好比任务频繁反压,找到反压点。主要经过:资源调优、做业参数调优。资源调优便是对做业中的Operator的并发数(parallelism)、CPU(core)、堆内存(heap_memory)等参数进行调优。做业参数调优包括:并行度的设置,State的设置,checkpoint的设置。

13. Flink是如何处理反压的?和Spark有什么区别?Storm呢?
参考:https://yq.aliyun.com/articles/64821

14. Operator Chains(算子链)这个概念你了解吗?Flink是如何优化的?什么状况下Operator才会chain在一块儿?

为了更高效地分布式执行,Flink会尽量地将operator的subtask连接(chain)在一块儿造成task。每一个task在一个线程中执行。将operators连接成task是很是有效的优化:它能减小线程之间的切换,减小消息的序列化/反序列化,减小数据在缓冲区的交换,减小了延迟的同时提升总体的吞吐量。
两个operator chain在一块儿的的条件:
  • 上下游的并行度一致

  • 下游节点的入度为1 (也就是说下游节点没有来自其余节点的输入)

  • 上下游节点都在同一个 slot group 中(下面会解释 slot group)

  • 下游节点的 chain 策略为 ALWAYS(能够与上下游连接,map、flatmap、filter等默认是ALWAYS)

  • 上游节点的 chain 策略为 ALWAYS 或 HEAD(只能与下游连接,不能与上游连接,Source默认是HEAD)

  • 两个节点间数据分区方式是 forward(参考理解数据流的分区)

  • 用户没有禁用 chain


关于源码篇:建议去读源码找答案,若是没读过源码,答案没有意义。
推荐一个源码解析电子书。

640?wx_fmt=png

连接: https://pan.baidu.com/s/1L5KOhly6AvJb6nWBXeHYjQ 
提取码: mwa5 
或者长按扫描二维码下载:
640?wx_fmt=jpeg

欢迎点赞+收藏
欢迎转发至朋友圈
640?wx_fmt=jpeg