Flink 重点
- batch 处理不支持checkpoint
- 因此在判断应该使用 Processing Time 还是 Event Time 的时候,可以遵循一个原则:当你的应用遇到某些问题要从上一个 checkpoint 或者 savepoint 进行重放,是不是希望结果完全相同。如果希望结果完全相同,就只能用 Event Time;如果接受结果不同,则可以用 Processing Time。Processing Time 的一个常见的用途是,根据现实时间来统计整个系统的吞吐,比如要计算现实时间一个小时处理了多少条数据,这种情况只能使用 Processing Time
- 大家要注意的是就是我们在分配 timestamp 和生成 watermark 的过程,虽然在 SourceFunction 和 DataStream 中都可以指定,但是还是建议生成的工作越靠近 DataSource 越好。
- 对于有多个输入的算子,watermark 的计算就有讲究了,一个原则是:单输入取其大,多输入取小
- 若 Flink 选择自己定制的序列化框架,对类型信息了解越多,可以在早期完成类型检查,更好的选取序列化方式,进行数据布局,节省数据的存储空间,直接操作二进制数据。
function
- RichMapFunction
open 方法:根据设置map 的并行度,执行几次。
map 方法:每个元素执行一次。
close 方法:flink 任务结束时 执行close,一个map 执行一次。
Data Types & Serialization
- Flink 在其内部构建了一套自己的类型系统,Flink 现阶段支持的类型分类如图所示,从图中可以看到 Flink 类型可以分为基础类型(Basic)、数组(Arrays)、复合类型(Composite)、辅助类型(Auxiliary)、泛型和其它类型(Generic)。
2.在Flink中,统一使用TypeInformation类表示。比如,POJO在Flink内部使用PojoTypeInfo来表示,PojoTypeInfo继承自CompositeType,CompositeType继承自TypeInformation。下图展示了TypeInformation的继承关系,可以看到,前面提到的诸多数据类型,在Flink中都有对应的类型。TypeInformation的一个重要的功能就是创建TypeSerializer序列化器,为该类型的数据做序列化。每种类型都有一个对应的序列化器来进行序列化。
3.在使用Java api 开发时,因为Java通常会擦除掉* 泛型* 信息,所以你需要将数据类型传递给TypeInformation构造函数:
对于非泛型类,直接传入 class 对象即可
PojoTypeInfo typeInfo = (PojoTypeInfo) TypeInformation.of(Person.class);
对于泛型类,需要通过 TypeHint 来保存泛型类型信息。
final TypeInfomation<Tuple2<Integer,Integer>> resultType = TypeInformation.of(new TypeHint<Tuple2<Integer,Integer>>(){});
当然可以写成lambda表达式:(注意lambda表达式需要显式指定return type 在官网 DateStrean api/Java Lambda表达式 有详解)
- flink返回的元组类型不允许为null, 返回的String 运行为null
解决:
使用空元组替代null , 使用 filter 过滤
### 窗口函数
- reduce(new ReduceFunction<Tuple3<String, String, Integer>>()
先划分窗口,窗口里的(第一个个元素都和下一个元素的计算的产出) 再和 下一个元素 进行计算。以此类推到最后一个元素。
比如求和
1,2,3 =》 12 = 3 。3+3 =6
java
- transient
对象所有的变量都会转变成持久状态。但是有时候,一些变量可能不需要序列化,因为没必要对这些变量进行序列化。这时,你就可以将这些变量申明为 transient。如果一个变量被申明为 transient,那么这个变量就不会被序列化
kafka
- 需要注意的是,因为 Flink 框架有容错机 制,如果作业故障,如果作业开启 checkpoint,会从上一次 checkpoint 状态开始恢 复。或者在停止作业的时候主动做 savepoint,启动作业时从 savepoint 开始恢复。 这两种情况下恢复作业时,作业消费起始位置是从之前保存的状态中恢复,与上面提 到跟 kafka 这些单独的配置无关。
- topic 和 partition 动态发现----需要在构建 FlinkKafkaConsumer 时的 properties 中设置 flink.partition-discovery.interval-millis 参数为非负值,表示开启动态发现 的开关,以及设置的时间间隔。此时 FlinkKafkaConsumer 内部会启动一个单独的线程定期去 kafka 获取最新的 meta 信息。
flink 部署方式
- Flink可以通过以下三种方式之一执行应用程序:
1. 在会话模式下,flink yarn-session
2. 在按作业模式下, single job on yarn (我们使用的这种)
3. 在应用程序模式下 application https://www.h5w3.com/34523.html
4. 区别:1和2 应用程序的main()方法都是在客户端执行的。
以上模式的区别在于:
集群生命周期和资源隔离保证
应用程序的main()方法是在客户端还是在集群上执行
总结。
在会话模式下,集群生命周期独立于集群上运行的任何作业,并且资源在所有作业之间共享。
“逐个作业”模式为每个提交的作业分配一个集群的代价,但这具有更好的隔离保证,因为资源不会在各个作业之间共享。在这种情况下,群集的生命周期将与作业的生命周期绑定在一起。
应用程序模式为每个应用程序创建一个会话群集,并main() 在该群集上执行该应用程序的方法。
run-appliaction 指定对列 不能使用 -yqu root.boss.pac.dap.vip,要用 -Dyarn.application.queue=root.boss.pac.dap.vip
flink project conf
- 在官网 datastream api 的 project conf 板块
flink log to kafka
conf.yml 增加
env.java.opts.taskmanager: -DyarnContainerId=
C
O
N
T
A
I
N
E
R
I
D
−
D
n
o
d
e
i
d
=
CONTAINER_ID -Dnodeid=
CONTAINERID−Dnodeid=_FLINK_NODE_ID -DflinkyarnContainerId=
F
L
I
N
K
C
O
N
T
A
I
N
E
R
I
D
e
n
v
.
j
a
v
a
.
o
p
t
s
.
j
o
b
m
a
n
a
g
e
r
:
−
D
y
a
r
n
C
o
n
t
a
i
n
e
r
I
d
=
{_FLINK_CONTAINER_ID} env.java.opts.jobmanager: -DyarnContainerId=
FLINKCONTAINERIDenv.java.opts.jobmanager:−DyarnContainerId=CONTAINER_ID