学习方法汇总:
flink官方文档
flink中文学习社区
B站视频:Apache_Flink
一些操作(数据处理等)会跨多个事件的信息(如窗口操作)。这些操作称为有状态。状态由一个任务维护,并且用来计算某个结果的所有数据,都属于这个任务的状态。可以简单的任务状态就是一个本地变量,可以被任务的业务逻辑访问。
窗口就是一个典型的状态,只有窗口结束才会输出数据,所以之前的数据一直被存储。
每个状态都是当前任务去管理维护,每个状态都是和当前算子关联在一起的,如果需要Flink真正的把他管理起来的话在运行时的时候Flink就必须要知道当前状态定义的类型是什么,所以一开始必须注册对应的状态,要有所谓的描述器。Flink有两种基本的状态:Operator State算子状态和Keyed State键控状态。
Operator State可以用在所有算子上,每个算子子任务或者说每个算子实例共享一个状态,流入这个算子子任务的数据可以访问和更新这个状态。
算子状态有3种基本数据结构:
①列表状态(List state):状态表示为一组数据的列表
②联合列表状态(Union list state):也将状态表示为数据的列表。它与常规列表状态的区别在于,在发生故障时,或者从保存点(savepoint)启动应用程序时如何恢复。
③广播状态(Broadcast state):如果一个算子有多项任务,而它的每项任务状态又都相同,那么这种特殊情况最适合应用广播状态。那就可以访问到别的并行子任务的状态。
只能在KeyedStream后使用,可以通过 stream.keyBy(…) 来得到 KeyedStream 。键控状态总是相对于键,根据键来维护和访问的。也就是数据调用keyby之后对各个的key维护自己的状态。
Keyed State很类似于一个分布式的key-value map数据结构,只能用于KeyedStream(keyBy算子处理之后)。键控状态基于每个key去管理,一般keyby进行HashCode重分区后基于它自己独享的内存空间就会针对每一个不同的key分别保存一份独立的存储状态,而且接下来来了一个新的数据只能访问自己的状态,不能访问其他key的,Flink会为每一个key维护一个状态。
Keyed 状态支持的数据类型
每种 state 都对应各自的描述符,通过描述符从 RuntimeContext 中获取对应的 State,而 RuntimeContext 只有 RichFunction 才能获取,所以要想使用 keyed state,用户编写的类必须继承 RichFunction 或者其子类。
Flink提供不同的State Backends状态后端,指定如何和在何处存储状态。
(1)MemoryStateBackend
将键控状态作为内存中的对象进行管理,将它们存储在TaskManager的JVM堆上,将checkpoint存储在JobManager的内存中
(2)FsStateBackend
本地状态存在TaskManager的JVM堆上,checkpoint存到远程的持久化文件系统(FileSystem)上。需要配置一个 checkpoint 路径,例如“hdfs://namenode:40010/flink/checkpoints” 或者 “file:///data/flink/checkpoints”,我们一般配置为 hdfs 目录
(3)RocksDBStateBackend
将所有状态序列化后,存入本地的RocksDB中存储。RocksDB 使用内存加磁盘的方式存储数据。
设置状态后端如下:
**val env = StreamExecutionEnvironment.getExecutionEnvironment()
//val checkpointPath: String = checkpoint_Path
//val backend = new RocksDBStateBackend(checkpointPath)
//env.setStateBackend(backend)
env.setStateBackend(new FsStateBackend(YOUR_PATH))
env.enableCheckpointing(1000)
// 配置重启策略
env.setRestartStrategy(RestartStrategies.fixedDelayRestart(60, Time.of(10, TimeUnit.SECONDS)))
**
在流执行模式下,Flink 使用 checkpoints 进行故障恢复。
flink在算子的运行过程中当某算子失败时为了保证数据的正确性,通过检查点实现。当出现异常后,Flink 就可以根据最近的一次的快照数据将所有算子恢复到先前的状态(个人理解相当于spark的DAG概念)。
1:checkpoint :在flink中每次的状态存储通过快照实现进行记录,将算子的运行状态保存到checkpoint中,每一次快照就是一次checkpoint。默认的checkpoint在 JobManager 的内存中,但是为了保证程序重启时能够根据状态进行恢复数据,在生产上一般将checkpoint保存到其他系统中,比如hdfs,本地linux系统文件中。
关于checkpoint的一些配置
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 开启checkpoint,默认关闭。每 1000ms 开始一次 checkpoint
env.enableCheckpointing(1000);
// 高级选项:
// 设置模式为精确一次 (这是默认值)
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
// 确认 checkpoints 之间的时间会进行 500 ms
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
// Checkpoint 必须在一分钟内完成,否则就会被抛弃
env.getCheckpointConfig().setCheckpointTimeout(60000);
// 同一时间只允许一个 checkpoint 进行
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
// 开启在 job 中止后仍然保留的 externalized checkpoints
env.getCheckpointConfig().enableExternalizedCheckpoints(ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
// 允许在有更近 savepoint 时回退到 checkpoint
env.getCheckpointConfig().setPreferCheckpointForRecovery(true);
2:savepoint:保存点是流式作业执行状态的一致图像,通过 Flink 的检查点机制创建。您可以使用 Savepoints 来停止和恢复、分叉或更新您的 Flink 作业。
3:flink和kafka的checkpoint需要自行实现。
水印:Flink 中衡量事件时间进度的机制是watermarks。主要用于保证特定时间段(window窗口)的运行时机(启动或者关闭)
flink的时间:包括事件时间(event-time)和处理时间(processing-time)
事件时间:数据中自带的时间字段,可以利用事件时间定义水印,规定什么样情况触发水印进行处理。
处理时间:该数据的处理时间(操作算子的计算机系统时间)。
关于流处理中时间特性请阅读:详解流处理中的时间特性
窗口是将无界数据流转化为有界数据流按照期望的时间字段进行处理,使得数据有序。
窗口化只是获取数据源(无界或有界)并将其沿时间边界分割成有限块进行处理的简单概念。
下图显示了三种不同的窗口模式:
fixed无重叠;sliding滚动窗口;sessions会话窗口。
Process Function与DataStream API集成,使得可以根据需要使用低级抽象。该数据集API提供的有限数据集的其他原语,如循环/迭代。
3:table API是为中心的声明性DSL表,其可被动态地改变的表(表示流时)。该表API遵循(扩展)关系模型:表有一个模式连接(类似于在关系数据库中的表)和API提供可比的操作,如选择,项目,连接,分组依据,聚合等表API程序声明性地定义应该执行的逻辑操作, 而不是具体指定操作代码的外观。
可以在table和DataStream / DataSet之间无缝转换,允许程序将Table API与DataStream和 DataSet API 混合。
4:Flink 提供的最高级别抽象是SQL。这种抽象在语义和表达上都类似于Table API,但将程序表示为 SQL 查询表达式。在SQL抽象与表API SQL查询紧密地相互作用,并且可以在中定义的表执行 表API。
所有的flink程序运行都包括三部分。source加载数据;transformation数据转换;sink发送数据。
source可以从kafka,本地文件等方式,也可以自己构建DS和DT。
transformation算子:https://nightlies.apache.org/flink/flink-docs-release-1.14/zh/docs/dev/datastream/operators/overview/
这StreamExecutionEnvironment是所有 Flink 程序的基础(创建批处理请使用ExecutionEnvironment)。
您可以使用以下静态方法获得一个StreamExecutionEnvironment:
StreamExecutionEnvironment.
getExecutionEnvironment() //最常用的
createLocalEnvironment() //创建本地运行环境,多用于idea中调试
createRemoteEnvironment(String host, int port, String... jarFiles)
示例:
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream text = env.readTextFile("file:///path/to/file");
StreamExecutionEnvironment也可以设置运行环境的一些参数。
放在conf/flink-conf.yaml文件中的配置程序启动时会加载覆盖集群上的参数。
主要参数如下。
jobmanager.memory.process.size:所述的总大小JobManager(JobMaster / ResourceManager的/分派器)处理。
taskmanager.memory.process.size:TaskManager 进程的总大小。
taskmanager.numberOfTaskSlots:TaskManager 提供的槽数(默认值:1)
检查点相关配置:
您可以直接在 Flink 作业或应用程序中的代码中配置检查点。将这些值放在配置中将它们定义为默认值,以防应用程序未配置任何内容。
state.backend:要使用的状态后端。这定义了拍摄快照的数据结构机制。常见值为filesystem或rocksdb。
state.checkpoints.dir: 写入检查点的目录。这需要一个路径 URI,如s3://mybucket/flink-app/checkpoints或hdfs://namenode:port/flink/checkpoints。
state.savepoints.dir:保存点的默认目录。采用路径 URI,类似于state.checkpoints.dir.
execution.checkpointing.interval:基本间隔设置。要启用检查点,您需要将此值设置为大于 0。
完整参数见:运行参数配置
flink的源:源是您的程序从中读取其输入的地方
基于文件:
readTextFile(path)-TextInputFormat逐行读取文本文件,即遵守规范的文件,并将它们作为字符串返回。
readFile(fileInputFormat, path) - 按照指定的文件输入格式读取(一次)文件。
基于套接字:
socketTextStream- 从套接字读取。元素可以由分隔符分隔。
基于集合:
fromCollection(Collection)- 从 Java Java.util.Collection 创建数据流。集合中的所有元素必须属于同一类型。
fromCollection(Iterator, Class)- 从迭代器创建数据流。该类指定迭代器返回的元素的数据类型。
fromElements(T ...)- 从给定的对象序列创建数据流。所有对象必须属于同一类型。
fromParallelCollection(SplittableIterator, Class)- 从迭代器并行创建数据流。该类指定迭代器返回的元素的数据类型。
generateSequence(from, to) - 并行生成给定间隔内的数字序列。
addSource- 附加一个新的源函数。例如,要从 Apache Kafka 读取数据,您可以使用 addSource(new FlinkKafkaConsumer<>(…)). 。
详见:https://nightlies.apache.org/flink/flink-docs-release-1.14/docs/connectors/datastream/overview/
transformation算子:https://nightlies.apache.org/flink/flink-docs-release-1.14/zh/docs/dev/datastream/operators/overview/
转换操作:如map,flarMap,filter等
dataStream.map(new MapFunction<Integer, Integer>() {
@Override
public Integer map(Integer value) throws Exception {
return 2 * value;
}
});
dataStream.keyBy(<key selector>)
.window(SlidingEventTimeWindows.of(Time.seconds(10), Time.seconds(5)))
.<windowed transformation>(<window function>);
对多个流dataStream进行处理关联操作
stream.join(otherStream)
对状态和定时器的一些操作必须使用ProcessFunction。比如统计定时器时间内的流量,数据条数等。
stream.keyBy(...).process(new MyProcessFunction());
数据接收器使用数据流并将它们转发到文件、套接字、外部系统或打印它们。Flink 内置了多种输出格式,封装在 DataStreams 上的操作后面:
writeAsText()/ TextOutputFormat- 将元素逐行写入为字符串。通过调用每个元素的toString()方法获得字符串。
writeAsCsv(...)/ CsvOutputFormat- 将元组写入逗号分隔值文件。行和字段分隔符是可配置的。每个字段的值来自对象的toString()方法。
print()/ printToErr() -在标准输出/标准错误流上打印每个元素的toString()值。可选地,可以提供前缀(msg),它被添加到输出中。这有助于区分对print 的不同调用。如果并行度大于 1,则输出也将带有产生输出的任务的标识符。
writeUsingOutputFormat()/ FileOutputFormat- 自定义文件输出的方法和基类。支持自定义对象到字节的转换。
writeToSocket - 根据 a 将元素写入套接字 SerializationSchema
addSink- 调用自定义接收器功能。Flink 捆绑了连接到其他系统(例如 Apache Kafka,自定义到hbase,hive等等地方)的连接器,这些连接器被实现为接收器功能。
flink处理流或者批数据。默认是流处理默认,配置批处理方式如下。
flink1.12.0版本后执行模式可以通过 execute.runtime-mode 设置来配置。有三种可选的值:
STREAMING: 经典 DataStream 执行模式(默认)
BATCH: 在 DataStream API 上进行批量式执行
AUTOMATIC: 让系统根据数据源的边界性来决定
指定方式1::这可以通过 bin/flink run … 的命令行参数进行配置
下面是如何通过启动命令行配置执行模式:
bin/flink run -Dexecution.runtime-mode=BATCH examples/streaming/WordCount.jar
这个例子展示了如何在代码中配置执行模式:
指定方式2:创建/配置 StreamExecutionEnvironment 时写进程序。
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setRuntimeMode(RuntimeExecutionMode.BATCH);
flink对数据进行处理的过程中,每一次处理(如窗口操作)都会有执行状态,可以获取执行的状态,以便于进行数据一致化处理(checkpoint等保存,以便于数据恢复)。
flink自身的checkpoint是默认关闭的,通常和kafka结合时,会利用kafka的checkpoint进行数据恢复。
DataStream 程序是对数据流进行转换(例如过滤、更新状态、定义窗口、聚合)的常规程序。
在用法上DataStream类似于常规 Java Collection,但在某些关键方面却大不相同。它们是不可变的,这意味着一旦它们被创建,你就不能添加或删除元素。您也不能简单地检查内部元素,而只能使用DataStreamAPI 操作(也称为转换)处理它们
DataStream 的转换操作
map():对每个元素进行操作
FlatMap():取一个元素并产生零个、一个或多个元素
filter():过滤操作。为每个元素计算一个布尔函数,并保留那些函数返回 true
Reduce():键控数据流上的“滚动”减少。
Window():窗口操作:可以设置窗口的时间大小,从而对窗口期内的数据进行操作,比如窗口期内数据进行排序等
brodcast:广播元素到每个分区
Flink 支持两种关系型的 API,Table API 和 SQL。这两个 API 都是批处理和流处理统一的 API,这意味着在无边界的实时数据流和有边界的历史记录数据流上,关系型 API 会以相同的语义执行查询,并产生相同的结果。Table API 和 SQL 借助了 Apache Calcite 来进行查询的解析,校验以及优化。它们可以与 DataStream 和 DataSet API 无缝集成,并支持用户自定义的标量函数,聚合函数以及表值函数。
利用该API可以实现对HIVE等数据库的操作。
maven依赖
org.apache.flink
flink-table-api-java-bridge_2.11
1.14.2
provided
构建TableEnvironment demo
EnvironmentSettings build = EnvironmentSettings.newInstance().inStreamingMode().build();
TableEnvironment tableEnvironment = TableEnvironment.create(build);
Flink 运行时由两种类型的进程组成:一个 JobManager 和一个或者多个 TaskManager。
Client 不是运行时和程序执行的一部分,而是用于准备数据流并将其发送给 JobManager。之后,客户端可以断开连接(分离模式),或保持连接来接收进程报告(附加模式)。客户端可以作为触发执行 Java/Scala 程序的一部分运行,也可以在命令行进程./bin/flink run …中运行。
Flink 应用程序的作业可以被提交到长期运行的 Flink Session 集群、专用的 Flink Job 集群 或 Flink Application 集群。这些选项之间的差异主要与集群的生命周期和资源隔离保证有关。
集群生命周期:在 Flink Session 集群中,客户端连接到一个预先存在的、长期运行的集群,该集群可以接受多个作业提交。即使所有作业完成后,集群(和 JobManager)仍将继续运行直到手动停止 session 为止。因此,Flink Session 集群的寿命不受任何 Flink 作业寿命的约束。
资源隔离:TaskManager slot 由 ResourceManager 在提交作业时分配,并在作业完成时释放。由于所有作业都共享同一集群,因此在集群资源方面存在一些竞争 — 例如提交工作阶段的网络带宽。此共享设置的局限性在于,如果 TaskManager 崩溃,则在此 TaskManager 上运行 task 的所有作业都将失败;类似的,如果 JobManager 上发生一些致命错误,它将影响集群中正在运行的所有作业。
集群生命周期:在 Flink Job 集群中,可用的集群管理器(例如 YARN)用于为每个提交的作业启动一个集群,并且该集群仅可用于该作业。在这里,客户端首先从集群管理器请求资源启动 JobManager,然后将作业提交给在这个进程中运行的 Dispatcher。然后根据作业的资源请求惰性的分配 TaskManager。一旦作业完成,Flink Job 集群将被拆除。
资源隔离:JobManager 中的致命错误仅影响在 Flink Job 集群中运行的一个作业。
集群生命周期:Flink Application 集群是专用的 Flink 集群,仅从 Flink 应用程序执行作业,并且 main()方法在集群上而不是客户端上运行。提交作业是一个单步骤过程:无需先启动 Flink 集群,然后将作业提交到现有的 session 集群;相反,将应用程序逻辑和依赖打包成一个可执行的作业 JAR 中,并且集群入口(ApplicationClusterEntryPoint)负责调用 main()方法来提取 JobGraph。例如,这允许你像在 Kubernetes 上部署任何其他应用程序一样部署 Flink 应用程序。因此,Flink Application 集群的寿命与 Flink 应用程序的寿命有关。
资源隔离:在 Flink Application 集群中,ResourceManager 和 Dispatcher 作用于单个的 Flink 应用程序,相比于 Flink Session 集群,它提供了更好的隔离。