概念
Flink 中的 DataStream 程序是对数据流进行转换(例如过滤、更新状态、定义窗口、聚合)的常规程序。数据流最初是从各种来源(例如,消息队列、套接字流、文件)创建的。结果通过接收器返回,例如可以将数据写入文件或标准输出(例如命令行终端)。Flink 程序可以在各种上下文中运行,可以独立运行,也可以嵌入到其他程序中。执行可以在本地 JVM 中发生,也可以在许多机器的集群上发生。
DataStream API 既可以处理无解流数据, 也可以处理有界的批量数据. 意思是既支持流处理,也支持离线的批处理.
说明
- ExecutionEnvironment.getExecutionEnvironment() :返回DataSet 对象 对应 DataSet api
- StreamExecutionEnvironment.getExecutionEnvironment():返回DataStream对象 对应DataStream api DataSet api和 DataStream 都可以处理无解和有界流数据,具体提供的一些transform方法上有些区别,但是核心逻辑大同小异,值得说的是,在以后的版本中DataSet api会被抛弃。 官网建议用Table api完全替代DataSet api.
一. 构建flink程序的一般步骤
1.获得一个execution environment,flin提供了两个类,类中有一些必要的静态方法。
你的flink程序可能是再idea上运行,也可能打jar包在集群上运行, 也可以指定已经存在的flink集群(指定host
port),在本地远程将你的程序通过socket传输到指定的集群上运行. 获取执行环境flink提供了几个静态方法:val env = ExecutionEnvironment.getExecutionEnvironment() val env = ExecutionEnvironment.createLocalEnvironment() val env = ExecutionEnvironment.createRemoteEnvironment(host: String, port: Int, jarFiles: String*)
2.加载/创建初始数据(source源构建)
添加数据源,此数据源可以来自任何地方,比如mysql,kafka,socket,或者本地文件,或者是hive等的. 例子:val
text = env.readTextFile(“/demo/a.txt”)
3.指定对此数据的转换
调用flink算子对数据源进行transform转换,所谓的算子就是map,flatMap等等
4.指定将计算结果放在哪里,
一旦你有一个包含最终结果的 DataStream,你可以通过创建一个接收器将它写入外部系统。
例子:writeAsText(path: String)
5.触发程序执行
将程序提交,开始运行程序 env.execute(“my flink job name”)
execute支持传入一个job name,此值是自定义,如果不传入,flink会自动生成一个job名字.
一个job就表示一个提交的任务.
二. flink source构建
source也就是流入flink程序的数据源, flink的source从大分类可以分为两种
A. 用户自定义source需要实现下面接口的任意一个
i.SourceFunction 此接口并行度为1
ii.ParallelSourceFunction 此接口并行度为多个
iii.RichParallelSourceFunction 此接口并行度为多个如何自定义source,本篇文章暂不涉及.
B. flink内部sourcei. 基于文件
ii. 基于socket
ii. 基于集合
iii: 基于已经实现的内部连接器,可以通过连接器连接到数据源,常见的连接器mysql, kafka 等.
2.1 flink内部source之基于文件
readTextFile(path):
Reads text files, i.e. files that respect the TextInputFormat
specification, line-by-line and returns them as Strings.
readFile(fileInputFormat, path) :
Reads (once) files as dictated by the specified file input format.
readFile(fileInputFormat, path, watchType, interval, pathFilter):
如果watchType设置为FileProcessingMode.PROCESS_CONTINUOUSLY,则在修改文件时,将完全重新处理其内容。这可能会破坏“exactly-once”语义,因为在文件末尾附加数据将导致其所有内容被重新处理。
如果watchType设置为FileProcessingMode.PROCESS_ONCE,当文件内容发生变化时,只会将变化的数据读取至Flink,在PROCESS_once模式下,可以保证数据Excatly Once级别的一致性保证
fileInputFormat 是用户自定义的文件输入格式,具体怎么实现这里暂且不说.
2.2 flink内部source之基于socket
val text = env.socketTextStream(“localhost”, 9999)
2.3 flink内部source之基于集合
fromCollection(Collection)
- Creates a data stream from the Java Java.util.Collection. All elements in the collection must be of the same type.
fromCollection(Iterator, Class)
- Creates a data stream from an iterator. The class specifies the data type of the elements returned by the iterator.
fromElements(T …)
- Creates a data stream from the given sequence of objects. All objects must be of the same type.
fromParallelCollection(SplittableIterator, Class)
- Creates a data stream from an iterator, in parallel. The class specifies the data type of the elements returned by the iterator.
generateSequence(from, to)
- Generates the sequence of numbers in the given interval, in parallel.
2.3 flink内部source之基于flink提供的连接器
Attach a new source function. For example, to read from Apache Kafka you can use addSource(new FlinkKafkaConsumer<>(…)). See connectors for more details.
连接器后面会单独出一章来说,这里先不说.简单来说连接器就是flink提供的访问外部存储空间的api, 访问到数据之后,基于访问到的数据构建数据流source
3.flink transform
transform就是转换算子,对数据元素进行解析,聚合,分组,过滤等,详情见:operators
4. flink sink
sink就是对输出结果落地. sink常见的方法就是write*(), 以及addSink(…),这里需要注意的是:write*()系列方法发主要用于调试目的。它们不参与 Flink 的检查点,这意味着这些函数通常具有 at-least-once 语义。这意味着并非所有发送到 OutputFormat 的元素都会立即显示在目标系统中。此外,在失败的情况下,这些记录可能会丢失。
要将流可靠地一次性交付到文件系统中,请使用StreamingFileSink. 此外,通过该.addSink(…)方法的自定义实现可以参与 Flink 的检查点,以获得完全一次语义.