Flink CEP 爆破登录

该博客介绍了如何利用Apache Flink的CEP库来检测5秒内连续登录失败的用户,并在检测到这种情况时阻止用户在1分钟内再次尝试登录。通过定义模式匹配规则和使用PatternProcessFunction,博主展示了如何从LoginEvent数据流中抽取连续失败的登录事件。
摘要由CSDN通过智能技术生成

需求说明:在这个案例中,我们需要找出那些 5 秒钟内连续登录失败的账号,然后禁止用户,再次尝试登录需要等待 1 分钟。

LoginEvent:
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author wanglin
 * @description TODO
 * @date 2022-06-09 7:46
 */
@AllArgsConstructor
@NoArgsConstructor
@Data
public class LoginEvent {
    private Long userId;
    private String isSuccess;
    private Long timeStamp;
}
AlertEvent:
package com.flink.cep.bean;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author wanglin
 * @description TODO
 * @date 2022-06-09 7:52
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class AlertEvent {
    private String id;
    private String message;
}

/**
 * @BelongsProject: FlinkCEP
 * @BelongsPackage: com.flink.cep.bean
 * @Author: wanglin
 * @CreateTime: 2022-06-09  07:52
 * @Description: TODO
 * @Version: 1.0
 */

LoginEvent主类:
package com.flink.cep.code;

import com.flink.cep.bean.AlertEvent;
import com.flink.cep.bean.LoginEvent;
import edu.umd.cs.findbugs.annotations.Nullable;
import org.apache.flink.api.java.functions.KeySelector;
import org.apache.flink.cep.CEP;
import org.apache.flink.cep.PatternStream;
import org.apache.flink.cep.functions.PatternProcessFunction;
import org.apache.flink.cep.pattern.Pattern;
import org.apache.flink.cep.pattern.conditions.IterativeCondition;
import org.apache.flink.streaming.api.datastream.DataStream;
import org.apache.flink.streaming.api.datastream.SingleOutputStreamOperator;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import org.apache.flink.streaming.api.functions.AssignerWithPeriodicWatermarks;
import org.apache.flink.streaming.api.watermark.Watermark;
import org.apache.flink.streaming.api.windowing.time.Time;
import org.apache.flink.util.Collector;

import java.util.List;
import java.util.Map;

public class LoginEventDemo {
    public static void main(String[] args) throws Exception {
        // 需求:在这个案例中,我们需要找出那些 5 秒钟内连续登录失败的账号,然后禁止用户,再次尝试登录需要等待 1 分钟。
        // 创建执行环境
        StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
        env.setParallelism(1);

        // 构建数据源,提取事件时间戳并生成watermark 并根据UserId分组
        DataStream<LoginEvent> source = env.fromElements(
                new LoginEvent(1L, "fail", 1597905234000L),
                new LoginEvent(1L, "success", 1597905235000L),
                new LoginEvent(2L, "fail", 1597905236000L),
                new LoginEvent(2L, "fail", 1597905237000L),
                new LoginEvent(2L, "fail", 1597905238000L),
                new LoginEvent(3L, "fail", 1597905239000L),
                new LoginEvent(3L, "success", 1597905240000L)
        ).assignTimestampsAndWatermarks(new BoundedOutOfOrdernessGenerator()).keyBy(new KeySelector<LoginEvent, Object>() {
            @Override
            public Object getKey(LoginEvent value) throws Exception {
                return value.getUserId();
            }
        });

        // 定义模式匹配规则
        Pattern<LoginEvent, LoginEvent> pattern = Pattern.<LoginEvent>begin("start").where(new IterativeCondition<LoginEvent>() {
            @Override
            public boolean filter(LoginEvent value, Context<LoginEvent> context) throws Exception {
                return value.getIsSuccess().equals("fail");
            }
        }).next("next").where(new IterativeCondition<LoginEvent>() {
            @Override
            public boolean filter(LoginEvent value, Context<LoginEvent> context) throws Exception {
                return value.getIsSuccess().equals("fail");
            }
        }).timesOrMore(2)
                .within(Time.seconds(5));

        // 5秒内连续登录多次
        /*Pattern<LoginEvent, LoginEvent> patternStream = Pattern.<LoginEvent>begin("start").where(new IterativeCondition<LoginEvent>() {
            @Override
            public boolean filter(LoginEvent value, Context<LoginEvent> context) throws Exception {
                return value.getIsSuccess().equals("fail");
            }
        }).timesOrMore(2)
               .within(Time.seconds(5));*/

        // 将模式作用在流上
        PatternStream<LoginEvent> patternStream = CEP.pattern(source, pattern);
        // 检测模式
        SingleOutputStreamOperator<AlertEvent> process = patternStream.process(new PatternProcessFunction<LoginEvent, AlertEvent>() {
            @Override
            public void processMatch(Map<String, List<LoginEvent>> match, Context ctx, Collector<AlertEvent> out) throws Exception {
                List<LoginEvent> start = match.get("start");
                List<LoginEvent> next = match.get("next");
                System.out.println("start:" + start + ",next:" + next);
            }
        });
        process.printToErr();
        // 启动任务
        env.execute("LoginEventDemo");

    }

    private static class BoundedOutOfOrdernessGenerator implements AssignerWithPeriodicWatermarks<LoginEvent> {
        private final long maxOutOfOrderness = 5000L;
        private long currentTimeStamp;
        @Nullable
        @Override
        public Watermark getCurrentWatermark() {
            return new Watermark(currentTimeStamp - maxOutOfOrderness);
        }
        @Override
        public long extractTimestamp(LoginEvent element, long previousElementTimestamp) {
            Long timeStamp = element.getTimeStamp();
            currentTimeStamp = Math.max(timeStamp, currentTimeStamp);
            System.err.println(element.toString() + ",EventTime:" + timeStamp + ",watermark:" + (currentTimeStamp - maxOutOfOrderness));
            return timeStamp;
        }
    }
}


测试结果:

LoginEvent(userId=1, isSuccess=fail, timeStamp=1597905234000),EventTime:1597905234000,watermark:1597905229000
LoginEvent(userId=1, isSuccess=success, timeStamp=1597905235000),EventTime:1597905235000,watermark:1597905230000
LoginEvent(userId=2, isSuccess=fail, timeStamp=1597905236000),EventTime:1597905236000,watermark:1597905231000
LoginEvent(userId=2, isSuccess=fail, timeStamp=1597905237000),EventTime:1597905237000,watermark:1597905232000
LoginEvent(userId=2, isSuccess=fail, timeStamp=1597905238000),EventTime:1597905238000,watermark:1597905233000
LoginEvent(userId=3, isSuccess=fail, timeStamp=1597905239000),EventTime:1597905239000,watermark:1597905234000
LoginEvent(userId=3, isSuccess=success, timeStamp=1597905240000),EventTime:1597905240000,watermark:1597905235000
start:[LoginEvent(userId=2, isSuccess=fail, timeStamp=1597905236000)],next:[LoginEvent(userId=2, isSuccess=fail, timeStamp=1597905237000), LoginEvent(userId=2, isSuccess=fail, timeStamp=1597905238000)]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值