Flink时间窗口实战解析(一)

  • 随着业务的增长,培优内部对实时任务的需求也愈来愈迫切。在这种情况下,除了实时业务的一些刚需之外,还会出现一些类似监控和告警之类的需求,下面我们讲一下近期用户平台部的 应用性能管理APM服务 实时需求开发中遇到的一些问题。

    一、APM服务背景

    本次,APMapplication performance manager)应用性能管理服务是用户平台部通过对线上服务日志采集,再通过flink实时处理性能数据以及对event事件进行管理来达到监控告警和管理的相关功能。

    下图是APM服务的整体运行架构图:  

     

      在实时功能的开发中,需要针对收集上来的日志进行统筹管理,也就是需要切分以及对照映射后,在窗口中对相关的字段等进行统计处理并写入到InfluxDB中,最终在Grafana做监控呈现。然后还有另一条分支则是触发event事件后,触发告警模块来进行监控告警。这里细心的小伙伴会发现,其实这一套可以用ELK统一流程来简洁处理的。但由于后续还要在事件处理后接入WebPortal服务以及做一些复杂的解析和逻辑处理,所以最终落地的还是这套相对功能更丰富一些的架构。综上看,简洁可复用才是我们架构的设计之道。

    在具体的开发过程中,将原本在logstash中需要做的解析也一并放到flink中,这样做有以下几点考虑:

    • 其一是我们需要尽量简洁不臃肿冗余的架构,简洁意味着出问题我们好查找解决;

    • 其二是对复杂处理逻辑上,自己做java开发能够更个性化一些;

    • 其三是后续需要对原始日志存储起来,那么在kafka前不作处理,我们后续才能收集到最原始的日志;

    二、watermark问题定位

      上面说完了需求和设计,下面来具体说一下本次遇到的异常现象及问题定位过程。在具体的开发中,从kafka端获取日志后,在flink中先对其进行切分整理包装,之后在一个2s的窗口中统计具体的times字段,最终做落地处理。看似很简单的一个过程,实际上也会存在一些问题,比如这次遇到的设置eventime后,窗口不触发的问题。

    2.1 watermark的设置

      由于首次开发,对flink的api不熟悉的情况下,极其容易按照java的开发思维去思考关于watermark的build方法,可以看到我们在custom source后给 datastream分配了一个watermark,但是这个算子后,便没了其他操作,那么试想我们涌动的数据流动的情况下,只分配而不使用,那么,后续的流里面是断然不会拥有watermark的。所以此部分正确的,应该是通过该operator后,我们生成一个新的datastream,其后的操作都紧跟这个新生成的datastream来展开。再一点敲黑板:大家在首次调试时,尽量把各个算子的并行度分开设置,这样便于分开各个算子,方便查找定位问题,我不信你直接搂日志有这么简单易行。

     

     

    2.2 assign分发watermark选择

      下来我们聚焦下创建watermark分发器的具体过程。这里的watermark分发器具体划分为哪几种,我们又有哪些是可以拿来直接上手操作的呢?这里我们针对watermark分发器的门类来一一展开。一步一步来,先看看总体的一个关系:

     

     

    那么,大家可以看到这个TimestampAssigner,他是做啥的嘞?原文如下:

    * A {@code TimestampAssigner} assigns event time timestamps to elements.
    * These timestamps are used by all functions that operate on event time,
    * for example event time windows.

      细看好似是给event time和window来分发时间戳的,我们用的正是event time,刚好,顺着他往下找是一个抽取时间戳的接口,刚好刚好,正合适来提取时间戳。下面我们看看上图,里面有两种watermark分配器接口,他们下面还有自己细分的实现类。

    2.3 AssignerWithPeriodicWatermarks

      AssignerWithPeriodicWatermarks这个接口将事件时间戳分配给具体元素,并生成标志着事件时间在流中运行的水印下限值。这些时间戳和水印具体用于提供在事件时间上操作的函数和算子来使用,比如我们这里用到的事件时间窗口。而且这个接口提供了阶段性触发水印的方法,也可以自己来设置这时间个间隔。咦,这貌似抽取元素时间的方法有了,分发watermark的方法也有了诶~~~ 别美,我们先看AssignerWithPeriodicWatermarks这个接口及其下的抽象方法和具体实现。

    AscendingTimestampExtractor:顾名思义是单调递增的时间戳分配器和水印生成器。下图中包含了一个用于处理违反时间单调性时自定义处理程序,这是他和其他的抽象类不同的地方,那么我们需要什么呢?我们需要的是按窗口和事件时间来处理watermark的方法和类。显然不是他啦。

     

     

    BoundedOutOfOrdernessTimestampExtractor:该抽象类用于发出超过窗口范围事件时间的最大时间戳的元素水印。这样做可以减少计算给定窗口的最终结果时的延迟数据影响。正常情况下,元素的到达时间不会晚于水印,但对于部分事件时间已超过其(事件时间)时间戳而被忽略的元素来讲,我们需要一套处理他们的方式。

     

     

      该抽象类中通过maxOutOfOrderness来控制发送迟到元素超过最大窗口时间的间隔。我们可以通过实现extractTimestamp(T)方法来抽取我们元素中,然后再经过extractTimestamp(T,long)赋值给watermark时间戳,在operator操作时通过getCurrentWatermark()来计算potentialWM也就是最大乱序的时间戳,有了它我们就可以按常规窗口逻辑来处理这部分乱序的数据啦。

    2.4 AssignerWithPunctuatedWatermarks

    说完阶段性的水印分发器,下面再看一下AssignerWithPunctuatedWatermarks这个接口。它里面只有这个方法:

    @Nullable
    Watermark checkAndGetNextWatermark(T lastElement, long extractedTimestamp);

           这里我们需要根据我们的流中的特定元素拿到其时间戳字段,然后再通过这个方法来将其赋值给watermark,也就是说我们这里的水印的时间完全来自于流中元素,不是阶段性触发,没有单调递增的这个判断,也没有什么乱序的超时时间设置。所以这种可以用于我们对特定事件的处理。

           说了这么多,那么我们具体应该使用的是哪个水印分发器也很清晰了,肯定选BoundedOutOfOrdernessTimestampExtractor了,在大体了解了上述的水印分配流程后,下来我们针对具体流中的处理方式来展开说一下这个分发器。

    2.5 BoundedOutOfOrdernessTimestampExtractor

    其实我们在选用了这个分配器后,将后续的处理也放到这个有了水印的流之后,但还是会发现很久都没有触发这个窗口。于是乎,我们重写了EventTimeTrigger这个类,然后通过打印日志来查找具体的watermark的时间戳。

     

             我们需要的是这里两个方法都触发TriggerResult.FIRE来使我们的窗口触发计算,得到窗口的计算结果。但日志中仅发现onElement 有打印具体的timestamp,而onEventTime 方法却没有打印,而且ctx.getCurrentWatermark()打印一直是-9223372036854775808。那么我们具体看下为什么会这样,首先可以发现在trigger时,肯定是窗口没有处罚watermark进行窗口计算,而且我们得到的当前的watermark也是负数,这就说明了我们的watermark分配我们元素里的时间也好,还是让他自动触发也罢,这里根本没生效,好的,基于这个点我们来再深入看下对乱序超时的数据进行水印分配的这个类其中的玄妙之处。

     

     

            可以看到,一共三个方法,里面包括了从流中抽取时间戳的方法和一个重载的用于判断抽取时间和当前最大水印时间的赋值方法,最后是一个获取我们将超时时长添加后的水印处理方法,这里可以看到我们复写extractTimestamp(T)后,其实其他逻辑是完全符合我们的业务场景的,但是我们自行触发也还是没有解决,所以问题是不是出在了水印上,这里,其实我们忽略了一个问题,那是什么问题呢?请看下一节之 --《Flink时间窗口实战解析(二)》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值