需求描述
物联设备实时上报采集参数,对每个设备的采集参数进行监控
发现某个采集参数存在异常时,触发报警
需求分析
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());