Flink 计数器Accumulator

简述

在 Apache Flink 中,Accumulator 是一个用于收集作业执行期间聚合信息的工具。它允许在用户定义的函数(如 MapFunction, FlatMapFunction, ProcessFunction 等)中累积值,并在作业完成后检索这些值。这对于跟踪诸如事件数量、处理延迟等统计信息非常有用。

要使用 Accumulator,需要首先定义一个 Accumulator 接口的实现,然后在用户定义函数中注册和使用它。

1. 定义 Accumulator:

通常,不需要直接定义 Accumulator 接口的实现,因为 Flink 已经为提供了一些内置的 Accumulator 类型,如 IntCounter, LongCounter, DoubleCounter 等。但如果需要自定义的聚合逻辑,可以实现 Accumulator 接口。

2. 在函数中使用 Accumulator:

在用户定义函数中,可以通过 getRuntimeContext().getAccumulator("name") 来获取或注册一个 Accumulator。然后,可以在逻辑中更新它的值。

3. 检索 Accumulator 的值:

在作业执行完成后,可以通过 JobExecutionResult 的 getAccumulatorResult() 方法来检索 Accumulator 的值。

但请注意,由于 Accumulator 已经被 Metric 系统所取代,以下是一个使用 Metric 的示例,它提供了类似的功能:

java 复制代码
import org.apache.flink.api.common.functions.RuntimeContext;  
import org.apache.flink.metrics.Counter;  
import org.apache.flink.streaming.api.functions.source.SourceFunction;  
  
public class MySourceFunction implements SourceFunction<String> {  
  
    private transient Counter counter;  
  
    @Override  
    public void open(Configuration parameters) throws Exception {  
        super.open(parameters);  
        // 获取或注册一个 Counter  
        this.counter = getRuntimeContext().getMetricGroup().counter("my-counter");  
    }  
  
    @Override  
    public void run(SourceContext<String> ctx) throws Exception {  
        // ... 数据源逻辑 ...  
  
        // 更新 Counter 的值  
        counter.inc();  
  
        // 发送数据到下游  
        ctx.collect("some data");  
    }  
  
    // ... 其他必要的方法 ...  
}

在这个示例中,我们使用了 Flink 的 Metric 系统来创建一个计数器,并在数据源函数中更新它的值。这样,就可以在作业执行期间跟踪和检索这个计数器的值了。

代码

java 复制代码
package com.wfg.flink.connector.mongodb;


import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson2.JSONObject;
import com.wfg.flink.connector.dto.KafkaPvDto;
import org.apache.flink.api.common.JobExecutionResult;
import org.apache.flink.api.common.accumulators.LongCounter;
import org.apache.flink.api.common.eventtime.WatermarkStrategy;
import org.apache.flink.api.common.functions.RichMapFunction;
import org.apache.flink.api.common.typeinfo.BasicTypeInfo;
import org.apache.flink.api.common.typeinfo.TypeInformation;
import org.apache.flink.api.java.tuple.Tuple2;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.configuration.MemorySize;
import org.apache.flink.connector.mongodb.source.MongoSource;
import org.apache.flink.connector.mongodb.source.enumerator.splitter.PartitionStrategy;
import org.apache.flink.connector.mongodb.source.reader.deserializer.MongoDeserializationSchema;
import org.apache.flink.core.fs.FileSystem;
import org.apache.flink.runtime.state.hashmap.HashMapStateBackend;
import org.apache.flink.streaming.api.CheckpointingMode;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.bson.BsonDocument;

import static com.wfg.flink.connector.constants.Constants.MONGO_TEST_PV_COLLECTION;

/**
 * @author wfg
 * 根据名字统计访问次数
 */
public class MongoAccumulatorCounts {

    public static void main(String[] args) throws Exception {
        String startTime = DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss");
        System.out.println("StartTime:" + startTime);
        final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        // 开启Checkpointing,设置Checkpoint间隔
        env.enableCheckpointing(30000);
        // 设置Checkpoint模式
        env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
        // 设置最小Checkpoint间隔
        env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
        // 设置最大并发Checkpoint数目
        env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
        // 使用RocksDB作为状态后端
        env.setStateBackend(new HashMapStateBackend());
        env.setParallelism(10);

        // 配置MongoDB源
        MongoSource<String> mongoSource = MongoSource.<String>builder()
                .setUri("mongodb://root:123456@127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019/admin?replicaSet=rs0&authSource=admin")
                .setDatabase("sjzz")
                .setCollection(MONGO_TEST_PV_COLLECTION)
                .setFetchSize(2048)
//                .setLimit(10000)
                .setNoCursorTimeout(true)
                .setPartitionStrategy(PartitionStrategy.SINGLE)
                .setPartitionSize(MemorySize.ofMebiBytes(64))
                .setDeserializationSchema(new MongoDeserializationSchema<>() {
                    @Override
                    public String deserialize(BsonDocument document) {
                        return document.toJson();
                    }

                    @Override
                    public TypeInformation<String> getProducedType() {
                        return BasicTypeInfo.STRING_TYPE_INFO;
                    }
                })
                .build();
        // 创建MongoDB数据流
        DataStream<String> sourceStream = env.fromSource(mongoSource, WatermarkStrategy.noWatermarks(), "kafka Mongo Source");
// 转换数据,提取人名作为Key
        DataStream<Tuple2<String, Integer>> nameCountStream = sourceStream
                .map(new RichMapFunction<String, Tuple2<String, Integer>>() {
                    private LongCounter elementCounter = new LongCounter();
                    Long count = 0L;

                    @Override
                    public void open(Configuration parameters) throws Exception {
                        super.open(parameters);
                        //-2注册累加器
                        getRuntimeContext().addAccumulator("elementCounter", elementCounter);
                    }

                    @Override
                    public Tuple2<String, Integer> map(String value) {
                        KafkaPvDto data = JSONObject.parseObject(value, KafkaPvDto.class);
                        //-3.使用累加器
                        this.elementCounter.add(1);
                        count += 1;
                        System.out.println("不使用累加器统计的结果:" + count);
                        return Tuple2.of(data.getUserName(), 1);
                    }
                }).setParallelism(10);
//                .keyBy(value->value.f0)
//                 .sum("f1");
        sourceStream.writeAsText("data/output/test", FileSystem.WriteMode.OVERWRITE);
//-4.获取加强结果
        JobExecutionResult jobResult = env.execute();
        long nums = jobResult.getAccumulatorResult("elementCounter");
        System.out.println("使用累加器统计的结果:" + nums);
        System.out.println("-----------------------------------");
        System.out.println("startTime: " + startTime);
        System.out.println("EndTime: " + DateUtil.format(DateUtil.date(), "yyyy-MM-dd HH:mm:ss"));
    }
}
相关推荐
皓741几秒前
服饰电商行业知识管理的创新实践与知识中台的重要性
大数据·人工智能·科技·数据分析·零售
jjyangyou1 分钟前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
Mephisto.java3 分钟前
【大数据学习 | kafka高级部分】kafka的kraft集群
大数据·sql·oracle·kafka·json·hbase
Mephisto.java5 分钟前
【大数据学习 | kafka高级部分】kafka的文件存储原理
大数据·sql·oracle·kafka·json
van叶~18 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
简简单单做算法19 分钟前
基于Retinex算法的图像去雾matlab仿真
算法·matlab·图像去雾·retinex
云卓SKYDROID33 分钟前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
W Y1 小时前
【架构-37】Spark和Flink
架构·flink·spark
ycsdn101 小时前
Caused by: org.apache.flink.api.common.io.ParseException: Row too short:
大数据·flink
半盏茶香1 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