flink 的一些概念以及 watermarks 水位线

批处理类似的hadoop spark 等这一批的数据的全部处理完才进行到下一个节点,中间处理的部分数据会被放到磁盘或内存cache

流处理如 storm flink(blink) sparkstreaming(严格意义来说不算,只是时间很小,mini-batch模拟流) 当前一个节点处理一条数据后,后一个节点接着就把数据给拉取进行处理,

而flink(blink) 可谓是集大成者,既能批处理又能流处理,流批合一,流批,流批,主要归功于flink采用了中比较灵活的方式,采用固定的缓存块来进行衡量是否进行流批,当缓存块超时值非常大时,为批处理,当缓存块超时值为0时可以为流处理,所以flink采用了折中的方式,通过用户控制缓存块的大小来进行处理,cache block,那么缓存块的大小呢?既然通过缓存块的超时值,那么缓存块的大小怎么确定呢?

flink中主要编程模型分为两中类型 datastream 和dataset分别对应与流 和批

DataSet<...> input = // [...]

DataSet<...> reduced = input

  .groupBy(/*define key here*/)

    .reduceGroup(/*do something*/);

扫描二维码关注公众号,回复: 5741820 查看本文章

    DataStream<...> input = // [...]

    DataStream<...> windowed = input

      .keyBy(/*define key here*/) //按照hash 分组

        .window(/*window specification*/);

dataset和datastream分别有不同的算子,需注意

flink 一般主要是on yarn有两种方式 一种是直接向yarn申请一块固定资源,太死板不灵活 yarn-session的方式

第二种,是提交flink job 的形式 推荐

window窗口的概念 ,因为是流计算,无边界,所以需要通过窗口来指定计算范围,主要有countWindow,TimeWindow 

countWindow 事件数量计算 一个参数时为滚动窗口,窗口之间没有重叠,每隔多少个事件统计一次,两个参数为滑动窗口,即两个窗口之间有重叠,countWindow(5,1) 每隔一个事件,计算前五次事件

TimeWindow 时间窗口 滚动 滑动2个参数 同样时间窗口和事件窗口差不多 TimeWindow(5,1) 每隔一秒计算前 五秒的数据

time 概念

eventtime(watermarks)  事件时间一般指事件被生产出来的时间,eventTime经常和watermarks一起使用处理乱序数据

(ingestion)进入时间  通过kafka等进入到flink的时间

process time flink正式处理的时间,一般默认就是这个时间

接着来说这个水位线watermars ,一般和eventTime一起来处理乱序的数据 eventTime是固定的,不受flink影响,包含着一个时间戳

需要指定一下 使用eventTime   

val env = StreamExecutionEnvironment.getExecutionEnvironment

//env.setStreamTimeCharacteristic(TimeCharacteristic.ProcessingTime)

// alternatively:
// env.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime)
env.setStreamTimeCharacteristic(TimeCharacteristic.EventTime)

w(11)之前的数据全部消费,11之后的先等一下

,比如如下一个场景,

统计一个窗口的数据 TimeWindow(5),统计每5秒内的数据,然后由于种种原因,source operator sink

如网络,机器性能等等,造成数据乱序了,本来该按照时间先后顺序抵达,然后乱序了,甚至有的迟迟未到,但是总不能一直等着那个迟到的孩子吧,所以得有个机制去触发窗口合并统计

(在此插一条,如果不是统计而是必须严格按照,时间先后顺序进行处理,是不是还得对此窗口的进行排序按照时间戳的形式,   还有那个容错延时时间,会不会出现这种情况,在那个迟到的孩子前面先来了一个最新的数据导致watermaers突然变大,然后提前使窗口合并???)

而这个合并的机制就是watermarks ,水位线大概是这样产生的 每次取进来事件的时间戳和当前最大时间戳取max,因为时间戳是一直增长的,然后max-容错值=watermarks

public class BoundedOutOfOrdernessGenerator implements AssignerWithPeriodicWatermarks<MyEvent> {
 
