Flink介绍

Flink目前属于Apache基金会的顶级项目,它一个分布式计算框架,主要应用场景包括:流式处理和批处理。流式处理可以应用在实时数据分析, 比如:统计电商网站流量,实时交通状况,银行收支等。批处理可应用在机器学习、深度学习等建模领域。Flink在流式处理上于兼容了更多类型的数据以及第三方插件,Flink在批处理上设计了算法和数据结构在内部进行了优化,计算效率较优。

使用Flink有哪些先决条件?
您需要Java 8来运行Flink作业/应用程序。
Scala API(可选)依赖于Scala 2.11。
Apache ZooKeeper需要高度可用且没有单点故障的设置。
对于可以从故障中恢复的高可用流处理设置,Flink需要某种形式的分布式存储用于检查点(HDFS / S3 / NFS / SAN / GFS / Kosmos / Ceph / …)。

Flink如何与Hadoop堆栈相关?
Flink独立于Apache Hadoop,并且在没有任何Hadoop依赖性的情况下运行。
但是,Flink与许多Hadoop组件集成得非常好,例如HDFS , YARN或HBase 。 与这些组件一起运行时,Flink可以使用HDFS读取数据,或写入结果和检查点/快照。 Flink可以通过YARN轻松部署,并与YARN和HDFS Kerberos安全模块集成。

Flink支持多大的规模?
用户在非常小的设置(少于5个节点)和1000个节点以及状态的TB上运行Flink作业。

SparkStream&Storm

SparkStream:
不得不说,Spark是一个非常优秀的分布式计算框架,社区热度较高,不仅支持Sql开发。还能很好的兼容Hive,提供了很多很强大的算子,并在架构设计上也在不断优化Shuffer的执行效率。同时在机器学习领域,提供了诸如:线性回归、朴素贝叶斯、聚类、协同过滤等优秀算法框架,但SparkStream并不能达到流式处理的标准,在数据处理上有一定延迟,从一定程度上抑制了Spark的成长之路,这本身是由于Spark架构设计导致。

Storm:
Storm中文直译叫做”风暴”,它是开源的分布式实时计算框架,Storm的Ack机制能对异常Tuple进行重试,但这可能会导致重试失败,所以Storm提供了一致性事务来保证数据有且仅被处理一次,对于金融等特殊领域极其关键,当然storm还有一个隐含的功能:由于Storm的处理组件是分布式的,而且处理延迟极低,所以可以作为一个通用的分布式RPC框架来使用。Storm能达到实时计算的原因,得益于Storm在设计上对数据只做了简单的处理,由于计算能力过于简单,Storm无法提供像Spark一样强大的算子能力。

Flink 特性:
1、 状态计算的exactly-once语义
流程序可以在计算过程中维护自定义状态。

2、高度灵活的流失窗口
Flink支持在时间窗口,统计窗口,session窗口,以及数据驱动的窗口。

3、流处理和批处理共用一个引擎
它能够基于同一个Flink Runtime,提供支持流处理和批处理两种类型应用的功能。

4、Flink具有迭代计算的专门支持(比如在机器学习和图计算中)。
增量迭代可以利用依赖计算来更快地收敛。

5、 程序调优
批处理程序会自动地优化一些场景,比如避免一些昂贵的操作(如shuffles和sorts),还有缓存一些中间数据。

Flink Timer

flink 需要掌握hadoop吗 flink用来做什么_Time

Event Time:
进入producer时间,一般由数据源产生,事件时间是每个事件在其生产设备上发生的时间。
Ingestion Time:
1. 摄取时间是事件进入Flink的时间。 在源操作员处,每个记录将源的当前时间作为时间戳,并且基于时间的操作(如时间窗口)引用该时间戳。
2. 在内部, 摄取时间与事件时间非常相似,但具有自动时间戳分配和自动水印生成功能。
Window ProcessIng Time
1. 处理时间是指执行相应操作的机器的系统时间。
2. 处理时间是最简单的时间概念,不需要流和机器之间的协调。 它提供最佳性能和最低延迟。 但是,在分布式和异步环境中,处理时间不提供确定性,因为它容易受到记录到达系统的速度(例如从消息队列)到记录在系统内的操作员之间流动的速度的影响。和停电(预定或其他)。
3. 处理时间有可能各自系统时间不协调的问题

