Flink 的DataStream程序四实现数据流转换的常规程序(例如L过滤, 更新状态,定义窗口,聚合).最初从各种源(例如,消息队列,套接字流,文件)创建数据流。结果通过接收器返回,接收器可以例如将数据写入文件或标准输出(例如命令行终端)。Flink程序可以在各种环境中运行,独立运行或嵌入其他程序中。执行可以在本地JVM中执行,也可以在许多计算机的集群上执行。
示例程序
一下程序是流窗口字数统计应用程序的完整工作示例,它在5秒窗口中对来自Web套接字的单词进行计数.可以复制代码在本地运行
package com.window;
import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;
public class WindowWordCount {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream> dataStream = env.socketTextStream("192.168.190.112", 9999)
.flatMap(new Splitter()).keyBy(0).timeWindow(Time.seconds(5)).sum(1);
dataStream.print();
// 启动项目
env.execute("window WordCount");
}
public static class Splitter implements FlatMapFunction>{
@Override
public void flatMap(String sentence, Collector> out) throws Exception {
for(String word:sentence.split(" ")){
out.collect(new Tuple2(word,1));
}
}
}
}
要运行示例程序,首先从终端使用netcat启动输入流
nc -lk 9999
只需键入一些单词就可以返回一个新的单词.这些将字数统计程序的输入.如果还要查看大于1的计数,请在5秒内反复键入相同的单词(如果无法快速输入,则将窗口大小5秒增加)
数据源
source是您的程序从中读取输入的位置.您可以使用将附加source附加到程序
StreamExecutionEnvironment.addSource(sourceFunction)
Flink附带了许多预先实现的source,但你可以通过实现Sourcefunction非并行source,或通过实现ParallelSourceFunction接口或扩展RichParallelSOurceFunction并行源来编写自己的自定义source
有几个预定义的流源可从以下位置访问StreamExecutionEnvironment:
基于文件的:
(1) readTextFile(path)-TextInputFormat逐行文本文件,即符合规范文件,并将它们作为字符串返回.
(2) readFile(fileInputFormat,path) 按指定的文件输入格式指定读取(一次)文件.
(3) readFile(fileInputFormat, path, watchType, interval, pathFilter, typeInfo) - 这是前两个内部调用的方法。它path根据给定的内容读取文件fileInputFormat。根据提供的内容watchType,此源可以定期监视(每intervalms)新数据(FileProcessingMode.PROCESS_CONTINUOUSLY)的路径,或者处理当前在路径中的数据并退出(FileProcessingMode.PROCESS_ONCE)。使用该pathFilter,用户可以进一步排除正在处理的文件。
实现:
在引擎盖下,Flink将文件读取过程分为两个子任务,即目录监控和数据读取。这些子任务中的每一个都由单独的实体实现。监视由单个非并行(并行性= 1)任务实现,而读取由并行运行的多个任务执行。后者的并行性等于工作并行性。单个监视任务的作用是扫描目录(定期或仅一次,具体取决于watchType),找到要处理的文件,将它们分成分割,并将这些拆分分配给下游读卡器。读者是那些将阅读实际数据的人。每个分割仅由一个读取器读取,而读取器可以逐个读取多个分割。
重要笔记:
1.如果watchType设置为FileProcessingMode.PROCESS_CONTINUOUSLY,则在修改文件时,将完全重新处理其内容.这可以打破”完全一次”的语义,因为在文件末尾追加数据将导致其所有内容重新处理.
2.如果watchType设置为FileProcessingMode.PROCESS_ONCE,则源扫描路径一次并退出,而不等待读者完成读取文件内容。当然读者将继续阅读,直到读取所有文件内容。在该点之后关闭源将导致不再有检查点。这可能会导致节点发生故障后恢复速度变慢,因为作业将从上一个检查点恢复读取。
socketTextStream : 从套接字读取.元素可以用分隔符分割
基于集合:
fromCollection(Collection) - 从Java Java.util.Collection创建数据流。集合中的所有元素必须属于同一类型。
fromCollection(Iterator, Class) - 从迭代器创建数据流。该类指定迭代器返回的元素的数据类型。
fromElements(T …) - 从给定的对象序列创建数据流。所有对象必须属于同一类型。
fromParallelCollection(SplittableIterator, Class) - 并行地从迭代器创建数据流。该类指定迭代器返回的元素的数据类型。
generateSequence(from, to) - 并行生成给定间隔中的数字序列
自定义:
addSource: 附加刑的source功能.例如,要从Apache Kafka中读取,您可以使用addSource(new FlinkKafkaConsumer<>())
数据接收
数据接收器使用DataStream并将它们转发到文件,套接字,外部系统或打印它们.Flink带有各种内置输出格式.这些格式封装在DataStreams上的操作后面;
要将流可靠,准确地一次传送到文件系统,请使用flink-connector-filesystem。此外,通过该.addSink(…)方法的自定义实现可以参与Flink的精确一次语义检查点。
迭代
迭代流程序实现步进功能将其嵌入到It而奥体veStream.由于DataStream程序可能永远不会完成,因此没有最大迭代次数/.相反你需要指定流的那个部分返回迭代,那个部分使用split转换或转发到下游filter.在这里,我们展示了使用过滤器的实例.首先,我们定义一个ItererativeStream
IterativeStream<Integer> iteration = input.iterate();
然后,我们使用一系列装换指定将在循环内执行的逻辑
DataStream<Integer> iterationBody = iteration.map(/*this is executed many times*/)
要关闭迭代并定义迭代尾部,请调用closeWith(feedbackStream)方法IterativeStream。赋予closeWith函数的DataStream 将反馈给迭代头。常见的模式是使用过滤器来分离反馈的流的部分和向前传播的流的部分。这些滤波器可以例如定义“终止”逻辑,其中允许元件向下游传播而不是反馈。
iteration.closeWith(iterationBody.filter(/*one part of the stream*/));
DataStream output = iterationBody.filter(/*some other part of the stream*/)
例如,这里是从一系列整数中连续减去1直到它们达到0的程序
package com.iter;
import org.apache.flink.api.common.functions.FilterFunction;
import org.apache.flink.api.common.functions.MapFunction;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.IterativeStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
public class ToZero {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream someIntegers = env.generateSequence(0,1000);
IterativeStream iteration = someIntegers.iterate();
DataStream minusOne = iteration.map(new MapFunction(){
@Override
public Long map(Long value) throws Exception {
return value - 1;
}
});
DataStream stillGreaterThanZero = minusOne.filter(new FilterFunction(){
@Override
public boolean filter(Long value) throws Exception {
// TODO Auto-generated method stub
return (value>0);
}
});
// iteration.closeWith(stillGreaterThanZero);
DataStream lessThanZero = minusOne.filter(new FilterFunction() {
@Override
public boolean filter(Long value) throws Exception {
return (value <= 0);
}
});
}
执行参数
该StreamExecutionEnvironment包含ExecutionConfig允许为运行时设置工作的具体配置值。
setAutoWatermarkInterval(long milliseconds):设置自动水印发射的间隔。您可以使用获取当前值long getAutoWatermarkInterval()
控制延迟
默认情况下,元素不会逐个传输到网络上(这会导致不必要的网络流量),但会被缓冲。可以在Flink配置文件中设置缓冲区的大小(实际在计算机之间传输)。虽然此方法适用于优化吞吐量,但当传入流速度不够快时,可能会导致延迟问题。要控制吞吐量和延迟,您可以env.setBufferTimeout(timeoutMillis)在执行环境(或单个运算符)上使用以设置缓冲区填充的最长等待时间。在此之后,即使缓冲区未满,也会自动发送缓冲区。此超时的默认值为100毫秒。
LocalStreamEnvironment env = StreamExecutionEnvironment.createLocalEnvironment();
env.setBufferTimeout(timeoutMillis);
env.generateSequence(1,10).map(new MyMapper()).setBufferTimeout(timeoutMillis);
为了最大化吞吐量,设置setBufferTimeout(-1)哪个将删除超时和缓冲区只有在它们已满时才会被刷新。要最小化延迟,请将超时设置为接近0的值(例如5或10 ms)。应避免缓冲区超时为0,因为它可能导致严重的性能下降。
数据数据源
Flink提供了特殊的数据源,这些数据源由Java集合支持,以方便测试。一旦程序经过测试,源和接收器可以很容易地被读取/写入外部系统的源和接收器替换。
集合数据源可以使用如下:
final StreamExecutionEnvironment env = StreamExecutionEnvironment.createLocalEnvironment();
// Create a DataStream from a list of elements
DataStream myInts = env.fromElements(1, 2, 3, 4, 5);
// Create a DataStream from any Java collection
List> data = ...
DataStream> myTuples = env.fromCollection(data);
// Create a DataStream from an Iterator
Iterator longIt = ...
DataStream myLongs = env.fromCollection(longIt, Long.class);
注意:目前,集合数据源要求实现数据类型和迭代器 Serializable。此外,收集数据源不能并行执行(并行度= 1)。
迭代数据接收器
Flink还提供了一个接收器,用于收集DataStream结果一进行测试和调试.他可以使用如下
斯卡拉
import org.apache.flink.streaming.experimental.DataStreamUtils
DataStream> myResult = ...
Iterator> myOutput = DataStreamUtils.collect(myResult)