flink watermark

watermark是为解决事件流乱序问题,如果,A,B两个端,A把10点15日志发送到服务端,B发送10.12的日志,但是因为B网络延迟,造成服务器在10点16时候做数据统计的时候A的数据到了,B的数据没有到造成数据丢失。

watermark 是一个触发计算的阀门,事件流来的时候,都会根据事件的时间创建或者更新这个阀门(取最大的),一旦阀门值大于等于流窗口结束时间,就会触发计算。

比如:下图,每行数据就是一个事件流,事件时间(eventTime)和上一个事件最大时间比较取最大值(MaxTImesTamp),减去3秒作为watermark。窗口结束时间为20000,当watermark等于或者大于20000时触发计算。

 

再说watermark的时候,中间插播一个东西,就是时间,flink中分为三个时间

事件流时间 flink时间flink处理时间
事件流生成的时间,一般由事件产生源携带过来进入flik的时间使用flink算子进行计算的时间
   

Watermark的产生方式:

Punctuated - 数据流中每一个递增的EventTime都会产生一个Watermark。在实际的生产中Punctuated方式在TPS很高的场景下会产生大量的Watermark在一定程度上对下游算子造成压力,所以只有在实时性要求非常高的场景才会选择Punctuated的方式进行Watermark的生成。
接口定义AssignerWithPunctuatedWatermarks:Watermark checkAndGetNextWatermark(T lastElement, long extractedTimestamp);
Periodic - 周期性的(一定时间间隔或者达到一定的记录条数)产生一个Watermark。在实际的生产中Periodic的方式必须结合时间和积累条数两个维度继续周期性产生Watermark,否则在极端情况下会有很大的延时。
接口定义AssignerWithPeriodicWatermarks:Watermark getCurrentWatermark();

周期性:

ev.setStreamTimeCharacteristic(TimeCharacteristic.EventTime);//设置时间类型

/**
 * 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 = 3000; // 3.0 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);//生产wm

//此处说明一下,如果延迟比较固定,可以使用系统当前时间代替currentMaxTimestamp
    }
}

递增模式:

 

使用 AssignerWithPunctuatedWatermarks 在某个事件指定生成新的水印的时候生成水印。这种情况下,Flink 首先会调用 extractTimestamp(...) 方法为数据分配时间戳,然后立即调用 checkAndGetNextWatermark(...)

checkAndGetNextWatermark(...) 方法传递在 extractTimestamp(...) 生成的时间戳,并且界定是否要生成水印。每当 checkAndGetNextWatermark(...) 方法返回非空水印,并且该水印大于先一个水印时,将向后发出新水印。

 

class PunctuatedAssigner extends AssignerWithPunctuatedWatermarks[MyEvent] {

    override def extractTimestamp(element: MyEvent, previousElementTimestamp: Long): Long = {
        element.getCreationTime
    }

    override def checkAndGetNextWatermark(lastElement: MyEvent, extractedTimestamp: Long): Watermark = {
        if (lastElement.hasWatermarkMarker()) new Watermark(extractedTimestamp) else null
    }
}

每个事件都可以生成水印。但是,由于水印会导致一些后续的计算,因此过多的水印会降低性能。

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值