需求描述

物联设备实时上报采集参数,对每个设备的采集参数进行监控
发现某个采集参数存在异常时,触发报警

需求分析

source:
设备采集数据 deviceIotData
  • 采集变量 : 采集值
/\*\*
 \* 物联采集数据
 \*/
@Data
public class IotData {

    /\*\*
 \* 设备ID
 \*/
    private Integer deviceId;

    /\*\*
 \* 时间戳
 \*/
    private Long timestamp;

    /\*\*
 \* 采集参数
 \*/
    private Map<String , Double> data;


}
监控报警规则 alarmRule
/\*\*
 \* 报警规则
 \*/
@Data
public class AlarmRule {


    /\*\*
 \* 规则ID
 \*/
    private Integer id;

    /\*\*
 \* 设备ID
 \*/
    private Integer deviceId;

    /\*\*
 \* 监控的变量名称
 \*/
    private String varName;

    /\*\*
 \* 最小值
 \*/
    private Double min;

    /\*\*
 \* 最大值
 \*/
    private Double max;

}
报警事件
/\*\*
 \* 报警消息
 \*/
@Data
public class AlarmMessage {


    /\*\*
 \* 设备
 \*/
    private Integer deviceId;

    /\*\*
 \* 报警时间
 \*/
    private Long timestamp;
    /\*\*
 \* 触发报警的采集变量名称
 \*/
    private String alarmVar;

    /\*\*
 \* 触发报警的采集值
 \*/
    private Number alarmValue;
}
开始实现
public class IotMonitorJob {

    public static void main(String[] args) throws Exception {


        StreamExecutionEnvironment environment = StreamExecutionEnvironment.getExecutionEnvironment();
        environment.setParallelism(1);

        // 采集数据Stream
        DataStreamSource<IotData> iotDataStream = getIotStream(environment);
        // 报警规则Stream
        DataStreamSource<AlarmRule> ruleConfig = getRuleConfig(environment);
        // 缓存报警规则 并监控报警数据
        SingleOutputStreamOperator<AlarmMessage> alarmStream = iotDataStream.connect(ruleConfig)
                .keyBy(IotData::getDeviceId, AlarmRule::getDeviceId)
                .process(new CoProcessFunction<IotData, AlarmRule, AlarmMessage>() {

                    // 用临时保存设备的报警规则 ,这里的状态交由flink维护
                    private MapState<Integer, AlarmRule> alarmRuleValueState;

                    @Override
                    public void open(Configuration parameters) throws Exception {
                        super.open(parameters);
                        // 初始化 ValueState
                        alarmRuleValueState = getRuntimeContext().getMapState(new MapStateDescriptor<>("alarm-rule-state", Integer.class, AlarmRule.class));
                    }

                    @Override
                    public void processElement1(IotData iotData, CoProcessFunction<IotData, AlarmRule, AlarmMessage>.Context context, Collector<AlarmMessage> collector) throws Exception {
                        Map<String, Double> data = iotData.getData();

                        // 遍历每个规则
                        alarmRuleValueState.values().forEach(rule -> {

                            String varName = rule.getVarName();
                            // 获取变量值
                            Double val = data.get(varName);
                            if (val == null) {
                                // 变量里没有值
                                return;
                            }

                            if (val <= rule.getMin() || val > rule.getMax()) {
                                // 超过限制,输出报警信息
                                AlarmMessage alarmMessage = new AlarmMessage();
                                alarmMessage.setDeviceId(iotData.getDeviceId());
                                alarmMessage.setTimestamp(iotData.getTimestamp());
                                alarmMessage.setAlarmVar(varName);
                                alarmMessage.setAlarmValue(val);
                                collector.collect(alarmMessage);
                            }
                        });


                    }

                    @Override
                    public void processElement2(AlarmRule alarmRule, CoProcessFunction<IotData, AlarmRule, AlarmMessage>.Context context, Collector<AlarmMessage> collector) throws Exception {
                        // 接收到AlarmRule, 仅更新 alarmRuleValueState
                        alarmRuleValueState.put(alarmRule.getId(), alarmRule);
                    }
                });


        alarmStream.print();
        environment.execute();
    }

    /\*\*
 \* 获取物联采集数据
 \*
 \* @param environment
 \* @return
 \*/
    private static DataStreamSource<IotData> getIotStream(StreamExecutionEnvironment environment) {
        return environment.addSource(new SourceFunction<>() {
            private boolean running = true;


            @Override
            public void run(SourceContext<IotData> sourceContext) throws Exception {
                while (running) {

                    // 模拟100个设备 每秒一次上报数据

                    long ts = System.currentTimeMillis();
                    ts = ts - ts % 1000;

                    for (int i = 0; i < 100; i++) {
                        IotData iotData = new IotData();
                        iotData.setTimestamp(ts);
                        iotData.setDeviceId(i);

                        Map<String, Double> data = new HashMap<>();
                        data.put("var1", RandomUtils.nextDouble());