    private final long maxOutOfOrderness = 3500; // 3.5 seconds
 
    private long currentMaxTimestamp;
 
    @Override
    public long extractTimestamp(MyEvent element, long previousElementTimestamp) {
        long timestamp = element.getCreationTime();
        currentMaxTimestamp = Math.max(timestamp, currentMaxTimestamp);
        return timestamp;
    }
 
    @Override
    public Watermark getCurrentWatermark() {
        // return the watermark as current highest timestamp minus the out-of-orderness bound
        return new Watermark(currentMaxTimestamp - maxOutOfOrderness);
    }
}
 

一会再解释为什么要减容错值,直到watermarks>=Timewindow 右边界,窗口合并计算,之所以要减去容错值是因为为了等一下那个迟到的孩子,称之为容错值,具体值的大小要根据具体业务来处理

提取WaterMark的方式两类,一类是定时提取watermark,对应AssignerWithPeriodicWatermarks,这种方式会定时提取更新wartermark,另一类伴随event的到来就提取watermark,就是每一个event到来的时候,就会提取一次Watermark,对应AssignerWithPunctuatedWatermarks,这样的方式当然设置watermark更为精准,但是当数据量大的时候,频繁的更新wartermark会比较影响性能。通常情况下采用定时提取就足够了。需要注意的是watermark的提取工作在taskManager中完成,意味着这项工作是并行进行的的,而watermark是一个全局的概念,就是一个整个Flink作业之后一个warkermark。那么warkermark一般是怎么提取呢,这里引用官网的两个例子来说明。在第一个例子中extractTimestamp方法,在每一个event到来之后就会被调用,这里其实就是为了设置watermark的值,关键代码在于Math.max(timestamp,currentMaxTimestamp),意思是在当前的水位和当前事件时间中选取一个较大值,来让watermark流动。为什么要选取最大值,因为理想状态下,消息的事件时间肯定是递增的,实际处理中,消息乱序是大概率事件,所以为了保证watermark递增,要取最大值。而getCurrentWatermarker会被定时调用,可以看到方法中减了一个常量,这个原因在下面阐述。就这样,不断从eventTime中提取并更新watermark。第二个例子,并没有在提取eventTime的时候更新watermark的值,而是直接取系统当前时间减去一个常量,作为新的watermark。

    /**
     * This generator generates watermarks assuming that elements arrive out of order,
     * but only to a certain degree. The latest elements for a certain timestamp t will arrive
     * at most n milliseconds after the earliest elements for timestamp t.
     */
    public class BoundedOutOfOrdernessGenerator implements AssignerWithPeriodicWatermarks<MyEvent> {
     
        private final long maxOutOfOrderness = 3500; // 3.5 seconds
     
        private long currentMaxTimestamp;
     
        @Override
        public long extractTimestamp(MyEvent element, long previousElementTimestamp) {
            long timestamp = element.getCreationTime();
            currentMaxTimestamp = Math.max(timestamp, currentMaxTimestamp);
            return timestamp;
        }
     
        @Override
        public Watermark getCurrentWatermark() {
            // return the watermark as current highest timestamp minus the out-of-orderness bound
            return new Watermark(currentMaxTimestamp - maxOutOfOrderness);
        }
    }

    /**
     * This generator generates watermarks that are lagging behind processing time by a fixed amount.
     * It assumes that elements arrive in Flink after a bounded delay.
     */
    public class TimeLagWatermarkGenerator implements AssignerWithPeriodicWatermarks<MyEvent> {
     
        private final long maxTimeLag = 5000; // 5 seconds
     
        @Override
        public long extractTimestamp(MyEvent element, long previousElementTimestamp) {
            return element.getCreationTime();
        }
     
        @Override
        public Watermark getCurrentWatermark() {
            // return the watermark as current time minus the maximum time lag
            return new Watermark(System.currentTimeMillis() - maxTimeLag);
        }
    }

