Flink Idle 中的设计

Flink Idle 中的设计

哈哈… 今天是源码解析天,关于Idle 的,来吧,看看源码中是怎样检测数据源是否要标记为Idle。

//在StreamSourceContexts 类中可以看到, 内部类 WatermarkContext的构造方法中设置了
//IdleTimeOut,timeService(这个是一个定时执行的服务),以及调用了scheduleNextIdleDetectionTask()方法。

 public WatermarkContext(
                final ProcessingTimeService timeService,
                final Object checkpointLock,
                final long idleTimeout) {

            this.timeService =
                    Preconditions.checkNotNull(timeService, "Time Service cannot be null.");
            this.checkpointLock =
                    Preconditions.checkNotNull(checkpointLock, "Checkpoint Lock cannot be null.");

            if (idleTimeout != -1) {
                Preconditions.checkArgument(
                        idleTimeout >= 1, "The idle timeout cannot be smaller than 1 ms.");
            }
            this.idleTimeout = idleTimeout;
            // 这个方法很重要,进去看一下。
            scheduleNextIdleDetectionTask();
        }

private void scheduleNextIdleDetectionTask() {
		//如果IdleTimeout不 为-1,嘎,就向定时服务注册一个定时任务。
            if (idleTimeout != -1) {
                // reset flag; if it remains true when task fires, we have detected idleness
                failOnNextCheck = true;
                nextCheck =
                        this.timeService.registerTimer(
                        // 这里注册时间,当前时间+idleTimeout的时间
                                this.timeService.getCurrentProcessingTime() + idleTimeout,
                               // 这个一个定时任务,cool,再跳进去。
                                new IdlenessDetectionTask());
            }
        }
// 定时服务的Task会调用Callback的onProcessingTime(...)方法
private class IdlenessDetectionTask implements ProcessingTimeCallback {
            @Override
            public void onProcessingTime(long timestamp) throws Exception {
                synchronized (checkpointLock) {
                    // set this to null now;
                    // the next idleness detection will be scheduled again
                    // depending on the below failOnNextCheck condition
                    nextCheck = null;
                   // 如果failOnNextCheck标识 默认为false,在调用scheduleNextIdleDetectionTask时,将该标识设置为true,
                    if (failOnNextCheck) {
                    // 调用Idle
                        markAsTemporarilyIdle();
                    } else {
                    //不然,就继续调用该方法。
                    //注意,这种看上去像是一个方法调用另外一个方法(容易栈溢出),但是不是哦,
                   //这里scheduleNextIdleDetectionTask()可是,向定时服务提交一个任务,即向另一个Thread 提交一个定时任务。所以安全。
                        scheduleNextIdleDetectionTask();
                    }
                }
            }
        }
      //  那failOnNextCheck 什么时候为false,下面贴的代码里有展示,是具体调用   
      //WatermarkContext类的相应的方法。有新数据collect 或者watermark 发射时会调用
       
         WatermarkContext类的方法。
        @Override
        public void collect(T element) {
            synchronized (checkpointLock) {
                processAndEmitStreamStatus(StreamStatus.ACTIVE);

                if (nextCheck != null) {
                    this.failOnNextCheck = false;
                } else {
                    scheduleNextIdleDetectionTask();
                }

                processAndCollect(element);
            }
        }

        @Override
        public void collectWithTimestamp(T element, long timestamp) {
            synchronized (checkpointLock) {
                processAndEmitStreamStatus(StreamStatus.ACTIVE);

                if (nextCheck != null) {
                    this.failOnNextCheck = false;
                } else {
                    scheduleNextIdleDetectionTask();
                }

                processAndCollectWithTimestamp(element, timestamp);
            }
        }

        @Override
        public void emitWatermark(Watermark mark) {
            if (allowWatermark(mark)) {
                synchronized (checkpointLock) {
                    processAndEmitStreamStatus(StreamStatus.ACTIVE);

                    if (nextCheck != null) {
                        this.failOnNextCheck = false;
                    } else {
                        scheduleNextIdleDetectionTask();
                    }

                    processAndEmitWatermark(mark);
                }
            }
        }


ok。除了上述,还有上篇文章提到的.withIdleness()这个就真的很简单了。

//调用 activity() 方法用户计数。
//这里时wm策略的方法 onEvent() 、onPeriodicEmit()
 @Override
    public void onEvent(T event, long eventTimestamp, WatermarkOutput output) {
        watermarks.onEvent(event, eventTimestamp, output);
        idlenessTimer.activity();
    }
//如果这次计数和上次计数不同,就说明,有wm产生,如果上次计数和这次计数的相同,就获取一
//个起点时间,如果时钟的时间-起点时间>=IdleTimeOut.则Idle。
//下面的IdlenessTimer类,及方法将表现这一逻辑
    @Override
    public void onPeriodicEmit(WatermarkOutput output) {
        if (idlenessTimer.checkIfIdle()) {
            output.markIdle();
        } else {
            watermarks.onPeriodicEmit(output);
        }
    }

    static final class IdlenessTimer {

        /** The clock used to measure elapsed time. */
        private final Clock clock;

        /** Counter to detect change. No problem if it overflows. */
        private long counter;

        /** The value of the counter at the last activity check. */
        private long lastCounter;

        /**
         * The first time (relative to {@link Clock#relativeTimeNanos()}) when the activity check
         * found that no activity happened since the last check. Special value: 0 = no timer.
         */
        private long startOfInactivityNanos;

        /** The duration before the output is marked as idle. */
        private final long maxIdleTimeNanos;

        IdlenessTimer(Clock clock, Duration idleTimeout) {
            this.clock = clock;

            long idleNanos;
            try {
                idleNanos = idleTimeout.toNanos();
            } catch (ArithmeticException ignored) {
                // long integer overflow
                idleNanos = Long.MAX_VALUE;
            }

            this.maxIdleTimeNanos = idleNanos;
        }

        public void activity() {
        //开始计数
            counter++;
        }

        public boolean checkIfIdle() {
        //  和上次的计数不同,不用Idle,返回false。
            if (counter != lastCounter) {
                // activity since the last check. we reset the timer
                lastCounter = counter;
                startOfInactivityNanos = 0L;
                return false;
            } else // timer started but has not yet reached idle timeout
            // 起点为0,将当前时钟的值赋予起点
            if (startOfInactivityNanos == 0L) {
                // first time that we see no activity since the last periodic probe
                // begin the timer
                startOfInactivityNanos = clock.relativeTimeNanos();
                return false;
            } else {
            //起点不为0,且计数相同,就比较当前时钟和起点的差值是否大于 IdleTimeOut 时间。
                return clock.relativeTimeNanos() - startOfInactivityNanos > maxIdleTimeNanos;
            }
        }
    }

结束了。散花。。。欢迎留言

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值