flink中使用外部定时器实现定时刷新

背景:

我们经常会使用到比如数据库中的配置表信息,而我们不希望每次都去查询db,那么我们就想定时把db配置表的数据定时加载到flink的本地内存中,那么如何实现呢?

外部定时器定时加载实现

1.在open函数中进行定时器的创建和定时加载,这个方法对于所有的RichFunction富函数都适用,包括RichMap,RichFilter,RichSink等,代码如下所示

package wikiedits.schedule;

import org.apache.flink.api.common.functions.RichFlatMapFunction;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.util.Collector;
import org.apache.flink.util.ExecutorUtils;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduleRichMapFunction extends RichFlatMapFunction<String, String> {

    // 定时任务执行器
    private transient ScheduledExecutorService scheduledExecutorService;
    // 本地变量
    private int threshold;

    @Override
    public void open(Configuration parameters) throws Exception {
        // 1.从db查询数据初始化本地变量
//        threshold = DBManager.SELECTSQL.getConfig("threshold");
        // 2.使用定时任务更新本地内存的配置信息以及更新本地变量threshold的值
        scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.scheduleWithFixedDelay(() -> {
            // 2.1 定时任务更新本地内存配置项
            // List<ConfigEntity> configList = DBManager.SELECTSQL.getConfigs();
//            for(ConfigEntity entity : configList){
                ConfigEntityLocalCache.getInstance().update("key", "value");
//            }
            // 2.2 更新本地变量threshold的值
//            threshold = DBManager.SELECTSQL.getConfig("threshold");
        }, 0, 100, TimeUnit.SECONDS);

    }

    @Override
    public void flatMap(String value, Collector<String> out) throws Exception {

    }

    @Override
    public void close() throws Exception {
        ExecutorUtils.gracefulShutdown(100, TimeUnit.SECONDS, scheduledExecutorService);
    }


}

//本地缓存实现
package wikiedits.schedule;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

/**
 * 保存Config信息的本地缓存 ---定时同步DB配置表的数据
 */
public class ConfigEntityLocalCache {

    private static volatile ConfigEntityLocalCache instance = new ConfigEntityLocalCache();

    /**
     * 获取本地缓存实例
     */
    public static ConfigEntityLocalCache getInstance() {
        return instance;
    }

    /** 缓存内存配置项 */
    private static Cache<String, String> configCache =
            CacheBuilder.newBuilder().initialCapacity(50).maximumSize(500).build();


    /**
     * 更新本地缓存数据
     */
    public boolean update(String key, String value){
        configCache.put(key, value);
        return true;
    }


    /**
     * 更新本地缓存数据
     */
    public  String getByKey(String key){
        return configCache.getIfPresent(key);
    }

}


2.在静态类中通过static语句块创建定时器并定时加载,代码如下

package wikiedits.schedule;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;

/**
 * 静态类定时加载DB配置表到本地内存中
 */
public class StaticLoadUtil {

    // 定时任务执行器
    private static transient ScheduledExecutorService scheduledExecutorService;

    public static final Cache<String, String> configCache =
            CacheBuilder.newBuilder().initialCapacity(50).maximumSize(500).build();

    // 通过定时执行器定时同步本地缓存和DB配置表
    static {
        scheduledExecutorService = Executors.newScheduledThreadPool(10);
        scheduledExecutorService.scheduleWithFixedDelay(() -> {
            // 2.1 定时任务更新本地内存配置项
            // List<ConfigEntity> configList = DBManager.SELECTSQL.getConfigs();
            // for(ConfigEntity entity : configList){
            configCache.put("key", "value");
            // }
            // 2.2 更新本地变量threshold的值
            // threshold = DBManager.SELECTSQL.getConfig("threshold");
        }, 0, 100, TimeUnit.SECONDS);
    }

    /**
     * 获取本地缓存
     */
    public static Cache<String, String> getConfigCache() {
        return configCache;
    }


}

总结:

1.外部定时器可以通过在富函数的open中进行初始化并开始定时执行

