什么是Apache Flink实时流计算框架?

一.概述

  Apache Flink 是一个框架和分布式处理引擎,用于对无限制和有限制的数据流进行有状态的计算。Flink被设计为可以在所有常见的集群环境中运行,以内存速度和任何规模的计算。

  

  首先,需要对什么是无限制什么是有限制做一下说明,首先看官方的解释:

  1、无限制数据流

    无限制数据流指数据是没有界限的,其有一个起点,但是定义终点。它们不会终止并在生成数据时提供数据。无限制的流必须被连续处理,即事件被摄取后必须立即处理。无法等待所有输入数据的到达【因为可能永远也没有所有这一说】。处理无限制的数据通常要求以特定顺序【例如事件发生的顺序】提取事件,以便能够推断出结果的完整性。

  2、有限制数据流

    有限制数据流指具有定义的开始和结束。可以通过在执行任何计算之前提取所有数据来处理有限制数据流。由于有限制数据流始终可以排序,因此不需要有序摄取即可处理有限制数据流,此时,也称为批处理。

  说完了官方的解释,来说说我自己的看法,有不对的地方大家多多指正,所谓有限制数据流和无限制数据流,就拿时间为条件进行分析,区别说白了就是数据生成的持续时间,在一定时间内能得到全部数据的就是有限制数据流也称一批数据,而数据随着某些条件一直延续生成,而这些条件又是无止境的【例如:时间,空间等】,那就是无限制数据流。当然数据是否有限制还是认为定义的,就拿时间来说,指定时间段的就是有限制数据流【比如定时统计每天网站的访问量】,而累计从网站上线到现在的实时访问量就是无限制数据流,因为未来就是现在!

  其实某些数据是不是有限制的对Flink来说其实区别不大,Flink擅长处理无限制和有限制的数据集【主要还是无限制的,就是常说的流计算,其在批处理上比其它大数据计算框架例如Spark来说,并没有多少优势,反而在于机器学习、图计算等方面存在劣势】,对时间和状态的准确控制使Flink的运行能够在无限制的流上运行任何类型的应用程序。有限制数据流由专门为固定大小的数据集设计的算法和数据结构在内部进行处理,从而产生出色的性能。

  部署的方便性

    Flink是一个分布式系统,需要计算资源才能执行应用程序,Flink可以与所有常见的集群资源管理器【如YARN、Mesos、Kubernate等】进行集成,这样允许Flink以其常用的方式与每个资源管理器进行交互。也可以设置为独立集群运行。

    部署Flink应用程序时,Flink会根据应用程序配置的并行性自动识别所需要的资源,并向资源管理器请求它们。如果发生故障,Flink会通过请求新资源来替换发生故障的容器。提交或控制应用程序的所有通信均通过REST调用进行,这简化了Flink在许多环境中的集成。

  运行任意规模应用程序

    Flink旨在运行任何规模的有状态应用程序。将应用程序并行化为可能在集群上分布式并行执行的数千个任务。因此,应用程序几乎可以利用无限数量的CPU、内存、磁盘和网络IO。而且,Flink易于维护非常大的应用程序状态。它的异步和增量检查点算法可确保对处理延迟的影响达到最小,同时可保证一次状态一致性。

  内存优先

    有状态Flink应用程序针对本地状态进行优化。任务始终保持在内存中,或者如果状态大小超过可用内存,则始终保持在访问有效的磁盘数据结构中。因此,任务通过访问通常处于内存中的状态来执行所有计算,从而产生非常低的处理延迟。Flink通过定期将本地状态异步同步到指定持久存储来确保出现故障时一次准确的状态一致性。

    

