文章目录
一 Flink
1.1 Flink流程和应用场景
1.2 架构演变
1.2.1 OLAP
1.2.2 OLAP
比较老的结构:
改进的架构:
新一代的架构(kappa):
1.3 流处理应用场景
1.4 分层API
1.5 flink spark
有一句比较通俗的说法:
flink: 代码不动,数据动;
spark: 数据不动, 代码动.
二 hello world
2.1 demo
word count: 既可以使用DataSet
也可以使用DataStream
在 Flink 的视角里,一切数据都可以认为是流,流数据是无界流,而批数据则是有界流。所以批处理,其实就可以看作有界流的处理。
- 对于流而言,我们会在获取输入数据后立即处理,这个过程是连续不断的。当然,有时我们的输入数据可能会有尽头,这看起来似乎就成了一个有界流;但是它跟批处理是截然不同的:
—— 在输入结束之前,我们依然会认为数据是无穷无尽的,处理的模式也仍旧是连续逐个处理
2.1.1 读取文本流
StreamExecutionEnvironment env =
StreamExecutionEnvironment.getExecutionEnvironment();
env.setParallelism(1);
DataStreamSource<String> source = env.readTextFile("input/a.txt");
SingleOutputStreamOperator<Tuple2<String, Long>> singleOutputStreamOperator = source.flatMap(new FlatMapFunction<String, String>() {
public void flatMap(String line, Collector<String> collector) throws Exception {
Arrays.stream(line.split(" ")).forEach(collector::collect);
}
}).returns(Types.STRING)
.map(word -> Tuple2.of(word, 1L))
.returns(Types.TUPLE(Types.STRING, Types.LONG));
KeyedStream<Tuple2<String, Long>, String> keyedStream = singleOutputStreamOperator.keyBy(new KeySelector<Tuple2<String, Long>, String>() {
@Override
public String getKey(Tuple2<String, Long> tuple2) throws Exception {
return tuple2.getField(0);
}
});
SingleOutputStreamOperator<Tuple2<String, Long>> sumOperator = keyedStream.sum(1);
sumOperator.print();
env.execute();
2.1.2 读取Socket流
略
2.2 部署
即使是个简单的wordcount job 对应 Flink 集群上执行的一个作业;所以我们在本地执行代码,其实是先模拟启动一个 Flink 集群,然后将作业提交到集群上,创建好要执行的任务等待数据输入.
flink的关键组件: 客户端(Client)、作业管理器(JobManager)和任务管理器(TaskManager)。我们的代码,实际上是由客户端获取并做转换,之后提交给JobManger 的。所以 JobManager 就是 Flink 集群里的“管事人”,对作业进行中央调度管理;而它获取到要执行的作业后,会进一步处理转换,然后分发任务给众多的 TaskManager。这里的 TaskManager,就是真正“干活的人”,数据的处理操作都是它们来做的.
2.2.1 测试环境部署
- 单机版本: 下载,解压,启动即可
- 集群版: 配置主从关系
2.2.2 部署模式
在一些应用场景中,对于集群资源分配和占用的方式,可能会有特定的需求。Flink 为各
种场景提供了不同的部署模式,主要有以下三种:
- 单机模式(Standalone Mode)
- 会话模式(Session Mode)
- 单作业模式(Per-Job Mode)
- 应用模式(Application Mode)
它们的区别主要在于:集群的生命周期以及资源的分配方式;以及应用的 main 方法到底在哪里执行: 客户端(Client)还是 JobManager
2.2.3 会话模式
先启动一个集群,保持一个会话,在这个会话中通过客户端提交作业,如图所示。集群启动时所有资源就都已经确定,所以所有提交的作业会竞争集群中的资源.
特点: 集群的生命周期是超越于作业之上的,铁打的营盘流水的兵,作业结束了就释放资源,集群依然正常运行。
当然缺点也是显而易见的:因为资源是共享的,所以资源不够了,提交新的作业就会失败; 另外,同一个 TaskManager 上可能运行了很多作业,如果其中一个发生故障导
致 TaskManager 宕机,那么所有作业都会受到影响
会话模式比较适合于单个规模小、执行时间短的大量作业
2.2.4 单作业(Per-Job)模式
会话模式因为资源共享会导致很多问题,所以为了更好地隔离资源,我们可以考虑为每个
提交的作业启动一个集群,这就是所谓的单作业(Per-Job)模式
集群和作业 严格的一对一,集群只为这个作业而生。同样由客户端运行应用程序,然后启动集群,作业被提交给 JobManager
,进而分发给 TaskManager
执行。作业完成后,集群就会关闭,所有资源也会释放。这样一来,每个作业都有它自己的 JobManager
管理,占用独享的资源,即使发生故障,它的 TaskManager
宕机也不会影响其他作业。
这些特性使得单作业模式在生产环境运行更加稳定,所以是实际应用的首选模式。
需要注意的是,Flink 本身无法直接这样运行,所以单作业模式一般需要借助一些资源管
理框架来启动集群,比如 YARN、Kubernetes。
2.2.5 应用模式
前面提到的两种模式下,应用代码都是在客户端上执行,然后由客户端提交给 JobManager
的。但是这种方式客户端需要占用大量网络带宽,去下载依赖和把二进制数据发送给JobManager
;加上很多情况下我们提交作业用的是同一个客户端,就会加重客户端所在节点的资源消耗.
解决办法就是,我们不要客户端了,直接把应用提交到JobManger
上运行。而这也就
代表着,我们需要为每一个提交的应用单独启动一个JobManager
,也就是创建一个集群。这个 JobManager
只为执行这一个应用而存在,执行结束之后 JobManager
也就关闭了,这就是所谓的应用模式
2.2.6 应用模式和单作业模式
应用模式与单作业模式,都是提交作业之后才创建集群;
单作业模式是通过客户端来提交的,客户端解析出的每一个作业对应一个集群;而应用模式下,是直接由 JobManager
执行应用程序的,并且即使应用包含了多个作业,也只创建一个集群.
三 架构
3.1 Job Manager
3.2 TaskManager
3.3 作业提交流程
首先看一下比较抽象的/上层的作业提交流程.实际根据flink的部署模式不同,可能略有差别
3.3.1 standalone session 模式下的提交
3.3.2 Yarn session模式下的作业提交流程
3.3.3 Yarn单作业提交流程
3.4 程序与数据流
3.5 并行度
并行度有2个维度: 任务的并行 和 数据的 并行. 后者我们更为关注
并行度设定的优先级(由高到低)
keyedStream.sum(1).setParallelism(2)
在算子上直接设置env.setParallelism(1);
在执行环境上设置- webUI上提交时设置
- 集群
conf/
配置
3.6 数据传输形式 和算子链
-
算子优化前
-
什么是 “算子优化”
-
"算子优化"后
-
执行图
3.7 任务和任务槽
举个栗子:
几个深度思考
3.5.1 怎么从Flink程序得到任务?
- 四个 graph: StreamGraph --> JobGraph --> ExecutionGraph --> PhysicalGraph
3.5.2 一个流处理程序到底包含多少任务
- 算子链优化
3.5.3 最终执行任务占用多少slot
- 这个任务的最大并行度 = 最小slot