Flink消费Kafka并统计报警

模拟场景

服务端异常时, 向kafka推送一条ALERT消息, flink解析消息, 如果连续10s钟有3次alert消息, 则发出报警消息

实现方法

在首次获取到alert消息后, 注册一个10s后的timer事件, 后续alert消息, 校验当前时间是否在timer有效期内, 如果不在则重置timer, 待timer到期时, 校验个数是否满足, 如果满足发出报警

代码

import org.apache.flink.api.common.functions.FlatMapFunction;
import org.apache.flink.api.common.serialization.SimpleStringSchema;
import org.apache.flink.api.common.state.ValueState;
import org.apache.flink.api.common.state.ValueStateDescriptor;
import org.apache.flink.api.common.typeinfo.Types;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.KeyedProcessFunction;
import org.apache.flink.streaming.connectors.kafka.FlinkKafkaConsumer;
import org.apache.flink.util.Collector;

import java.util.Properties;

public class ConsumeKafkaAndAlertTest {

    public static void main(String[] args) throws Exception {
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.enableCheckpointing(10 * 1000L);

        Properties prop = new Properties();
        prop.setProperty("bootstrap.servers", "localhost:9092"); // kafka地址
        prop.setProperty("group.id", "consumer_flink_1");

        String consumeTopic = "flink-source"; // topic
        FlinkKafkaConsumer<String> kafkaConsumer = new FlinkKafkaConsumer<>(
                consumeTopic, new SimpleStringSchema(), prop);
        kafkaConsumer.setStartFromLatest();

        env.addSource(kafkaConsumer)
        		// 过滤消息包含ALERT和:的字符串
                .flatMap(new FlatMapFunction<String, String>() {
                    @Override
                    public void flatMap(String s, Collector<String> collector) throws Exception {
                        if (s.contains(" ALERT ") && s.contains(": ")) {
                            collector.collect(s.split(": ")[1]); // 保留 msg
                        }
                    }
                })
                .keyBy(new KeySelector<String, String>() {
                    @Override
                    public String getKey(String s) throws Exception {
                        return "ALERT"; // 使用默认值keyBy
                    }
                }).process(new MyProcessFunction()).print();

        env.execute("My Flink Test");
    }

    private static class MyProcessFunction extends KeyedProcessFunction<String, String, String> {

		// 开始时间
        private ValueState<Long> timer;
        // 从开始到现在一共多少次报警
        private ValueState<Integer> count;
        // 记录各报警消息内容
        private ValueState<String> msg;

        private final int alertStillSeconds = 10;
        private final int alertGreaterThan = 3;

        @Override
        public void open(Configuration parameters) throws Exception {
       		// 初始化消息
            super.open(parameters);
            timer = getRuntimeContext().getState(new ValueStateDescriptor<>("alert_timer", Types.LONG));
            count = getRuntimeContext().getState(new ValueStateDescriptor<>("alert_count", Types.INT));
            msg = getRuntimeContext().getState(new ValueStateDescriptor<>("alert_msg", Types.STRING));
        }

        @Override
        public void processElement(String value, Context ctx, Collector<String> out) throws Exception {
            if (timer == null || timer.value() == null || timer.value() == 0 
                    || timer.value() < ctx.timerService().currentProcessingTime() - alertStillSeconds * 1000) {
                // 添加timer报警 并更新时间
                long pt = ctx.timerService().currentProcessingTime();
                ctx.timerService().registerProcessingTimeTimer(pt + alertStillSeconds * 1000);
                timer.update(pt);
                count.update(1);
                msg.update(value + "\n");
            } else {
                count.update(count.value() + 1);
                msg.update(msg.value() + value + "\n");
            }
        }

        @Override
        public void onTimer(long timestamp, OnTimerContext ctx, Collector<String> out) throws Exception {
            super.onTimer(timestamp, ctx, out);
            // 定时器出发 校验次数是否达到阈值
            if (count.value() >= alertGreaterThan) {
                out.collect("服务器报警.... " + count.value() + "次 msg: \n" + msg.value());
                // 报警完重置
                timer.clear();
                count.clear();
                msg.clear();
            }
        }
    }
}

生产消息

D:\data\kafka_2.12-2.8.0\bin\windows>kafka-console-producer.bat --broker-list 127.0.0.1:9092 --topic flink-source
> ALERT : Hello World
> ALERT : Hello World
> ALERT : Hello World
> ALERT : Hello World
> ALERT : Hello World...
> ALERT : Hello World...
> ALERT : Hello World...

运行结果

Connected to the target VM, address: '127.0.0.1:51010', transport: 'socket'
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
4> 服务器报警.... 4次 msg: 
Hello World
Hello World
Hello World
Hello World

4> 服务器报警.... 3次 msg: 
Hello World...
Hello World...
Hello World...
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值