1. Flink的特点
-
事件驱动(Event-driven)
-
基于流处理
一切皆由流组成,离线数据是有界的流;实时数据是一个没有界限的流。(有界流、无界流)
-
分层API
-
越顶层越抽象,表达含义越简明,使用越方便
-
越底层越具体,表达能力越丰富,使用越灵活
-
1.1 Flink vs Spark Streaming
-
数据模型
-
Spark采用RDD模型,spark streaming的DStream实际上也就是一组组小批数据RDD的集合
-
flink基本数据模型是数据流,以及事件(Event)序列
-
-
运行时架构
-
spark是批计算,将DAG划分为不同的stage,一个完成后才可以计算下一个
-
flink是标准的流执行模式,一个事件在一个节点处理完后可以直接发往下一个节点处理
-
2. 快速上手
2.1 批处理实现WordCount
flink-steaming-scala_2.12 => org.apache.flink:flink-runtime_2.12:1.12.1 => com.typesafe.akka:akka-actor_2.12:2.5.21,akka就是用scala实现的。即使这里我们用java语言,还是用到了scala实现的包
pom依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>zch</artifactId>
<groupId>com.zch</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>flink</artifactId>
<dependencies>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-java</artifactId>
<version>1.10.1</version>
</dependency>
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-streaming-java_2.12</artifactId>
<version>1.10.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>1.7.15</version>
</dependency>
</dependencies>
</project>
代码实现
package com.zch.flink;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.DataSet;
import org.apache.flink.api.java.ExecutionEnvironment;
import org.apache.flink.api.java.operators.AggregateOperator;
import org.apache.flink.api.java.operators.DataSource;
import org.apache.flink.api.java.tuple.Tuple1;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.util.Collector;
/**
* Author: zhaoHui
* Date: 2022/01/19
* Time: 12:02
* Description: 批处理wordCount
*/
public class WordCount {
public static void main(String[] args) throws Exception {
// 创建执行环境
ExecutionEnvironment env = ExecutionEnvironment.getExecutionEnvironment();
// 从文件中读取数据
String inputPath = "F:\\JAVA\\bigdata2107\\zch\\flink\\src\\main\\resources\\Herry.txt";
DataSource<String> dataSource = env.readTextFile(inputPath);
// 对数据集进行处理,按空格分隔,转换成(word,1),进行词频统计
DataSet<Tuple2<String,Integer>> sum = dataSource.flatMap(new MyFlatMapper())
.groupBy(0) // 按照第一个位置的word分组
.sum(1);// 按照第二个位置的值进行求和
sum.print();
}
// 自定义类,实现FlatMapFunction接口
public static class MyFlatMapper implements FlatMapFunction<String, Tuple2<String,Integer>>{
public void flatMap(String value, Collector<Tuple2<String, Integer>> out) throws Exception {
// 按空格分词
String[] words = value.split(" ");
// 遍历所有word,包装成二元组输出
for (String word : words) {
Tuple2<String, Integer> tuple2 = new Tuple2<String, Integer>(word, 1);
out.collect(tuple2);
}
}
}
}
输出:
(different,1)
(models,volumetric,2)
(particle,1)
(provide,1)
(At,1)
(a,1)
(discussed,1)
(in,1)
(models,implicit,1)
(not,1)
...
[解决 Flink 升级1.11 报错 No ExecutorFactory found to execute the application]
在项目添加依赖即可
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-clients_2.12</artifactId>
<version>1.10.1</version>
</dependency>
在2.1批处理的基础上,新建一个类进行改动。
-
批处理=>几组或所有数据到达后才处理;流处理=>有数据来就直接处理,不等数据堆叠到一定数量级
-
这里不像批处理有groupBy => 所有数据统一处理,而是用流处理的keyBy => 每一个数据都对key进行hash计算,进行类似分区的操作,来一个数据就处理一次,所有中间过程都有输出!
-
并行度:开发环境的并行度默认就是计算机的CPU逻辑核数
代码实现
package com.zch.flink;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.api.java.utils.ParameterTool;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
/**
* Author: zhaoHui
* Date: 2022/01/19
* Time: 12:43
* Description: 流处理wordCount
*/
public class StreamWordCount {
public static void main(String[] args) throws Exception {
// 创建流处理执行环境
StreamExecutionEnvironment env = StreamContextEnvironment.getExecutionEnvironment();
// 设置并行度,默认值 = 当前计算机的CPU逻辑核数(设置成1即单线程处理)
// env.setMaxParallelism(32);
// 从文件中读取数据
String inputPath = "F:\\JAVA\\bigdata2107\\zch\\flink\\src\\main\\resources\\Herry.txt";
DataStream<String> inputDataStream = env.readTextFile(inputPath);
// 基于数据流进行转换计算
DataStream<Tuple2<String,Integer>> resultStream = inputDataStream.flatMap(new WordCount.MyFlatMapper())
.keyBy(0)
.sum(1);
resultStream.print();
// 执行任务
env.execute();
}
}
输出:
这里因为是流处理,所以所有中间过程都会被输出,前面的序号就是并行执行任务的线程编号。
9> (world,1)
5> (hello,1)
8> (are,1)
10> (you,1)
11> (how,1)
6> (thank,1)
9> (fine,1)
这里env.execute();
之前的代码,可以理解为是在定义任务,只有执行env.execute()
后,Flink才把前面的代码片段当作一个任务整体(每个线程根据这个任务操作,并行处理流数据)。