二.应用场景

  Flink是用于无限制和有限制数据流上的有状态计算框架。其在不同的抽象级别上提供了多个API,并为常见用例提供了专门的库。

  一.流应用程序的构建块

    流处理框架可以构建和执行的应用程序的类型由框架控制流、状态和时间的能力定义。

  二.流的特点和分类

    显然,流是流处理的基本内容。但是,流可能具有不同的特性,这些特性会影响流的处理方式。Flink是一个通用的处理框架,可以处理任何类型的流。

    >有限制和无限制数据流【上面已经详细描述,此处不再赘述】

    >实时流和记录流【区别为是否在数据产生时就开始处理,立即或经过类似Kafka暂存处理的为实时流,先存储到持久存储器以待以后处理的为记录流】

  三.状态

    每个存在多个事件的流应用程序都是有状态的,即,仅对单个事件应用转换的应用程序不需要状态。任何运行基本业务逻辑的应用程序都需要记住事件或中间结果,以便在以后的某个时间点访问它们,例如在下一个事件时或在特定的持续时间后。

    

    应用程序状态是Flink中的一等公民。通过查看Flink在状态处理上下文中提供的所有功能,可以看到这一点。

    1.多个状态基元

      Flink为不同的数据结构【例如:原子值、列表或映射】提供状态基元。开发人员可以根据功能的访问模式选择最有效的状态原语。

    2.可插拔状态后端

      在可插拔状态后端中管理应用程序状态并对其进行检查。Flink具有不同的状态后端,这些后端将状态存储在内存或RocksDB【高效的嵌入式磁盘数据存储】中。自定义状态后端也可以插入。

    3.一次精确的状态一致性

      Flink的检查点和恢复算法可确保发生故障时应用程序状态的一致性。因此,可以透明地处理故障,并且不会影响应用程序的正确性。

    4.支持大状态

      Flink由于具有异步和增量检查点算法,因此能够保持大小为TB的应用程序状态。

    5.可扩展的应用程序

      Flink通过将状态重新分配给更多或更少的工作程序来支持有状态应用程序的扩展。

  四.时间

    时间是流应用程序的另一个重要组成部分。大多数时间流具有固定的时间语义,因为每个事件都是在特定的时间点产生的。此外,许多常见的流计算都是基于时间的,例如窗口聚合、会话、模式检测和基于时间的连接。流处理的一个重要方面是应用程序如何测量时间,即事件时间与处理时间之差。

    1.事件时间模式

      使用事件时间语义处理流的应用程序根据事件的时间戳计算结果。因此,无论是处理记录的事件还是实时事件,事件时间处理都可以提供准确一致的结果。

    2.水印支持

      Flink在事件时间应用程序中使用水印推理时间。水印还是权衡结果的延迟和完整性的灵活机制。

    3.后期数据处理

      在带有水印的事件时间模式下处理流时,可能会发生所有相关事件到达之前已经完成计算的情况。这种事件称为迟发事件。Flink具有多个选项来处理较晚的事件,例如通过侧面输出重新路由它们并更新先前完成的结果。

    4.处理时间模式

      除事件时间模式外,Flink还支持处理时间语义,该语义执行由处理机的挂钟时间触发计算。处理时间模式可能适合具有严格的低延迟要求的某些应用程序,这些应用程序可以忍受近似结果。

  五.分层API

    Flink提供了三层API。每个API针对不同的用例在简洁性和表达性之间提供了不同的权衡。

    

    1.ProcessFunctions

      ProcessFunctions是Flink提供的最具表现力的功能接口。Flink提供了ProcessFunctions来处理来自一个或两个输入流或分组在一个窗口中的单个事件。ProcessFunctions提供对时间和状态的细粒度控制。其可以任意修改其状态并注册计时器,这些计时器会触发回调函数。因此,ProcessFunctions可以根据许多有状态事件驱动的应用程序的需要实现复杂的业务逻辑。

      以下示例显示KeyedProcessFunction操作KeyedStream并匹配START和END事件。当一个事件被START接收,则该函数将记住其状态时间戳和寄存器在有效期为四个小时的计时器中。如果END在计时器触发之前收到事件,则该函数将计算END和START事件之间的持续时间,清除状态并返回值。否则,计时器将触发并清除状态。

 1 /**
 2  * Matches keyed START and END events and computes the difference between 
 3  * both elements' timestamps. The first String field is the key attribute, 
 4  * the second String attribute marks START and END events.
 5  */
 6 public static class StartEndDuration
 7     extends KeyedProcessFunction<String, Tuple2<String, String>, Tuple2<String, Long>> {
 8 
 9   private ValueState<Long> startTime;
10 
11   @Override
12   public void open(Configuration conf) {
13     // obtain state handle
14     startTime = getRuntimeContext()
15       .getState(new ValueStateDescriptor<Long>("startTime", Long.class));
16   }
17 
18   /** Called for each processed event. */
19   @Override
20   public void processElement(
21       Tuple2<String, String> in,
22       Context ctx,
23       Collector<Tuple2<String, Long>> out) throws Exception {
24 
25     switch (in.f1) {
26       case "START":
27         // set the start time if we receive a start event.
28         startTime.update(ctx.timestamp());
29         // register a timer in four hours from the start event.
30         ctx.timerService()
31           .registerEventTimeTimer(ctx.timestamp() + 4 * 60 * 60 * 1000);
32         break;
33       case "END":
34         // emit the duration between start and end event
35         Long sTime = startTime.value();
36         if (sTime != null) {
37           out.collect(Tuple2.of(in.f0, ctx.timestamp() - sTime));
38           // clear the state
39           startTime.clear();
40         }
41       default:
42         // do nothing
43     }
44   }
45 
46   /** Called when a timer fires. */
47   @Override
48   public void onTimer(
49       long timestamp,
50       OnTimerContext ctx,
51       Collector<Tuple2<String, Long>> out) {
52 
53     // Timeout interval exceeded. Cleaning up the state.
54     startTime.clear();
55   }
56 }

    2.DataStream API

      数据流API提供了许多常见的流处理操作的原语,比如窗口,记录在A-时间变换,并通过查询外部数据存储获取事件。数据流API可用于Java和Scala编程语言调用,如map()、reduce()和aggregate()。函数可以通过扩展接口定义,也可以定义为Java或Scala lambda函数。

      以下示例显示了如何对点击流进行会话并计算每个会话的点击次数。

 1 // a stream of website clicks
 2 DataStream<Click> clicks = ...
 3 
 4 DataStream<Tuple2<String, Long>> result = clicks
 5   // project clicks to userId and add a 1 for counting
 6   .map(
 7     // define function by implementing the MapFunction interface.
 8     new MapFunction<Click, Tuple2<String, Long>>() {
 9       @Override
10       public Tuple2<String, Long> map(Click click) {
11         return Tuple2.of(click.userId, 1L);
12       }
13     })
14   // key by userId (field 0)
15   .keyBy(0)
16   // define session window with 30 minute gap
17   .window(EventTimeSessionWindows.withGap(Time.minutes(30L)))
18   // count clicks per session. Define function as lambda function.
19   .reduce((a, b) -> Tuple2.of(a.f0, a.f1 + b.f1));

    3.SQL和表API

      Flink具有两个关系API,即Table API和SQL。这两个API都是用于批处理和流处理的统一API,即,对无界的实时流或有界的记录流都是以相同的语义执行的查询,并产生相同的结果。Table API和SQL利用Apache Calcite进行剖析,验证和查询优化。它们可以与DataStream、DataSet API无缝集成,并支持用户定义的标量,聚合和表值函数。Flink的关系API旨在简化数据分析,数据管道和ETL应用程序的定义。以下示例显示了SQL查询,以会话化点击流并计算每个会话的点击次数。

 1 SELECT userId, COUNT(*) 2 FROM clicks 3 GROUP BY SESSION(clicktime, INTERVAL '30' MINUTE), userId 

    4.库

      Flink具有几个常见数据处理用例的库。这些库通常嵌入在API中,并且不完全独立。因此,它们可以从API的所有功能中受益,并可以与其他库进行集成。

      4.1.复杂事件处理【CEP】

        模式检测是事件流处理中非常常见的用例。Flink的CEP库提供了一个API,用于指定事件的模式【考虑正则表达式或状态机】。CEP库与Flink的DataStream API集成在一起,因此可以在DataStreams上评估模型。CEP库的应用程序包括网络入侵检测,业务流程监视和欺诈检测。

      4.2.DataSet API

        DataSet API是Flink的批处理应用程序核心API。DataSet API的原语包括map,reduce,join【外连接】,cogroup和iterate。所有操作都由算法和数据结构支撑,这些算法和数据结构对内存中的序列化数据进行操作,如果数据大小超出内存大小,则溢出到磁盘。Flink的DataSet API的数据处理算法受传统数据库运算符的启发,例如混合哈希连接或外部合并排序。

      4.3.Gelly

        Gelly是用可伸缩图形处理和分析的库。Gelly在DataSet API之上实现并和它进行集成。因此,它得益于其可扩展且强大的库。Gelly具有内置算法,例如标签传播,三角形枚举和页面等级,但还提供了Graph API,可简化自定义图形算法的实现。

