- 无界流: 有定义流的开始,但没有定义流的结束。它们会无休止地产生数据。无界流的数据必须持续处理,即数据被摄取后需要立刻处理。我们不能等到所有数据都到达再处理,因为输入是无限的,在任何时候输入都不会完成。处理无界数据通常要求以特定顺序摄取事件,例如事件发生的顺序,以便能够推断结果的完整性。
- 有界流: 有定义流的开始,也有定义流的结束。有界流可以在摄取所有数据后再进行计算。有界流所有数据可以被排序,所以并不需要有序摄取。有界流处理通常被称为批处理。
Flink 被设计为能够很好地工作在上述每个资源管理器中,这是通过资源管理器特定(resource-manager-specific)的部署模式实现的。Flink 可以采用与当前资源管理器相适应的方式进行交互。
部署 Flink 应用程序时,Flink 会根据应用程序配置的并行性自动标识所需的资源,并从资源管理器请求这些资源。在发生故障的情况下,Flink 通过请求新资源来替换发生故障的容器。提交或控制应用程序的所有通信都是通过 REST 调用进行的,这可以简化 Flink 与各种环境中的集成。
Flink 用户报告了其生产环境中一些令人印象深刻的扩展性数字
每天处理数万亿的事件
可以维护几TB大小的状态
可以部署上千个节点的集群
在实际生产的过程中,大量数据在不断地产生,例如金融交易数据、互联网订单数据、 GPS 定位数据、传感器信号、移动终端产生的数据、通信信号数据等,以及我们熟悉的网络流量监控、服务器产生的日志数据,这些数据最大的共同点就是实时从不同的数据源中产生, 然后再传输到下游的分析系统。针对这些数据类型主要包括实时智能推荐、复杂事件处理、 实时欺诈检测、实时数仓与 ETL 类型、流数据分析类型、实时报表类型等实时业务场景,而 Flink 对于这些类型的场景都有着非常好的支持。
在flink整个软件架构体系中。同样遵循着分层的架构设计理念,在降低系统耦合度的同时,也为上层用户构建 flink 应用提供了丰富且友好的接口。
Flink 整个系统主要由两个组件组成,分别为 JobManager 和 TaskManager,Flink 架构也遵循 Master-Slave 架构设计原则,JobManager 为 Master 节点,TaskManager 为 Worker(Slave)节点。所有组件之间的通信都是借助于 Akka Framework,包括任务的状态以及 Checkpoint 触发等信息。
主机名 | JobManager | TaskManager |
---|---|---|
node01 | 是 | 是 |
node02 | 是 | 是 |
node03 | 是 |
依赖:
下载安装包:flink-1.13.0-bin-scala_2.11.tgz
上传安装包到node01服务器,然后解压
tar -zxvf flink-1.13.0-bin-scala_2.11.tgz -C /bigdata/install/
# 1、修改配置文件conf/flink-conf.yaml,新增配置
# 使用zookeeper搭建高可用
high-availability: zookeeper
# 存储JobManager的元数据到HDFS
high-availability.storageDir: hdfs://node01:8020/flink
high-availability.zookeeper.quorum: node01:2181,node02:2181,node03:2181
# 2、修改conf/masters
# 指定集群的JobManager地址
node01:8081
node02:8081
# 3、修改conf/workers
# 指定集群的TaskManager地址
node01
node02
node03
# 4、拷贝到其他节点
scp -r /bigdata/install/flink-1.13.0 node02:/bigdata/install
scp -r /bigdata/install/flink-1.13.0 node03:/bigdata/install
# 5、配置Flink集成hadoop
# 修改每个节点的/etc/profile, 添加 HADOOP_CLASSPATH,然后每个节点执行 source /etc/profile
export HADOOP_CLASSPATH=`hadoop classpath`
# 6、node01(JobMananger)节点启动,注意:启动之前先启动hadoop和zookeeper集群
cd /kkb/install/flink-1.13.0
bin/start-cluster.sh
# 7、关闭flink集群, 在主节点上执行
cd /bigdata/install/flink-1.13.0
bin/stop-cluster.sh
jobmanager.memory.process.size: jobmanager节点可用的内存大小
taskmanager.memory.process.size: taskmanager节点可用的内存大小
taskmanager.numberOfTaskSlots: 每台taskmanager节点提供的TaskSlot总数
parallelism.default: 默认情况下任务的并行度
taskmanager.tmp.dirs: taskmanager的临时数据存储目录
Flink on Yarn 有三种模式
无论是 Session 还是 Per Job 模式,程序代码都是在客户端编译完成。这里的客户端就是我们执行 flink run 启动的程序(其实是Cli Frontend)。假如现在需要做一个平台给多个用户提交任务,或者任务的量级很大,那么客户端的压力会非常大。因为编译生成
StreamGraph
和JobGraph
需要消耗大量的CPU,下载依赖的Jar包资源、上传 JobGraph 也需要大量的网络带宽,客户端很容易成为瓶颈。此时就考虑可不可以把编译图的工作放在集群中完成?
【yarn-session.sh(开辟资源) + flink run(提交任务)】
# 1. 在 flink 目录启动 yarn-session
bin/yarn-session.sh -n 2 -tm 1024 -s 1 -d
# -n: 指定申请多少个容器
# -s: 指定每个容器启动多少个slot
# -tm: 指定每个 TaskManager 申请多少内存
# -d: 以后台进程方式运行
# 2. 使用 flink 脚本提交任务
bin/flink run examples/batch/WordCount.jar -input hdfs://node01:8020/words.txt -output hdfs://node01:8020/output/result.txt
# 如果启动了很多的yarn-session, 在提交任务的时候可以通过参数 -yid 指定作业提交到哪一个yarn-session中运行
# 例如:
bin/flink run -yid application_1647823591557_0001 examples/batch/WordCount.jar -input hdfs://node01:8020/words.txt -output hdfs://node01:8020/output/result1.txt
# 3. 停止任务
yarn application -kill application_1647823591557_0001
【必选】
-n,--container <arg> # 分配多少个 yarn 容器 (=taskmanager的数量)
【可选】
-D <arg> # 动态属性
-d,--detached # 独立运行
-jm,--jobManagerMemory <arg> # JobManager 的内存 [in MB]
-nm,--name # 在 YARN 上为一个自定义的应用设置一个名字
-q,--query # 显示 yarn 中可用的资源 (内存, cpu核数)
-qu,--queue <arg> # 指定 YARN 队列.
-s,--slots <arg> # 每个 TaskManager 使用的 slots 数量
-tm,--taskManagerMemory <arg> # 每个 TaskManager 的内存 [in MB]
-z,--zookeeperNamespace <arg> # 针对 HA 模式在 zookeeper 上创建 NameSpace
-id,--applicationId <yarnAppId> # YARN 集群上的任务 id,附着到一个后台运行的 yarn session 中
【flink run -t yarn-per-job(开辟资源+提交任务)】
# 启动集群,执行任务
bin/flink run -t yarn-per-job -yjm 1024 -ytm 1024 examples/batch/WordCount.jar -input hdfs://node01:8020/words.txt -output hdfs://node01:8020/output/result2.txt
# 注意:client端必须要设置 YARN_CONF_DIR 或者 HADOOP_CONF_DIR 或者 HADOOP_HOME 环境变量,通过这个环境变量来读取 YARN 和 HDFS 的配置信息,否则启动会失败。
flink run
脚本参数说明run [OPTIONS] <jar-file> <arguments>
"run" 操作参数:
-c,--class <classname> # 如果没有在jar包中指定入口类,则需要在这里通过这个参数指定
-m,--jobmanager <host:port> # 指定需要连接的jobmanager(主节点)地址,使用这个参数可以指定一个不同于配置文件中的jobmanager
-p,--parallelism <parallelism> # 指定程序的并行度。可以覆盖配置文件中的默认值。
-t,--target <arg> # 用来指定部署目标
# 补充【任务提交到standalone集群中运行】需要指定连接 host 和 port 的 jobmanager
bin/flink run -m node01:6123 examples/batch/WordCount.jar -input hdfs://hostname:port/hello.txt -output hdfs://hostname:port/result1
【flink run-application -t yarn-application】
# 启动集群,执行任务
bin/flink run-application -t yarn-application -Djobmanager.memory.process.size=1024m \
-Dtaskmanager.memory.process.size=1024m \
-Dtaskmanager.numberOfTaskSlots=1 \
examples/batch/WordCount.jar \
-input hdfs://node01:8020/words.txt \
-output hdfs://node01:8020/output2
# -t: 用来指定部署目标,目前支持 YARN(yarn-application)和K8S(kubernetes-application)。
# -D: 用来指定与作业相关的各项参数,具体可参见官方文档。
那么如何解决传输依赖项造成的带宽占用问题呢?Flink作业必须的依赖是发行包 flink-dist.jar,还有扩展库(位于== F L I N K H O M E / l i b ) = = 和 插 件 库 ( 位 于 = = FLINK_HOME/lib)==和插件库(位于== FLINKHOME/lib)==和插件库(位于==FLINK_HOME/plugin==)?
yarn.provided.lib.dirs
参数指定存储的路径即可。-Dyarn.provided.lib.dirs="hdfs://myhdfs/flink-common-deps/lib;hdfs://myhdfs/flink-common-deps/plugins"
Flink on Yarn 部署很简单,就是只要部署好 hadoop 集群即可,我们只需要部署一个 Flink 客户端,然后从 flink 客户端提交 Flink 任务即可。类似于 spark on yarn 模式。
<properties>
<flink.version>1.13.0flink.version>
properties>
<dependencies>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-clients_2.11artifactId>
<version>${flink.version}version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-streaming-java_2.12artifactId>
<version>${flink.version}version>
dependency>
<dependency>
<groupId>org.apache.flinkgroupId>
<artifactId>flink-streaming-scala_2.11artifactId>
<version>${flink.version}version>
dependency>
dependencies>
import org.apache.flink.streaming.api.scala.{DataStream, StreamExecutionEnvironment}
//导入隐式转换的包
import org.apache.flink.api.scala._
object WordCountStreamScala {
def main(args: Array[String]): Unit = {
// 1. 构建流处理环境
val env = StreamExecutionEnvironment.getExecutionEnvironment
// 2. 从socket获取数据
val sourceStream: DataStream[String] = env.socketTextStream("node01", 9999)
// 3. 对数据进行处理
val result: DataStream[(String, Int)] = sourceStream
.flatMap(x => x.split(" ")) // 按照空格切分
.map(x => (x, 1)) // 每个单词计为1
.keyBy(x => x._1) // 按照单词进行分组
.sum(1) // 按照下标为1累加相同单词出现的次数
// 4. 打印输出, sink
result.print()
// 5. 开启任务
env.execute("WordCountStreamScala")
}
}
nc -lk 9999
发送 socket 数据,并查看控制台输出结果flink run -t yarn-per-job -yjm 1024 -ytm 1024 -c com.yw.flink.example.WordCountStreamScala flink-demo-1.0.jar
public class WordCountStreamJava {
public static void main(String[] args) throws Exception {
// 1. 构建流处理环境
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 2. 从socket获取数据
DataStreamSource<String> streamSource = env.socketTextStream("node01", 9999);
// 3. 对数据进行处理
DataStream<Tuple2<String, Integer>> resultStream = streamSource
.flatMap((FlatMapFunction<String, Tuple2<String, Integer>>) (line, collector) -> {
String[] words = line.split(" ");
Arrays.stream(words).filter(Objects::nonNull)
.forEach(word -> collector.collect(new Tuple2<>(word, 1)));
}).returns(Types.TUPLE(Types.STRING, Types.INT))
.keyBy((KeySelector<Tuple2<String, Integer>, String>) tuple2 -> tuple2.f0)
.sum(1);
// 4. 打印输出, sink
resultStream.print();
// 5. 开启任务
env.execute("WordCountStreamJava");
}
}
import org.apache.flink.api.scala.{DataSet, ExecutionEnvironment}
import org.apache.flink.api.scala._
/**
* scala开发flink的批处理程序
*/
object WordCountBatchScala {
def main(args: Array[String]): Unit = {
// 1. 构建Flink的批处理环境
val env = ExecutionEnvironment.getExecutionEnvironment
// 2. 读取数据文件
val fileDataSet: DataSet[String] = env.readTextFile("words.txt")
// 3. 对数据进行处理
val resultDataSet: DataSet[(String, Int)] = fileDataSet
.flatMap(x => x.split(" "))
.map(x => (x, 1))
.groupBy(0)
.sum(1)
// 4. 打印结果
resultDataSet.print()
// 5. 保存结果到文件
resultDataSet.writeAsText("output")
env.execute("FlinkFileCount")
}
}