实时数仓大数据

Flink-双十一神话的基石

2019-11-14  本文已影响0人  SUSUR_28f6

2019年天猫双11再次刷新世界记录,订单创新峰值达到54.4万笔/秒,单日数据处理量达到970PB;支撑起这个双十一狂欢神话是阿里强悍的数据云上系统,这其中阿里的数据计算云引擎Blink功不可没,而Blink正是由Apache的顶级项目Flink经过"阿里化“而来;

四代计算引擎:

由此看出,计算引擎由批处理向流式处理发展,由一个组件干一个事向一个组件干全部事转变,一代代计算引擎的发展,追求的目标都是:更通用,更高效,更优雅,更易用的一栈式(集成批处理和流式处理)的计算引擎;

相较于Flink前三代计算引擎的区别与缺点:

Flink

Flink等诞生:

Flink源于柏林工业大学等一个研究性项目----StratoSphere;早期Flink是做批处理等,但是在2014年,StratoSphere里面的核心成员孵化出Flink,同年Flink捐给来Apache,后来成为Apache的顶级大数据项目,同时Flink将计算的主流方向定位为流处理;

Flink是什么:

Flink是一个低延迟,高吞吐、统一的大数据计算引擎;---- Stateful Computations over Data Streams,有状态的流式计算引擎。

Flink最区别于其他流计算引擎对就是statefule;即有状态计算 Flink提供流内置对对状态对一致性对处理,即如果任务发生流Failover,其状态不会丢失,不会被多算少算,同时提供流非常高对性能;

g8kh78syvr Flink01

Flink四大核心

数据流:有界流和无界流

Flink认为所有类型等数据都是作为事件流产生等,所有这些数据可以分为有界流和无界流:

图片1

Window

在流处理中,数据是连续不断的,因此我们不可能等到所有数据都到了才开始处理,当然我们可以每来一个消息就处理一次,但是有时我们需要做一些聚合类的处理,例如,在过去的一分钟内有多少用户点击类我们的网页;这种情况下,我们必须定义一个用来收集最近最近一分钟内的数据,并对这个窗口内的数据进行计算;

窗口可以是时间驱动(Time Window例如30秒),也可以是数据驱动的(Count Window),一种典型的窗口分类可以分成:防滚窗口(Tumbing Window,无重叠),滚动窗口(Sliding Window,有重叠),和会话窗口(Session Window,活动窗口);



Window

上图中raw data stream代表用户的购买行为流,圈中的数字代表该用户本次购买的商品个数,事件是按时间分布的,所以可以看出事件之间是有time gap的。Flink提供流上图中所有的窗口类型;

Time Window

Flink提出流三种时间概念,分别是event(事件时间:事件发生的时间)、ingestion time(摄取时间:时间进入流处理系统的时间)、processing time(处理时间:消息被计算处理的时间);Flink中窗口机制和时间类型是完全解耦的,也就是说当需要改变时间类型时不需要更改窗口逻辑相关的代码;

//Stream of(userId, buyCnt)
val buyCnts : DataStream[(Int, Int)] = ...

val tumblingCnts : DataStream[(Int, Int)] = buyCnts
//key stream by userId
.keyBy(0)
//tumbling time window of 1 minute length
// compute sum over buyCnt
.sum(1)
val slidingCnts : DataStream[Int, Int] = buyCnts.keyBuy(0)
// sliding time window of 1 minute length and 30 secs trigger interval
.timeWindow(Time.minutes(1), Time.seconds(30))
.sum(1)

Count Window

Count Window 是根据元素个数对数据流进行分组的

// Stream of (userId, buyCnts)
val buyCnts: DataStream[(Int, Int)] = ...

val tumblingCnts: DataStream[(Int, Int)] = buyCnts
//Key stream by sensorId
.keyBy(0)
// tumbling count window of 100 elements size
.countWindow(100)
// compute the buyCnt sum
.sum(1)

CountWindow也支持Silding Window,和Sliding Time window类似:

val slidingCnts: DataStream[(Int, Int)] = vehicleCnts
.keyBy(0)
// sliding count window of 100 elements size and 10 elements trigger interval
.countWindow(100, 10)
.sum(1)

Session Window

在这种用户交互事件流中,我们首先想到的是将事件聚合到会话窗口中(一段用户持续活跃的周期),由非活跃的间隙分隔开,如上图所示,就是需要计算每个用户在活跃期间总共购买的商品数量,如果用户30秒没有活动则视为会话断开(假设让raw data stream是单个用户的购买行为流):

// Stream of (userIdm, buyCnts)
val buyCnts: DataStream[(Int, Int)] = ...

val sessionCnts: DataStream[(Int, Int)] = vehicleCnts
.keyBy(0)
// session window based on a 30 seconds session gap interval
.window(ProcessingTimeSessionWindows.withGap(Time.seconds(30)))
.sum(1)

一般而言,window是在无限流上定义了一个有限元素集合,这个集合可以是基于时间的,元素的个数的,时间和个数结合的,会话间隙的,或者是自定义的;F林肯的DataStreamAPI提供了简洁的算子来满足常用的窗口操作,同时提供来通用的窗口机制来允许用户自己定义窗口分配逻辑;

Window API

