貌似扯远了,接下来就正题吧。
Flink是一种由Java和Scala编写的分布式数据流处理框架。与其他分布式框架不同的是,其将流处理和批处理统一起来,流处理的数据是无界的,批处理的数据是有界的,一种特殊的流处理。
1. 架构
Flink程序是由Stream和Transformation这两个基本块构建组成的,其中Stream是中间结果数据,Transformation是一个操作,它对一个或者多个Stream输入进行处理,输出一个或多个Stream。
1.1 运行层
运行层以JobGraph形式接收程序。JobGraph为一个一般化的并行数据流图,它拥有任意数量的Task来接收和产生data stream。一个Stream可以被分成多个Stream分区,一个Operator可以被分成多个Operator Subtask,每一个Operator Subtask是在不同的线程中独立执行的,可能在不同机器或容器上执行。
https://flink.sojb.cn/concepts/programming-model.html
Stream可以One-to-One和Redistribution模式在两个Operator之间传输数据
- One-to-One,(如Source和map算子之间)保存数据元的分区和排序。这意味着map()中看到的数据流中记录的顺序,与Source中看到的记录顺序是一致的。
- Redistribution,Streams在map()和keyBy/window之间,以及keyBy/window和Sink之间改变Stream的分区。每个Operator subtask根据所选的转换向不同的目标subtasks发送数据。例如keyBy()
Flink分布式执行环境中,会将多个Operator Subtask串起来组成一个Operator Chain,每个Operator Chain会在TaskManager上独立的线程中执行。
1.2 窗口
聚合操作(例如计数、和)在Stream上的工作方式上与批处理不同。例如,不可能计算Stream中的所有元素,因为Stream通常是无边界的。所以,Stream上的聚合由窗口限定范围,例如“过去5分钟内的计数或最后100个元素的总和”。
1.3 时间
Flink中的时间有几种:
- Event Time 创建事件的时间,通常由事件中的时间戳描述,例如由生产传感器或生产服务附加。Flink通过时间戳分配器访问Event Time
- Ingestion time 事件在Source Operator处进入Flink dataflow的时间
- Processing Time 每个执行基于时间的操作的Operator的本地时间。
1.4 有状态的操作(Stateful Operators)
虽然dataflow中的许多操作一次只查看一个单独事件(例如一个事件解析器),但是有些操作可以跨多个事件记录信息(例如窗口Operators)。这些操作称为有状态的。
有状态操作的状态维护可以认为是一个embedded key/value 存储。严格分区和分布的状态与Streams一起被Stateful Operators读取。因此,只有在keyBy()函数之后的键控制流上才能访问key/value状态,并且只能访问与当前事件的键关联的值。将流的键与状态对齐可以确保所有状态更新都是本地操作,从而确保一致性Tasks and Operator ChainTasks and Operator Chain,而不需要事务开销。这种对齐还允许Flink重新分配状态并透明地调整Stream分区。
1.5 容错
占位,先不写,这个有点耗时。。。
1.6 任务和 Operator 链接
对于分布式执行,Flink将operator subtasks链接到任务中。每个任务由一个线程执行。将operators链接到任务中是一种有用的优化:它减少了线程到线程切换和缓冲的开销,增加了总体的吞吐量,同时降低了延迟。
2. 集群调度
2.1 Flink运行时由两种类型的进程组成:
JobManagers(也称为masters)协调分布式执行。负责安排任务、协调检查点、协调故障恢复等。
至少有一个Job Manager。一个高可用性的设置将有多个Job Managers,其中一个是领导,其他的总是备用的。
TaskManagers(也称为workers)执行数据流的任务(或者更具体说,subtasks),并缓冲和交换数据流。至少有一个TaskManager
JobManagers和TaskManagers可以通过多种方式启动:直接在机器上作为独立集群启动,或者在容器中启动,或者由像YARN或Mesos之类的资源框架管理。TaskManagers连接到JobManagers,宣布自己可用,并分配工作。
client不是运行时和runtime和程序执行的一部分,而是用于准备和向JobManager发送数据流。然后,client可以断开连接,或者保持连接以接收进度报告。client可以作为触发执行Java/Scala程序的一部分运行,也可以在命令行进行中运行。
2.2 调度
在JobManager端,会接收到Client提交的JobGraph形式的Flink Job,JobManager会将一个JobGraph转换映射为一个ExecutionGraph,ExecutionGraph是JobGraph的并行表示,也就是实际JobManager调度一个Job在TaskManager上运行的逻辑视图。
资源的分配与使用例子:
- 左上图:有2个TaskManager,每个TaskManager有3个Task Slot
- 左下图:一个Flink JobGraph,逻辑上包含了1个data source、1个MapFunction、1个ReduceFunction。
- 左下图:用户提交的Flink Job对各个Operator进行的配置——data douorce的并行度设置为4,MapFunction的并行度也为4,ReduceFunction的并行度为3,在JobManager端对应于ExecutionGraph
- 右上图:TaskManager1上,有2个并行的ExecutionVertex组成的DAG图,它们各占用一个Task Slot
- 右下图:TaskManager2上,有2个并行的ExecutionVertex组成的DAG图,它们各占用一个Task Slot
- 在2个TaskManager上运行的4个Execution是并行执行的
2.3 迭代
普通迭代、增益迭代。占位,先不写。。。。
2.4 监控
流处理系统中,当下游Operator处理速度跟不上的情况,如果下游Operator能够将自己处理状态传播给上游Operator,使得上游Operator处理速度慢下来就会缓解上述问题,比如通过告警的方式通知现有流处理系统存在的问题。
Flink web界面上提供了对运行Job的Backpressure行为的监控,它通过使用Sampling线程对正在运行的Task进行堆栈跟踪采样来实现。
默认情况下,JobManager会每间隔50ms触发对一个Job的每个Task依次进行100次堆栈跟踪调用,过计算得到一个比值,例如,radio=0.01,表示100次中仅有1次方法调用阻塞。Flink目前定义了如下Backpressure状态:
- OK: 0 <= Ratio <= 0.10
- LOW: 0.10 < Ratio <= 0.5
- HIGH: 0.5 < Ratio <= 1
3. 上层库
- Table :Flink的Table API实现了使用类SQL进行流和批处理。https://ci.apache.org/projects/flink/flink-docs-release-1.2/dev/table_api.html
- CEP:支持在流中发现复杂的事件模式,快速筛选用户感兴趣的数据。https://ci.apache.org/projects/flink/flink-docs-release-1.2/concepts/programming-model.html#next-steps
- Gelly:图计算API,提供了简化开发和构建图计算分析应用的接口。https://ci.apache.org/projects/flink/flink-docs-release-1.2/dev/libs/gelly/index.html
- FlinkML:FlinkML是Flink提供的机器学习库,提供了可扩展的机器学习算法、简洁的API和工具简化机器学习系统的开发。https://ci.apache.org/projects/flink/flink-docs-release-1.2/dev/libs/ml/index.html
4. 安装配置
下载,https://flink.apache.org/downloads.html#apache-flink-164
移动到hadoop用户,
mv flink-1.6.4-bin-hadoop28-scala_2.11.tgz /home/hadoop
解压:
tar -zxvf flink-1.6.4-bin-hadoop28-scala_2.11.tgz
Flink有多种部署模式,Local本地部署、Standalone Cluster集群部署、Flink ON YARN。这里使用Local本地部署,用于开发调试。其实很简单,直接在bin目录下执行
bin$ ./start-cluster.sh
jps命令后出现StandaloneSessionClusterEntrypoint进程,打开地址http://localhost:8081,即可进入Flink web管理页面
至于Standalone Cluster集群模式,则是需要修改配置文件。Flink ON YARN是在生产环境使用的,比较重型,做开发与调试不是很适合,需要另外启动Hadoop集群YARN任务,浪费资源。
5. IDEA开发配置
这里使用maven配置IDEA,为了maven更新下载快些,先配置下国内的源,比如阿里云。
添加~/.m2/settings.xml 文件,加入如下声明:
<?xml version="1.0" encoding="UTF-8"?>
配置阿里云后更新就飞起来了。然后是pom.xml添加项目jar包依赖和一些声明。
。。。balabala,配置是个阻挡入门的帮手。。。
然后开始写代码了。
6. 创建第一个WordCount程序
public
整个程序很简单,统计10秒内stream时间窗口上的单词数。
StreamExecutionEnvironment是一个任务的入口类,可以用于设置参数和创建数据源以及提交任务。
StreamExecutionEnvironment
下一步,创建一个从本地端口号9003的socket中读取数据的数据源,"n"换行符是指数据每行每行的读取,Flink的时间窗口是读取指定时间窗口内的数据,并进行处理。
DataStream
这里创建了一个字符串类型的DataStream。在这段代码中,我们计算每个单词在特定时间窗口中出现的次数,比如10秒窗口。所以,首先应该分割字符串解析成Tuple2<单词,次数>的形式表示。实现了一个flatmap:
DataStream
接着将生成的Stream按照单词字段做分组,keyBy(0)即是以Tuple的第一个元素为key,然后取10秒窗口的数据流进行聚合。.timeWindow()指定需要的滚动窗口时间。.sum聚合函数以窗口的每个key计算聚合,参数1指按照次数字段相加,得到的结果数据流,将每5秒输出一次这5秒内每个单词的出现次数。
DataStream
最后将数据流打印到控制台,并执行execute调用提交作业到集群上或本地计算机运行。
windowCounts
这时,使用netcat命令在终端,获取输入流:
9003
在终端输入单词,按回车,数据才进入SocketWindowWordCount程序运行计算,因为定义flink读取数据以换行符为每次读取数据的间隔。