Flink Window

窗口的生命周期:
简而言之,只要应该属于此窗口的第一个元素到达,就会创建一个窗口,当时间(事件或处理时间)超过其结束时间戳加上用户指定的allowed lateness时,窗口将被完全删除 。 Flink保证仅删除基于时间的窗口而不是其他类型, 例如全局窗口(请参阅窗口分配器 )。 例如,使用基于事件时间的窗口策略,每5分钟创建一个不重叠(或翻滚)的窗口并允许延迟1分钟,Flink将为12:00到12:05之间的间隔创建一个新窗口12:05当具有落入该间隔的时间戳的第一个元素到达时,当水印通过12:06时间戳时它将删除它。
此外,每个窗口都有一个Trigger (参见触发器 )和一个附加到它的函数( ProcessWindowFunction , ReduceFunction , AggregateFunction或FoldFunction )(请参阅窗口函数 )。 该函数将包含要应用于窗口内容的计算,而Trigger指定窗口被认为准备好应用该函数的条件。 触发策略可能类似于“当窗口中的元素数量大于4”时,或“当水印通过窗口结束时”。 触发器还可以决定在创建和删除之间的任何时间清除窗口的内容。 在这种情况下,清除仅涉及窗口中的元素,而不是窗口元数据。 这意味着仍然可以将新数据添加到该窗口。
除上述内容外,您还可以指定一个Evictor (参见Evictors ),它可以在触发器触发后以及应用函数之前和/或之后从窗口中删除元素。

flink 需要掌握hadoop吗 flink用来做什么_Time_02


滚动窗口:按照间隔时间设定窗口,比如:每隔五分钟创建一个新的窗口,数据不会重复

滑动窗口:按照间隔时间和滑动时间设定,比如:每5s滑动一次,每次获取10s数据,数据可能重复

全局窗口:全局窗口分配器将具有相同键的所有元素分配给同一个全局窗口 。 此窗口方案仅在指定了自定义触发器时才有用。 否则,将不执行任何计算,因为全局窗口没有我们可以处理聚合元素的自然结束。

flink 需要掌握hadoop吗 flink用来做什么_时间戳_03

val input : DataStream [ T ] = 
 ... input . keyBy (< key selector >) . window ( 
 GlobalWindows . create ()) .< windowed transformation >(< window function >)

会话窗口:会话窗口分配器按活动会话对元素进行分组。 与翻滚窗口和滑动窗口相比,会话窗口不重叠并且没有固定的开始和结束时间。 相反,当会话窗口在一段时间内没有接收到元素时, 即当发生不活动的间隙时,会关闭会话窗口。 会话窗口分配器可以配置静态会话间隙或会话间隙提取器功能,该功能定义不活动时间段的长度。 当此期限到期时,当前会话将关闭,后续元素将分配给新的会话窗口。

flink 需要掌握hadoop吗 flink用来做什么_时间戳_04

public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
         DataStream<Tuple2<String, Integer>> dataStream = env.socketTextStream("localhost", 9999)
                .flatMap(new SessionWindow.Splitter())
                .keyBy(0)
                 //处理时间
                .window(ProcessingTimeSessionWindows.withGap(Time.seconds(10)))
                .reduce(new ReduceFunction<Tuple2<String, Integer>>() {
                    public Tuple2<String, Integer> reduce(Tuple2<String, Integer> value1, Tuple2<String, Integer> value2) throws Exception {
                        System.out.println(value1.f1 + value2.f1);
                        return new Tuple2<String, Integer>(value1.f0, value1.f1 + value2.f1);
                    }
                });
        dataStream.print();
        env.execute("SessionWindowWc WordCount");
    }

    public static class Splitter implements FlatMapFunction<String, Tuple2<String, Integer>> {
        public void flatMap(String sentence, Collector<Tuple2<String, Integer>> out) throws Exception {
            for (String word : sentence.split(" ")) {
                System.out.println(word);
                out.collect(new Tuple2<String, Integer>(word, 1));
            }
        }
    }