2.外部定时器也可以通过创建一个单独的静态类,然后在static模块中进行初始化并开始定时执行

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Flink是一个基于流的计算框架,可以实现定时器累加功能。下面是一段实现定时器累加功能的代码:val env = StreamExecutionEnvironment.getExecutionEnvironment val timerStream = env.fromCollection(Seq(0, 1, 2, 3))val accumulator = 0 val resultStream = timerStream.map(x => { accumulator += x accumulator })resultStream.print()env.execute() ### 回答2: import org.apache.flink.api.common.functions.RichFlatMapFunction; import org.apache.flink.api.java.tuple.Tuple2; import org.apache.flink.api.java.tuple.Tuple3; import org.apache.flink.api.java.tuple.Tuple4; import org.apache.flink.streaming.api.datastream.DataStream; import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment; import org.apache.flink.util.Collector; /** * 使用Flink状态和定时器实现累加功能的代码示例 */ public class AccumulateFunctionExample { public static void main(String[] args) throws Exception { // 创建执行环境 StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); // 设置每个并行任务的最大并发数 env.setParallelism(1); // 模拟输入数据,元组的第一个字段为时间,第二个字段为需要累加的值 DataStream<Tuple2<Long, Integer>> dataStream = env.fromElements( Tuple2.of(1L, 1), Tuple2.of(2L, 2), Tuple2.of(3L, 3) ); // 使用RichFlatMapFunction来实现累加功能 DataStream<Tuple4<Long, Long, Integer, Integer>> resultStream = dataStream .keyBy(0) // 数据按时间进行分组 .flatMap(new RichAccumulateFunction()); // 使用自定义的RichFlatMapFunction进行计算 // 打印结果 resultStream.print(); // 执行任务 env.execute(); } /** * 自定义的RichFlatMapFunction */ public static class RichAccumulateFunction extends RichFlatMapFunction<Tuple2<Long, Integer>, Tuple4<Long, Long, Integer, Integer>> { // 状态变量,保存累加结果 private Integer sum = 0; // 定时器的处理时间阈值 private final long threshold = 10 * 1000L; // 10秒 @Override public void flatMap(Tuple2<Long, Integer> value, Collector<Tuple4<Long, Long, Integer, Integer>> out) throws Exception { // 获取当前事件时间 Long currentTimestamp = value.f0; // 如果当前时间大于等于阈值,则触发定时器逻辑 if (currentTimestamp >= threshold) { // 输出当前时间和累加结果 out.collect(Tuple4.of(currentTimestamp, currentTimestamp - threshold, sum, value.f1)); // 清空状态变量 sum = 0; } // 更新状态变量 sum += value.f1; } @Override public void open(org.apache.flink.configuration.Configuration parameters) throws Exception { // 在open方法注册定时器 long timerTimestamp = System.currentTimeMillis() + threshold; getRuntimeContext().registerTimer(timerTimestamp, timerTimestamp); } @Override public void onTimer(long timestamp, OnTimerContext ctx, Collector<Tuple4<Long, Long, Integer, Integer>> out) throws Exception { // 定时器触发时,将累加结果输出到下游 out.collect(Tuple4.of(timestamp, timestamp - threshold, sum, 0)); // 清空状态变量 sum = 0; } } } ### 回答3: Flink是一个用于实时流处理和批处理的开源分布式计算框架。为了实现累加功能,我们可以使用Flink的状态和定时器来跟踪和更新累加值。 首先,我们需要创建一个实现 RichFlatMapFunction 接口的自定义函数。我们将在函数创建和更新累加值的状态,并使用定时器来定期触发累加操作。 以下是一个使用状态和定时器实现累加功能的示例代码: ```java public class AccumulatorFunction extends RichFlatMapFunction<Integer, Integer> { private ValueState<Integer> sumState; private Long lastTimerTimestamp; @Override public void open(Configuration parameters) { // 在open方法初始化状态 ValueStateDescriptor<Integer> descriptor = new ValueStateDescriptor<>("sumState", Integer.class); sumState = getRuntimeContext().getState(descriptor); } @Override public void flatMap(Integer value, Collector<Integer> out) throws Exception { // 从状态获取当前的累加值 Integer currentSum = sumState.value(); if (currentSum == null) { currentSum = 0; } // 更新累加值 currentSum += value; // 将更新后的累加值保存到状态 sumState.update(currentSum); // 如果没有定时器,注册一个1小时之后的定时器 if (lastTimerTimestamp == null) { Long timerTimestamp = System.currentTimeMillis() + 3600000; getRuntimeContext().getTimerService().registerProcessingTimeTimer(timerTimestamp); lastTimerTimestamp = timerTimestamp; } // 发射累加值 out.collect(currentSum); } @Override public void onTimer(long timestamp, OnTimerContext ctx, Collector<Integer> out) throws Exception { // 定时器触发时,输出当前的累加值,并清空状态 Integer currentSum = sumState.value(); out.collect(currentSum); sumState.clear(); lastTimerTimestamp = null; } } ``` 在上述代码,我们首先在 `open` 方法初始化累加值的状态。然后,我们在 `flatMap` 方法更新累加值,并注册一个1小时后的定时器。当定时器触发时,在 `onTimer` 方法输出当前的累加值,并清空状态。 要执行这个函数,可以将它应用在一个流处理任务,例如: ```java StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(); DataStream<Integer> dataStream = ...; // 输入数据流 dataStream .flatMap(new AccumulatorFunction()) .print(); env.execute("Accumulator Example"); ``` 在这个例子,我们将输入的数据流通过 `flatMap` 函数传递给自定义函数,然后通过 `print` 方法输出结果。 使用状态和定时器可以实现各种累加功能,以及其他具有状态管理和时间感知需求的复杂计算逻辑。希望以上代码对您有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值