得益于Flink Window API松耦合设计,我们可以非常灵活地定义符合特定业务的窗口,Flink中定义一个窗口主要需要三个组件:

WindowAssigner Trigger

上述的三个组件的不同实现组合,可以定义出非常复杂的窗口,Flink中内置的窗口也都是基于这三个组件构成的;

State(只有每一个单独的事件进行转换操作的应用才不需要state)

每一个具有一定复杂度对流处理应用都是又状态对,任何运行基本业务逻辑对流处理应用都需要在一定时间内存储所接收的事件或中间结果,以供后续的某个时间点进行访问并进行后续处理:

Exactly-once语义保证

Exactly-once语义是Flink的特性之一:是否以为这每一份到达FLink的数据,只会被处理一次;官网的描述如下

Exactly-once state consistency: Flink’s checkpointing and recovery algorithms guarantee the consistency of application state in case of a failure. Hence, failures are transparently handled and do not affect the correctness of an application.

Flink 的 checkpoint 和故障恢复算法保证了故障发生后应用状态的一致性。因此,Flink 能够在应用程序发生故障时,对应用程序透明,不造成正确性的影响。

可以看出,Exactly-once是为有状态的计算准备的

没有状态的算子系统,Flink无法也无需保障只被处理Exactly-once!在失败的情况下,无状态的opertor(map,filter等)只需要数据重新计算一遍即可,例如:

dataStream.filter(_.isInNYC)

当机器(节点)等失败时,只需从最近的一份快照开始,利用可重发的数据源重发一次数据即可,当数据经过filter算子时,全部重新算一次即可,根本不需要区分哪个数据被计算过,哪个数据没有被计算过,因为没有状态的算子只有输入和输出,没有状态可以保存;

此外Flink的Exactly-once需要从最近的一份快照开始重放数据,因此这也和数据源的能力有关,不是所有的数据源都可以提供Exactly-once语义的,以下是官网列出的数据源和Exactly-once语义保障能力列表

Source Guarantees Notes
Apache Kafka exactly once Use the appropriate Kafka connector for your version
RabbitMQ at most once(v0.10)/exactly once(v1.0)
Twitter Streaming API at most once
Collections exactly once
Files exactly once
Sockets exactly once

Flink对于mini-batch(Spark Streaming)的Exactly-once语义的优势

mini-batch的处理过程

也就是说Spark为了处理一个mini-batch,需要调度一个批处理动作,相比Flink延迟较大,spark的处理是秒级;

而Flink只需要启动一个流计算拓扑,处理持续不断的数据,Flink的处理延迟在毫秒级别,如果涉及到计算中的有多个网络shuffle,SparkStreaming和Flink之间的延迟插件会进一步拉大;

2.Exactly-once语义实现原理

Flink实现Exactly-once语义的原理与SparkStreaming是不一样的;

流处理在计算中既要保障高性能的同时又要保证容错是非常困难的,在批处理中,当作业失败时,可以容易地重新运行作业的失败部分来重新计算丢失的结果,这在批处理中是可行的,因为文件可以从头到尾重放,但是在流处理中却不能这样处理,数据流是无穷无尽的,没有开始和结束点,带有缓冲的数据流可以进行重放一小段数据,但是重最开始重放数据流是不切实际的(流处理作业可能以及运行流数月流);如果当前的流计算是有状态的,那就意味着除了输出之外没,系统还可以备份和恢复中间算子状态;

记录确认机制(Apache Storm)

mini-batch(Storm Trident,Spark Streaming):

容错流行架构的下一个发展阶段是微批处理或离散化流:为了解决连续计算模型所带来的级别同步的复杂性和开销,连续计算分解为一系列的原子性的批处理,每个batch都可能成功或失败,如果发生故障,重新计算最近的batch;基于微批处理可以实现Exactly-once、高吞吐,但是也有不足:

- 由于是batch,用户不能再任意时间而只能在checkpoint间隔的倍数上的窗口化数据;并且模型不支持许多应用程序所需的计数或会话窗口;

- 微批处理在下游操作比在划分批次的算子(通常指源)中花费更长的时间,则微批次将花费比配置更长的时间没,这导致越来越多的批次排队,或者导致微批量增加

- 微批处理相对于流式处理有更高的延迟,特别是在具有多个网络Shuffle的程序中,很容易将延迟时间延长到数秒;

事务更新(Google Cloud Dataflow):

在保留连续算子模型(低延迟,背压容错,可变状态)的优势同时又保证Exactly-Once的一种强大而优雅的方法,是原子性记录需要处理的数据并更新到状态中,失败后可以从日志中重新恢复状态以及需要处理的记录;

分布式快照(Flink)

分布式快照与事务更新相比,是将拓扑的状态作为一个整体进行快照,从而减少对分布式存储的写入和频率(确定当前流式计算所处的状态即正在处理中记录和算子状态),然后生成该状态的一致性快照,并将快照存储在持久化存储中;

Time

因为事件总是在特定对时间点发生,所以大多数对事件流拥有事件本身所固有对时间语义;进一步而言,许多常见对流计算都基于时间语义,例如:窗口聚合、会话计算、模式检测和基于时间的join;事件时间(event-time)和处理时间(procession-time)

上一篇下一篇

猜你喜欢

热点阅读