可以上面两种代码中,提取watermark的时候都要减去一个常量,为了理解这么做的原因,需要了解,watermark的工作方式,上文提到在基于eventTime的计算中,需要watermark的协助来触发window的计算,触发规则是watermark大于等于window的结束时间,并且这个窗口中有数据的时候,就会触发window计算。 举个例子说明其工作方式,当前window为10s,设想理想情况下消息都没有延迟,那么eventTime等于系统当前时间,假如设置watermark等于eventTIme的时候,当watermark = 00:00:10的时候,就会触发w1的计算,这个时后因为消息都没有延迟,watermark之前的消息(00:00:00~00:00:10)都已经落入到window中,所以会计算window中全量的数据。那么假如有一条消息data1,eventTime是00:00:01 应该属于w1,在00:00:11才到达,因为假设消息没有延迟,那么watermark等于当前时间,00:00:11,这个时候w1已经计算完毕,那么这条消息就会被丢弃,没有加入计算,这样就会出现问题。这是已经可以理解,代码中为什么要减去一个常量作为watermark,假设每次提取eventTime的时后,减去2s,那么当data1在00:00:11到达的时候,watermark才是00:00:09这个时候,w1还没有触发计算,那么data1会被加入w1,这个时候计算完全没有问题,所以减去一个常量是为了对延时的消息进行容错的。
 

如果在多条并行流中watermarks选取最小的那个,保证数据的不丢失

指定时间戳和水印

两种方式第一种直接从source里面产生

第二种通过Timestamp assigners和watermarks generator生成,覆盖第一种的timestamp

第二种又有两种方式 第一种 With Periodic Watermarks 定时 产生 timestamp watermarks

第二种 With Punctuated Watermarks 基于事件产生timeatmp 和watermarks punctual比较准确些,但当数据量大时,效率不高

flink节点间的关系:jobmanager(master)调度任务,checkpoint,失败恢复等

taskmanager(slave) 执行任务

每一个worker(taskmanager) 都是一个jvm进程,执行着一个或多个子任务在不同的线程中,为了控制有多少个任务被work接受,一个worker也被叫做task slots,在TaskManager内可以运行多个task。多个task运行在一个JVM内有几个好处,首先task可以通过多路复用的方式TCP连接,其次task可以共享节点之间的心跳信息,减少了网络传输

taskmanager->多个slot(内存)->多个task(线程)

Slot是TaskManager资源粒度的划分,每个Slot都有自己独立的内存。所有Slot平均分配TaskManger的内存,比如TaskManagerSlot仅划分内存,不涉及cpu的划分。同时Slot是Flink中的任务执行器(类似Storm中Executor),每个Slot可以运行多个task,而且一个task会以单独的线程来运行。Slot主要的好处有以下几点:

    可以起到隔离内存的作用,防止多个不同job的task竞争内存。
    Slot的个数就代表了一个Flink程序的最高并行度,简化了性能调优的过程
    允许多个Task共享Slot,提升了资源利用率,
 

The processes involved in executing a Flink dataflow

每一个task slots 代表着一taskmanager的部分的资源比如内存,但是没有cpu隔离,

多个slot共享一个jvm,

state 

operate state 算子状态 一般在内存

keyed state 

state backend 一般在rocksdb 再到hdfs

checkpoint 全局异步,局部同步

用于内部失败的恢复,

source 注入barrier 

savepoint 外部恢复应用重启,升级 状态历史版本

cancel with savepoint 取消时自动触发,

手动触发

在flink中主要有两种状态,keyed state 和 operator state 

keyed state可以看作是 operate state的分区版本

默认checkpoint是关闭的需要手动开启 env.enableCheckpointing(n) n是每隔多少毫秒checkpoint一次,可以设置exactl-once 或者at-least-once,checkpoint通过state backend 存在taskmanager的memory中,

猜你喜欢

转载自blog.csdn.net/qq_38250124/article/details/88675660