Flink 触发器:

确定何时窗口功能准备好处理窗口(由窗口分配器形成)。每个都有默认值。如果默认触发器不符合需要,可以使用指定自定义触发器。WindowAssignerTriggertrigger(…)
触发器界面有五种方法可以Trigger对不同的事件做出反应:
onElement():为添加到窗口的每个元素调用该方法。 适用于统计聚合
onEventTime():在注册的事件时间计时器触发时调用该方法。基于时间的触发函数,适用于时间聚合
onProcessingTime():在注册的处理时间计时器触发时调用该方法。基于时间的触发函,适用于时间聚合
该onMerge()方法与状态触发器相关,并且当它们的相应窗口合并时合并两个触发器的状态,例如当使用会话窗口时。
最后,该clear()方法在移除相应窗口时执行所需的任何动作 相当于flatMap操作

public abstract TriggerResult onElement(T element, long timestamp, W
window, TriggerContext ctx) throws Exception;

 public abstract TriggerResult onProcessingTime(long time, W window,
 TriggerContext ctx) throws Exception;

 public abstract TriggerResult onEventTime(long time, W window,
 TriggerContext ctx) throws Exception;

 public void onMerge(W window, OnMergeContext ctx) throws Exception {
    throw new UnsupportedOperationException("This trigger does not
 support merging."); }

 public abstract void clear(W window, TriggerContext ctx) throws
 Exception;

onElement、onEventTime、onProcessingTime 此方法均反馈TriggerResult对象,TriggerResult有四个状态:CONTINUE(不做任何事),FIRE(触发),PURGE(消除窗口元素),FIRE_AND_PURGE(触发&清除窗口元素)
注意:清除将简单地删除窗口的内容,并将保留有关窗口和任何触发状态的任何潜在元信息(没明白,留后续研究)

Flink 驱逐器:

Flink Water:

注意:此部分与在事件时间运行的程序相关。

  1. 为了处理事件时间 ,Flink需要知道事件的时间戳 ,这意味着流中的每个元素都需要分配其事件时间戳。 这通常通过从元素中的某个字段访问/提取时间戳来完成。时间戳分配与生成水印密切相关,水印告诉系统事件时间的进展。
  2. 有两种方法可以分配时间戳并生成水印:
    a) 直接在数据流源中
    b) 通过时间戳分配器/水印生成器:在Flink中,时间戳分配器还定义要发出的水印

代码示例:

public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);
        DataStream<Tuple2<String, Integer>> dataStream = env
                .socketTextStream("localhost", 9999)
                .flatMap(new Splitter())
                //理论上可以在任何一个transform设定
                .assignTimestampsAndWatermarks(
                        new AscendingTimestampExtractor<Tuple2<String, Integer>>() {
                            @Override
                            public long extractAscendingTimestamp(Tuple2<String, Integer> element) {
                                System.out.println(element.f0);
                                return Long.parseLong(element.f0);
                            }
                        })
                .keyBy(0)
                .window(TumblingEventTimeWindows.of(Time.seconds(10)))//event window
                .allowedLateness(Time.seconds(5))//allow later
                .sum(1);
        dataStream.print();

        env.execute("LaterWaterWc WordCount");
    }
    public static class Splitter implements FlatMapFunction<String, Tuple2<String, Integer>> {

        public void flatMap(String sentence, Collector<Tuple2<String, Integer>> out) throws Exception {
            for (String word : sentence.split(" ")) {
                out.collect(new Tuple2<String, Integer>(word, 1));
            }
        }
    }