三.运行方式

  Apache Flink是用于无限制和有限制的数据流上的有状态计算的框架。由于许多流应用程序的设计目的是在最少的停机时间内连续运行,因此流处理框架必须提供出色的故障恢复能力,以及在运行时监视和维护应用程序的工具。Flink将重点放在流处理的操作上。下面将介绍Flink的故障恢复机制,以及其用来管理和监控的应用程序。

  一.不间断运行流计算应用程序7*24

    机器出现故障在分布式系统中是非常常见的。像Flink这样的分布式流处理框架必须从故障中恢复,才能保证7*24小时不间断运行。显然,这不仅意味着失败后重新启动应用程序,而且还确保其内部状态保持一致,从而使应用程序可以像没有发生过故障那样继续执行。Flink提供一些功能来确保应用程序继续运行并保持一致:

    1.一致的检查点

      Flink的恢复机制基于应用程序状态一致性的检查点。如果发生故障,将重新启动应用程序,并从最新的检查点加载其状态。与可重置的流数据源结合使用时,此功能可以保证一次状态一致性。

    2.高效的检查点

      如果应用程序的状态保持TB级,则对应用程序的状态进行检查会非常昂贵Flink可以执行异步和增量检查点,以使检查点对应用程序延迟SLA的影响很小。

    3.端到端精确一次

      Flink具有特定存储系统的事务接收器,即使在发生故障的情况下,也可以保证数据仅被精确 地写入一次。

    4.与集群管理器集成

      Flink与集群管理器紧密集成,例如Hadoop YARN,Mesos或Kubernates。当流程失败时,新流程将自动启动以接管其工作。

    5.高可用性设置

      Flink具有高可用性模式,可消除所有单点故障。HA模式基于Apache Zookeeper,这是一项经过实践检验的服务,可实现可靠的分布式协调服务。

  二.更新,迁移,暂停和恢复应用程序

    需要维护支持关键业务服务的流应用程序。需要修复错误,并需要改进或实现新功能。但是,更新有状态流应用程序并非易事。通常,一个人无法简单地停止应用程序并重新启动一个固定或改进版本,因为一个人无法承受失去应用程序状态的负担。

    Flink的保存点是一项独特而强大的功能,可以解决更新有状态应用程序的问题以及许多其他相关挑战。保存点是应用程序状态的一致快照,因此与检查点非常相似。但是,与检查点相比,保存点需要手动触发,并且在停止应用程序时不会自动将其删除。保存点可用于启动状态兼容的应用程序并初始化其状态。保存点启用一下功能:

    1.应用程序演化

      保存点可用于演化应用程序。可用从先前版本的应用程序中获取的保存点重新启动应用程序的固定版本或改进版本。也可以从较早的时间点启动应用程序【如果存在这样的保存点】,以修复有缺陷的版本产生的错误结果。

    2.集群迁移

      使用保存点,可以将应用程序迁移【或克隆】到不同的集群。

    3.Flink版本更新

      可以使用保存点迁移应用程序以在新的Flink版本上运行。

    4.应用程序缩放

      保存点可用于增加或减少应用程序的并行性。

    5.A/B测试和假设方案

      可以通过从同一保存点启动所有版本来比较应用程序的两个【或多个】不同版本的性能或质量。

    6.暂停或恢复

      可以通过保存一点并停止它来暂停应用程序。在以后的任何时间点,都可以从保存点恢复应用程序。

    7.归档

      可以将保存点归档,以便将应用程序的状态重置为较早的时间点。

  三.监视和控制应用程序

    就像任何其他服务一样,需要监视连续运行的流应用程序并将其集成到组织的操作基础架构【即监视和日志记录服务】中。监视有助于预测问题并提前做出反应。通过日志记录,可以进行根本原因分析以调查故障。最后,易于访问的界面是控制运行中的应用程序的重要功能。Flink与许多常用的日志记录和监视服务很好地集成在一起,并提供REST API来控制应用程序和查询信息。

    1.Web UI

     2.日志记录:整合slf4j,并与日志记录框架log4j或logback集成。

     3.指标:Flink具有完善的指标系统,可收集和报告系统和用户定义的指标。指标可以导出到多个报告器,包括JMX,Ganglia,Graphite,Prometheus,StatsD,Datadog和Slf4j。

     4.REST API:Flink公开REST API来提交新应用程序,获取正在运行的应用程序的保存点或取消应用程序。REST API还公布了正在运行或已完成的应用程序的元数据和收集的指标。 

posted @ 2019-12-31 10:45  云山之巅  阅读(1294)  评论(0编辑  收藏  举报