目录
一、初识Flink
Apache Flink是一个面向分布式数据流处理和批量数据处理的开源计算平台,提供支持流处理和批处理两种类型应用的功能。
实时处理:Storm (Storm Trident)、Spark Streaming、Flink
- Storm:支持低延迟,但是很难实现高吞吐,并且不能保证 exactly-once
- Sparking Streaming ( Storm Trident ):利用微批处理实现的流处理(将连续事件的流数据分割成一系列微小的批量作业),能够实现 exactly-once 语义,但不可能做到完全实时(毕竟还是批处理,不过还是能达到几秒甚至几亚秒的延迟)
- Flink:实时流处理,支持低延迟、高吞吐、exactly-once 语义、有状态的计算、基于事件时间的处理
二、Flink的重要特点:
1、事件驱动型(Event-driven)
以事件为单位处理,典型的kafka是事件型,sparkstreaming是以时间为单位。
2、流与批的世界观
批处理的特点是有界、持久、大量,非常适合需要访问全套记录才能完成的计算工作,一般用于离线统计。
流处理的特点是无界、实时, 无需针对整个数据集执行操作,而是通过系统传输的每个数据项执行操作,一般用于实时统计。
在spark的世界观中,一切都是由批次组成的,离线数据是一个大批次,而实时数据是由一个一个无限的小批次组成的。
在flink的世界观中,一切都是由流组成的,离线数据是有界限的流,实时数据是没有界限的流,这就是有界流和无界流。
无界数据流:无界数据流有一个开始但是没有结束,它们不会在生成时终止并提供数据,必须连续处理无界流,也就是说必须在获取后立即处理event。对于无界数据流我们无法等待所有数据都到达,因为输入是无界的,并且在任何时间点都不会完成。处理无界数据通常要求以特定顺序(例如事件发生的顺序)获取event,以便能够推断结果完整性。
有界数据流:有界数据流有明确定义的开始和结束,可以在执行任何计算之前通过获取所有数据来处理有界流,处理有界流不需要有序获取,因为可以始终对有界数据集进行排序,有界流的处理也称为批处理。
这种以流为世界观的架构,获得的最大好处就是具有极低的延迟。
3、分层API
最底层级的抽象仅仅提供了有状态流,它将通过过程函数(Process Function)被嵌入到DataStream API中。大多数应用并不需要上述的底层抽象,而是针对核心API(Core APIs) 进行编程,比如DataStream API(有界或无界流数据)以及DataSet API(有界数据集),Table API 是以表为中心的声明式编程,其中表可能会动态变化(在表达流数据时)。Flink提供的最高层级的抽象是 SQL 。
4、支持有状态计算
状态管理,所谓状态管理就是在流失计算过程中将算子的中间结果保存在内存或者文件系统中,等下一个事件进入算子后可以让当前事件的值与历史值进行汇总累计。(updatestatebykey,chekpoint或者保存带redis)
5、支持exactly-once语义
Exactly once: sender发送一条message到receiver,如果receiver出现fail,sender确保每条message到receiver只收到一次
6、支持事件时间(EventTime)
目前大多数框架时间窗口计算,都是采用当前系统时间,以时间为单位进行的聚合计算只能反应数据到达计算引擎的时间,而并不是实际业务时间
三、安装配置
1、standalone模式
(1)修改flink/conf/flink-conf.yaml 文件
(2)修改 /conf/slave文件并分发给hdp-2,hdp-3
(3)启动
[root@hdp-1 bin]# ./start-cluster.sh
打开网址http://hdp-1:8081验证
(4)执行程序
./flink run -c com.xin.flink.app.BatchWcApp /ext/flink0503-1.0-SNAPSHOT.jar --input /applog/flink/input.txt --output /applog/flink/output.csv
四、API案例
1、wordcount
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-scala_2.11</artifactId>
<version>1.7.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.flink/flink-streaming-scala -->
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-scala_2.11</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 该插件用于将Scala代码编译成class文件 -->
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.4.6</version>
<executions>
<execution>
<!-- 声明绑定到maven的compile阶段 -->
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
scala版本
object WordCount {
def main(args: Array[String]): Unit = {
// 1.env 2.source 3.transform 4.sink
//构造执行环境
val env: ExecutionEnvironment = ExecutionEnvironment.getExecutionEnvironment
//读取文件
val input = "in/hello.text"
val ds: DataSet[String] = env.readTextFile(input)
// 其中flatMap 和Map 中 需要引入隐式转换
import org.apache.flink.api.scala.createTypeInformation
//经过groupby进行分组,sum进行聚合
val aggDs: AggregateDataSet[(String, Int)] = ds.flatMap(_.split(" "))
.map((_, 1)).groupBy(0).sum(1) //1代表 _._2
// 打印
aggDs.print()
}