一、Source
预定义Source
基于本地集合的source(Collection-based-source)
基于文件的source(File-based-source)
基于网络套接字(socketTextStream)
自定义Source
在flink最常见的创建DataStream方式有四种:
使用env.fromElements(),这种方式也支持Tuple,自定义对象等复合形式
使用env.fromCollection(),这种方式支持多种Collection的具体类型,如List,Set,Queue
使用env.generateSequence()方法创建基于Sequence的DataStream --已经废弃了
使用env.fromSequence()方法创建基于开始和结束的DataStream
二、Transformation-转换算子
map、FlatMap、Filter、KeyBy、Reduce --sum
KeyBy流处理中没有groupBy而是KeyBy
KeySelector对象可以支持元组类型,也可以支持POJO[Entry、JavaBean]
元组类型
单个字段keyBy
//用字段位置(已经被废弃)
wordAndOne.keyBy(0)
//用字段表达式
wordAndOne.keyBy(v -> v.f0)
多个字段keyBy
//用字段位置
wordAndOne.keyBy(0, 1);
//用KeySelector
wordAndOne.keyBy(new KeySelector<Tuple2<String, Integer>, Tuple2<String, Integer>>() {
@Override
public Tuple2<String, Integer> getKey(Tuple2<String, Integer> value) throws Exception {
return Tuple2.of(value.f0, value.f1);
}
});
类似于sql中的group by
select sex,count(1) from student group by sex;
group by 后面也可以跟多个字段进行分组,同样 keyBy 也支持使用多个列进行分组
Reduce --sum的底层是reduce
三、 union和connect-合并和连接
union可以合并多个同类型的流
将多个DataStream 合并成一个DataStream
【注意】:union合并的DataStream的类型必须是一致的
注意:union可以取并集,但是不会去重。
connect
connect可以连接2个不同类型的流(最后需要处理后再输出)
DataStream,DataStream → ConnectedStreams:连接两个保持他们类型的数据流,两个数据流被 Connect 之后,只是被放在了一个同一个流中,内部依然保持各自的数据和形式不发生任何变化【一国两制】,两个流相互独立, 作为对比Union后是真的变成一个流了。
和union类似,但是connect只能连接两个流,两个流之间的数据类型可以不同,对两个流的数据可以分别应用不同的处理逻辑。
Side Outputs侧道输出-----可以分流
物理分区
1) Global Partitioner
2)Shuffle Partitioner
根据均匀分布随机划分元素
3) Broadcast Partitioner
发送到下游所有的算子实例,是将上游的所有数据,都给下游的每一个分区一份
4)Rebalance Partitioner --重分区 【重点】
通过循环的方式依次发送到下游的task
数据倾斜: 某一个分区数据量过大。
解决方案:可以对分区数据进行重分区rebalance。
5) Forward Partitioner
发送到下游对应的第一个task,保证上下游算子并行度一致,即上有算子与下游算子是1:1的关系
四、Sink
flink在批处理中常见的sink
- print 打印
- writerAsText 以文本格式输出
- writeAsCsv 以csv格式输出
- writeUsingOutputFormat 以指定的格式输出
- writeToSocket 输出到网络端口
- 自定义连接器(addSink)
连接器Connectors
JDBC Connector
该连接器可以向JDBC 数据库写入数据
https://nightlies.apache.org/flink/flink-docs-release-1.13/zh/docs/connectors/datastream/jdbc/
使用java操作jbdc时,需要的依赖
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-connector-jdbc_2.11</artifactId>
<version>${flink.version}</version>
</dependency>
<!--假如你是连接低版本的,使用5.1.49-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
五、Window
Flink 认为 Batch 是 Streaming 的一个特例,所以Flink 底层引擎是一个流式引擎,在上面实现了流处理和批处理。而窗口(window)就是从 Streaming 到 Batch 的一个桥梁。Flink 提供了非常完善的窗口机制。
https://nightlies.apache.org/flink/flink-docs-release-1.13/zh/docs/dev/datastream/operators/windows/
window有如下的控制属性
窗口的长度(大小): 决定了要计算最近多长时间的数据
窗口的间隔: 决定了每隔多久计算一次
举例:每隔10min,计算最近24h的热搜词,24小时是长度,每隔10分钟是间隔。
Flink的窗口算子为我们提供了方便易用的API,我们可以将数据流切分成一个个窗口,对窗口内的数据进行处理。本文将介绍如何在Flink上进行窗口的计算。
一个Flink窗口应用的大致骨架结构如下所示:
l Keyed Window --键控窗口
// Keyed Window
stream
.keyBy(...) <- 按照一个Key进行分组
.window(...) <- 将数据流中的元素分配到相应的窗口中
[.trigger(...)] <- 指定触发器Trigger(可选)
[.evictor(...)] <- 指定清除器Evictor(可选)
.reduce/aggregate/process/apply() <- 窗口处理函数Window Function
l Non-Keyed Window
// Non-Keyed Window
stream
.windowAll(...) <- 不分组,将数据流中的所有元素分配到相应的窗口中
[.trigger(...)] <- 指定触发器Trigger(可选)
[.evictor(...)] <- 指定清除器Evictor(可选)
.reduce/aggregate/process() <- 窗口处理函数Window Function
window的分类
Window可以分成两类:
CountWindow:按照指定的数据条数生成一个Window,与时间无关。
滚动计数窗口,每隔N条数据,统计前N条数据
滑动计数窗口,每隔N条数据,统计前M条数据
TimeWindow:按照时间生成Window。(重点)
滚动时间窗口,每隔N时间,统计前N时间范围内的数据,窗口长度N,滑动距离N
滑动时间窗口,每隔N时间,统计前M时间范围内的数据,窗口长度M,滑动距离N
会话窗口,按照会话划定的窗口
基于时间的滑动和滚动窗口 [重点]
滚动窗口- TumblingWindow概念
假设有个红绿灯,提出个问题:统计1分钟内通过的汽车数量
每隔1分钟,统计这1分钟内通过汽车的数量。窗口长度是1分钟,时间间隔是1分钟,所以这样的窗口就是滚动窗口
滑动窗口– SlidingWindow概念
每隔1分钟,统计前面2分钟内通过的车辆数
对于这个需求我们可以看出,窗口长度是2分钟,每隔1分钟统计一次,窗口长度和时间间隔不相等,并且是大于关系,就是滑动窗口
窗口的长度(大小) > 窗口的间隔 : 如每隔5s, 计算最近10s的数据 【滑动窗口】
窗口的长度(大小) = 窗口的间隔: 如每隔10s,计算最近10s的数据 【滚动窗口】
窗口的长度(大小) < 窗口的间隔: 每隔15s,计算最近10s的数据 【没有名字,不用】
滚动窗口:窗口长度= 滑动距离
滑动窗口:窗口长度!= 滑动距离
windows Function窗口函数
窗口函数的分类:
全量函数:窗口先缓存所有元素,等到触发条件后对窗口内的全量元素执行计算。
l增量函数:窗口保存一份中间数据,每流入一个新元素,新元素与中间数据两两合一,生成新的中间数据。
增量聚合函数:
实现方法(常见的增量聚合函数如下):
reduce(reduceFunction)
aggregate(aggregateFunction)
sum()
min()
max()reduce接受两个相同类型的输入,生成一个同类型输出,所以泛型就一个 <T>
maxBy、minBy、sum这3个底层都是由reduce实现的
aggregate的输入值、中间结果值、输出值它们3个类型可以各不相同,泛型有<T, ACC, R>
全量聚合函数:
实现方法
apply(windowFunction)
process(processWindowFunction)全量聚合: 窗口需要维护全部原始数据,窗口触发进行全量聚合。
ProcessWindowFunction一次性迭代整个窗口里的所有元素,比较重要的一个对象是Context,可以获取到事件和状态信息,这样我们就可以实现更加灵活的控制,该算子会浪费很多性能,主要原因是不增量计算,要缓存整个窗口然后再去处理,所以要设计好内存。
后续还在整理中!