Apache Flink
Flink作为第三代流计算引擎,同采取了DAG Stage拆分的思想构建了存粹的流计算框架。被人们称为第三代大数据处理方案
。该计算框架和Spark设计理念出发点恰好相反。
- Spark: 底层计算引擎 批处理模型,在批处理之上构建流 - 流计算实时性较低
- Flink:底层计算就是连续的流计算模型,在流计算上模拟批处理 - 既保证流的实时性,有可以实现批处理。
第一代:2006年 Hadoop(HDFS、MapReduce),2014年 9月份 Storm 诞生顶级项目。
第二代:2014年2月份 Spark诞生 Spark RDD/DStream
第三代:2014年12月份Flink诞生。
原因是因为早期人们对大数据分析的认知或者业务场景大都停留在批处理
领域。才导致了Flink的发展相比较于Spark较为缓慢,直到2017年人们才慢慢将批处理
开始转向流处理
。
流计算场景:实时计算领域,系统监控、舆情监控、交通预测、国家电网、疾病预测,银行/金融 风控。
Spark架构 vs Flink 架构
**总结:**不难看出Flink在架构的设计优雅程度上其实和Spark是非常相似的。资源管理上Flink同样可以运行在Standalone和yarn、k8s等,在上层上抽象出 流处理和批处理两个维度数据的处理方式分别处理unbound和bounded数据。并且在DataStream和DateSet API之上均有对应的实现例如SQL处理、CEP-Event (Complex event processing)、MachineLearing等,也自然被称为第三代大数据处理方案。
Flink 运行与架构
参考:https://ci.apache.org/projects/flink/flink-docs-master/concepts/runtime.html
Flink会使用chaining oprators的方式将一些操作归并到一个subtask中,每个任务就是一个线程。这种chain operator方式类似于Spark DAG拆分。通过该种方式可以优化计算,减少Thread-to-Thread的通信成本。下图描绘了Flink 流计算chain操作
Flink架构角色:JobManager(类似Spark Master)、TaskManager(类似Spark Worker)、Client(类似Spark Driver)
- JobManager:任务计算master,负责分布式计算的协调,例如:线程调度、协调Checkpoints、失败恢复等。
There is always at least one Job Manager. A high-availability setup will have multiple JobManagers, one of which one is always the leader, and the others are standby.
- TaskManager:主要负责执行 流计算的中的任务集合(SubTasks = 线程集),负责流计算过程中数据缓存和数据交换,需要连接JobManager汇报自身状态,以及所负责的任务。
There must always be at least one TaskManager.
- Client:虽然类似于Driver,是程序执行入口,只负责发送任务给JobManager,并不负责任务执行期间的调度。一旦提交后,可以关闭client。(注意区分Spark中Driver,因为Spark Driver负责任务调度和恢复)
每一个TaskManager是一个JVM进程,用于执行1~n个subtasks(个子任务都运行在一个独立线程中),通过Task slots控制TaskManager JVM接受Tasks的数目(Job计算任务数目)。因此一个TaskManager至少有1个Task slots.
每个Task Slot表示一个Task Manager计算资源的一个子集。例如:一个Task Manager有3个slots,意味着每个Slots占用该JVM进程的1/3的内存资源。由于1个Task slot只能分配以一个Job,所以通过slots策略可以到达不同job任务计算间的隔离。就上述案例,如果给一个计算任务分配6 slots,该任务的种任务总数5,分配如下:
一个线程占用一个slots.其中还有一些多余的slot被浪费了,因此在使用Flink程序的时候需要用户精准的知道该job需要多好个Slot,以及任务的并行度。因为Flink可以做到同一个job中Task slots的共享。
默认情况下,Flink任务所需的TaskSlots的数目等于 其中一个Task的最大并行度。
Flink 安装部署
-
前提条件
- HDFS正常启动 (SSH免密码认证)
- JDK1.8+
-
上传并解压flink
[root@CentOS ~]# tar -zxf flink-1.8.1-bin-scala_2.11.tgz -C /usr/
- 配置flink-conf.yaml配置文件
[root@CentOS ~]# cd /usr/flink-1.8.1/
[root@CentOS flink-1.8.1]# vi conf/flink-conf.yaml
jobmanager.rpc.address: CentOS
taskmanager.numberOfTaskSlots: 4
[root@CentOS flink-1.8.1]# vi conf/slaves
CentOS
- 启动flink服务
[root@CentOS flink-1.8.1]# ./bin/start-cluster.sh
Starting cluster.
Starting standalonesession daemon on host CentOS.
Starting taskexecutor daemon on host CentOS.
[root@CentOS flink-1.8.1]# jps
4721 SecondaryNameNode
4420 DataNode
36311 TaskManagerRunner
35850 StandaloneSessionClusterEntrypoint
2730 QuorumPeerMain
3963 Kafka
36350 Jps
4287 NameNode
如果Flink需要将计算数据写入HDFS系统,需要注意Flink安装版本和Hadoop的版本,一般需要下载flink-shaded-hadoop-2-uber-xxxx.jar并且将该jar放置在Flink的lib目录下,这样做的目的是可以通过Flink直接操作HBase、HDFS、YARN都可以。第二种方案在是环境变量中配置HADOOP_CLASSPATH
访问http://centos:8081/#/overview查看flink web UI
快速入门
- pom.xml
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-core</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients_2.11</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-scala_2.11</artifactId>
<version>1.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-scala_2.11</artifactId>
<version>1.8.1</version>
</dependency>
- Client代码
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
import org.apache.flink.streaming.api.scala._
object FlinkStreamWordCount {
def main(args: Array[String]): Unit = {
//1.创建StreamExecutionEnvironment
val env=StreamExecutionEnvironment.getExecutionEnvironment
//2.设置Source
val lines:DataStream[String]=env.socketTextStream("CentOS",9999)
//3.对lines数据实现常规转换
lines.flatMap(_.split("\\s+"))
.map(WordPair(_,1))
.keyBy("word")
.sum("count")
.print()
//4.执行任务
env.execute("wordcount")
}
}
case class WordPair(word:String,count:Int)
- 任务提交
[root@CentOS flink-1.8.1]# ./bin/flink run --class com.baizhi.demo01.FlinkStreamWordCount -p 3 /root/flink-1.0-SNAPSHOT.jar
- 查看任务
[root@CentOS flink-1.8.1]# ./bin/flink list
Waiting for response...
------------------ Running/Restarting Jobs -------------------
26.08.2019 04:21:26 : 8b03648cbd94c37a200349ccf3ff0331 : wordcount (RUNNING)
--------------------------------------------------------------
No scheduled jobs.
- 取消
[root@CentOS flink-1.8.1]# ./bin/flink cancel 8b03648cbd94c37a200349ccf3ff0331
Flink基本结构
- 创建执行所需的环境 StreamExecutionEnvironment
2)构建DataStream
3)执行DataStream转换算子(lazy)
4)指定计算结果输出
5)执行计算任务env.execute(“job名字”)
创建ExecutionEnviroment
- getExecutionEnvironment()
val env=StreamExecutionEnvironment.getExecutionEnvironment
可以根据程序部署环境,自动识别运行上下文。用在本地执行和分布式环境
- createLocalEnvironment()
val env=StreamExecutionEnvironment.createLocalEnvironment(4)
指定本地测试环境。
- createRemoteEnvironment
val jarFiles="D:\\IDEA_WorkSpace\\BigDataProject\\20190813\\FlinkDataStream\\target\\flink-1.0-SNAPSHOT.jar"
val env=StreamExecutionEnvironment.createRemoteEnvironment("CentOS",8081,jarFiles)
获取任务执行计划
val env=StreamExecutionEnvironment.getExecutionEnvironment
//2.设置Source
val lines:DataStream[String]=env.socketTextStream("CentOS",9999)
//3.对lines数据实现常规转换
lines.flatMap(_.split("\\s+"))
.map(WordPair(_,1))
.keyBy("word")
.sum("count")
.print()
println(env.getExecutionPlan)
{
"nodes":[{
"id":1,"type":"Source: Socket Stream","pact":"Data Source","contents":"Source: Socket Stream","parallelism":1},{
"id":2,"type":"Flat Map","pact":"Operator","contents":"Flat Map","parallelism":16,"predecessors":[{
"id":1,"ship_strategy":"REBALANCE","side":"second"}]},{
"id":3,"type":"Map","pact":"Operator","contents":"Map","parallelism":16,"predecessors":[{
"id":2,"ship_strategy":"FORWARD","side":"second"}]},{
"id":5,"type":"aggregation","pact":"Operator","contents":"aggregation","parallelism":16,"predecessors":[{
"id":3,"ship_strategy":"HASH","side":"second"}]},{
"id":6,"type":"Sink: Print to Std. Out","pact":"Data Sink","contents":"Sink: Print to Std. Out","parallelism":16,"predecessors":[{
"id":5,"ship_strategy":"FORWARD","side":"second"}]}]}
打开网页:https://flink.apache.org/visualizer/将以上的json黏贴到该网页
就可以看到任务执行计划:
Data Source
Source是流计算应用的输入,用户可以通过``StreamExecutionEnvironment.addSource(sourceFunction)给流计算指定输入,其中sourceFunction可以使
SourceFunction或者是
ParallelSourceFunction|RichParallelSourceFunction `实现自定义的输入Source.当然Flink也提供了一些内建的Source以便于测试使用:
File-based
- readTextFile(path)
底层使用的TextInputForamt读取,仅仅读取一次。
//1.创建StreamExecutionEnvironment
val env=StreamExecutionEnvironment.getExecutionEnvironment
//2.设置Source
val lines:DataStream[String]=env.readTextFile("hdfs://CentOS:9000/demo/words")
//3.对lines数据实现常规转换
lines.flatMap(_.split("\\s+"))
.map((_,1))
.keyBy(0)
.sum(1)
.print()
//4.执行任务
env.execute("wordcount")
提示如果读取HDFS的文件系统需要额外引入依赖
<!--添加HDFS支持-->
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>