优化agent本地存储流量数据处理

This commit is contained in:
gaoyutao
2026-01-29 12:00:05 +08:00
parent 29a30b1f52
commit 1dab9b1cf4
15 changed files with 465 additions and 89 deletions
@@ -133,4 +133,11 @@ public interface RemoteRevenueConfigService
@GetMapping("/businessScript/inner/{id}") @GetMapping("/businessScript/inner/{id}")
public R<EpsBusinessScriptRemote> getBusinessScriptMsgByScriptId(@PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); public R<EpsBusinessScriptRemote> getBusinessScriptMsgByScriptId(@PathVariable("id") Long id, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
/**
* 保存流量数据
* @param queryParam 流量数据列表
* @return 操作结果
*/
@PostMapping("/revenueConfig/autoSaveServiceRecoverTrafficData")
public R<String> autoSaveServiceRecoverTrafficData(@RequestBody EpsInitialTrafficDataRemote queryParam, @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
} }
@@ -96,6 +96,11 @@ public class RemoteRevenueConfigFallbackFactory implements FallbackFactory<Remot
public R<EpsBusinessScriptRemote> getBusinessScriptMsgByScriptId(Long id, String source) { public R<EpsBusinessScriptRemote> getBusinessScriptMsgByScriptId(Long id, String source) {
return R.fail("获取错误关键词失败:" + throwable.getMessage()); return R.fail("获取错误关键词失败:" + throwable.getMessage());
} }
@Override
public R<String> autoSaveServiceRecoverTrafficData(EpsInitialTrafficDataRemote queryParam, String source) {
return R.fail("保存重试流量数据失败:" + throwable.getMessage());
}
}; };
} }
} }
@@ -118,7 +118,6 @@ public class EchartsDataUtils {
// 准备X轴和Y轴数据 // 准备X轴和Y轴数据
List<String> xAxisData = new ArrayList<>(); List<String> xAxisData = new ArrayList<>();
Map<String, Object> yData = new LinkedHashMap<>(); Map<String, Object> yData = new LinkedHashMap<>();
// 初始化Y轴数据结构 // 初始化Y轴数据结构
dataExtractors.keySet().forEach(name -> dataExtractors.keySet().forEach(name ->
yData.put(name, new ArrayList<>())); yData.put(name, new ArrayList<>()));
@@ -152,7 +151,7 @@ public class EchartsDataUtils {
seriesData.add(getDefaultValue(name, fixedPercentile95Value, xAxisData.size()-1, hasRealData)); seriesData.add(getDefaultValue(name, fixedPercentile95Value, xAxisData.size()-1, hasRealData));
} else { } else {
// 在数据时间范围外 // 在数据时间范围外
seriesData.add(getEmptyDataDefaultValue(name, xAxisData.size()-1)); seriesData.add(getEmptyDataDefaultValue(name, xAxisData.size()-1, hasRealData));
} }
} }
} }
@@ -338,13 +337,23 @@ public class EchartsDataUtils {
/** /**
* 获取空数据默认值(用于数据时间范围外的点) * 获取空数据默认值(用于数据时间范围外的点)
*/ */
private static Object getEmptyDataDefaultValue(String metricName, int timeIndex) { private static Object getEmptyDataDefaultValue(String metricName, int timeIndex, boolean hasRealData) {
// deployDevice特殊处理:始终补空字符串 // deployDevice特殊处理:始终补空字符串
if ("deployDevice".equals(metricName)) { if ("deployDevice".equals(metricName)) {
return ""; return "";
} }
// 智能补全策略
return null; if (hasRealData) {
// 数据集中有真实数据:所有缺失点都补null
return null;
} else {
// 数据集中没有真实数据:第一个点补0,其他点补null
if (timeIndex == 0) {
return 0;
} else {
return null;
}
}
} }
/** /**
@@ -79,5 +79,14 @@ public class EpsServerRevenueConfigController extends BaseController
{ {
return epsServerRevenueConfigService.autoSaveServiceTrafficData(epsServerRevenueConfig); return epsServerRevenueConfigService.autoSaveServiceTrafficData(epsServerRevenueConfig);
} }
/**
* 流量相关数据入库
*/
@InnerAuth
@PostMapping("/autoSaveServiceRecoverTrafficData")
public R<String> autoSaveServiceRecoverTrafficData(@RequestBody EpsServerRevenueConfig epsServerRevenueConfig)
{
return epsServerRevenueConfigService.autoSaveServiceRecoverTrafficData(epsServerRevenueConfig);
}
} }
@@ -74,4 +74,6 @@ public interface EpsInitialTrafficDataMapper {
void createSwitchOpMdTable(String tableName); void createSwitchOpMdTable(String tableName);
void createDiskInfo(String tableName); void createDiskInfo(String tableName);
void batchInsertRecoverDetailTraffic(EpsInitialTrafficData batchData);
} }
@@ -36,6 +36,7 @@ public interface EpsInitialTrafficDataService {
* @param dataList 流量数据列表 * @param dataList 流量数据列表
*/ */
void saveBatch(EpsInitialTrafficData dataList); void saveBatch(EpsInitialTrafficData dataList);
void saveBatchRecoverTraffic(EpsInitialTrafficData dataList);
/** /**
* 查询流量数据 * 查询流量数据
@@ -67,6 +67,7 @@ public interface IEpsServerRevenueConfigService
* @param epsServerRevenueConfig * @param epsServerRevenueConfig
*/ */
R<String> autoSaveServiceTrafficData(EpsServerRevenueConfig epsServerRevenueConfig); R<String> autoSaveServiceTrafficData(EpsServerRevenueConfig epsServerRevenueConfig);
R<String> autoSaveServiceRecoverTrafficData(EpsServerRevenueConfig epsServerRevenueConfig);
/** /**
* 当前在线服务器的流量相关的业务数 * 当前在线服务器的流量相关的业务数
* @return * @return
@@ -245,6 +245,73 @@ public class EpsInitialTrafficDataServiceImpl implements EpsInitialTrafficDataSe
} }
}); });
} }
/**
* 批量保存数据到对应分表
* @param epsInitialTrafficData 流量数据表
*/
@Override
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
public void saveBatchRecoverTraffic(EpsInitialTrafficData epsInitialTrafficData) {
if (epsInitialTrafficData == null || epsInitialTrafficData.getDataList().isEmpty()) {
return;
}
// 内存去重(基于唯一键)
List<EpsInitialTrafficData> distinctList = epsInitialTrafficData.getDataList().stream()
.filter(Objects::nonNull)
.map(data -> {
EpsInitialTrafficData processed = new EpsInitialTrafficData();
BeanUtils.copyProperties(data, processed);
if (data.getCreateTime() == null) {
processed.setCreateTime(DateUtils.getNowDate());
}
return processed;
})
.collect(Collectors.collectingAndThen(
// 使用TreeSet按唯一键去重
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(
d -> String.join("|",
d.getClientId(),
d.getMac(),
d.getName(),
d.getCreateTime().toString()
)
))),
ArrayList::new
));
// 按表名分组
Map<String, List<EpsInitialTrafficData>> groupedData = distinctList.stream()
.map(data -> {
data.setTableName(TableRouterUtil.getTableName(
data.getCreateTime().toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
));
return data;
})
.collect(Collectors.groupingBy(
EpsInitialTrafficData::getTableName,
LinkedHashMap::new,
Collectors.toList()
));
// 分表插入(带冲突降级)
groupedData.forEach((tableName, list) -> {
try {
EpsInitialTrafficData batchData = new EpsInitialTrafficData();
BeanUtils.copyProperties(epsInitialTrafficData, batchData);
batchData.setTableName(tableName);
batchData.setDataList(list);
// 优先尝试批量插入
epsInitialTrafficDataMapper.batchInsertRecoverDetailTraffic(batchData);
} catch (Exception e) {
log.error("表 {} 插入失败", tableName, e);
throw new RuntimeException("数据入库失败", e);
}
});
}
/** /**
* 查询流量数据 * 查询流量数据
*/ */
@@ -259,6 +259,102 @@ public class EpsServerRevenueConfigServiceImpl implements IEpsServerRevenueConfi
return R.fail("数据保存失败:" + e.getMessage() + ",已成功保存" + successCount + ""); return R.fail("数据保存失败:" + e.getMessage() + ",已成功保存" + successCount + "");
} }
} }
/**
* 保存流量信息
* @param epsServerRevenueConfig
*/
@Override
public R<String> autoSaveServiceRecoverTrafficData(EpsServerRevenueConfig epsServerRevenueConfig) {
// 查询初始流量数据
EpsInitialTrafficData epsInitialTrafficData = new EpsInitialTrafficData();
epsInitialTrafficData.setStartTime(epsServerRevenueConfig.getStartTime());
epsInitialTrafficData.setEndTime(epsServerRevenueConfig.getEndTime());
List<EpsInitialTrafficData> dataList = epsInitialTrafficDataService.getAllTraficMsg(epsInitialTrafficData);
if (dataList == null || dataList.isEmpty()) {
return R.ok("没有需要处理的数据");
}
List<EpsInitialTrafficData> batchList = new ArrayList<>();
int batchSize = 1000; // 每批处理数量
int totalCount = 0;
int successCount = 0;
int batchNumber = 0;
try {
for (EpsInitialTrafficData initialTrafficData : dataList) {
// 根据clientId查询业务名称
RmResourceRegistration rmResourceRegistration = new RmResourceRegistration();
rmResourceRegistration.setClientId(initialTrafficData.getClientId());
List<RmResourceRegistration> registerLst = rmResourceRegistrationMapper.selectRmResourceRegistrationList(rmResourceRegistration);
if(registerLst != null && !registerLst.isEmpty()){
RmResourceRegistration registerMsg = registerLst.get(0);
// 赋值
if(registerMsg != null){
String businessName = registerMsg.getBusinessName();
if(businessName != null){
initialTrafficData.setBusinessName(businessName);
// 根据业务名称查询业务代码
EpsBusiness epsBusiness = epsBusinessMapper.selectEpsBusinessByName(businessName);
if(epsBusiness != null){
initialTrafficData.setBusinessId(epsBusiness.getId());
}
}
initialTrafficData.setServiceSn(registerMsg.getHardwareSn());
initialTrafficData.setRevenueMethod("1");
}
}
// id自增
initialTrafficData.setId(null);
batchList.add(initialTrafficData);
// 达到批次大小时保存
if (batchList.size() >= batchSize) {
batchNumber++;
totalCount += batchList.size();
epsInitialTrafficData.setDataList(batchList);
epsInitialTrafficDataService.saveBatchRecoverTraffic(epsInitialTrafficData);
log.info("第{}批流量数据批量入库成功,数据量:{}", batchNumber, batchList.size());
// 处理接口名称
processInterfaceNames(batchList);
successCount += batchList.size();
// 清空当前批次,准备下一批
batchList = new ArrayList<>();
}
}
// 处理最后一批不足1000条的数据
if (!batchList.isEmpty()) {
batchNumber++;
totalCount += batchList.size();
epsInitialTrafficData.setDataList(batchList);
epsInitialTrafficDataService.saveBatchRecoverTraffic(epsInitialTrafficData);
log.info("第{}批流量数据批量入库成功,数据量:{}", batchNumber, batchList.size());
// 处理最后一批的接口名称
processInterfaceNames(batchList);
successCount += batchList.size();
}
log.info("流量数据批量入库完成,总批次数:{},总数据量:{},成功数量:{}",
batchNumber, totalCount, successCount);
if (successCount == totalCount) {
return R.ok("数据保存成功,共处理" + successCount + "条数据");
} else {
return R.fail("数据保存部分成功,应处理" + totalCount + "条,实际成功" + successCount + "");
}
} catch (Exception e) {
log.error("流量数据入库失败,已处理批次:{},成功数量:{},当前批次数量:{},错误原因:{}",
batchNumber, successCount, batchList.size(), e.getMessage(), e);
return R.fail("数据保存失败:" + e.getMessage() + ",已成功保存" + successCount + "");
}
}
/** /**
* 当前在线服务器的流量相关的业务数 * 当前在线服务器的流量相关的业务数
* @return * @return
@@ -377,6 +377,91 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) )
</foreach> </foreach>
</insert> </insert>
<insert id="batchInsertRecoverDetailTraffic">
INSERT INTO ${tableName} (
id,
`name`,
`mac`,
`status`,
`type`,
ipV4,
`in_dropped`,
`out_dropped`,
`in_speed`,
`out_speed`,
`total_in_speed`,
`total_out_speed`,
`speed`,
`duplex`,
business_id,
business_name,
service_sn,
node_name,
revenue_method,
package_bandwidth,
create_time,
update_time,
create_by,
update_by,
client_id,
ipv4_in_speed,
ipv4_out_speed,
ipv6_in_speed,
ipv6_out_speed,
total_ipv4_in_speed,
total_ipv4_out_speed,
total_ipv6_in_speed,
total_ipv6_out_speed,
ipV6,
ping_dropped
) VALUES
<foreach collection="dataList" item="data" separator=",">
(
#{data.id,jdbcType=BIGINT},
#{data.name,jdbcType=VARCHAR},
#{data.mac,jdbcType=VARCHAR},
#{data.status,jdbcType=VARCHAR},
#{data.type,jdbcType=VARCHAR},
#{data.ipV4,jdbcType=VARCHAR},
#{data.inDropped,jdbcType=DECIMAL},
#{data.outDropped,jdbcType=DECIMAL},
#{data.inSpeed,jdbcType=VARCHAR},
#{data.outSpeed,jdbcType=VARCHAR},
#{data.totalInSpeed,jdbcType=VARCHAR},
#{data.totalOutSpeed,jdbcType=VARCHAR},
#{data.speed,jdbcType=VARCHAR},
#{data.duplex,jdbcType=VARCHAR},
#{data.businessId,jdbcType=VARCHAR},
#{data.businessName,jdbcType=VARCHAR},
#{data.serviceSn,jdbcType=VARCHAR},
#{data.nodeName,jdbcType=VARCHAR},
#{data.revenueMethod,jdbcType=VARCHAR},
#{data.packageBandwidth,jdbcType=DECIMAL},
#{data.createTime,jdbcType=TIMESTAMP},
#{data.updateTime,jdbcType=TIMESTAMP},
#{data.createBy,jdbcType=VARCHAR},
#{data.updateBy,jdbcType=VARCHAR},
#{data.clientId,jdbcType=VARCHAR},
#{data.ipv4InSpeed,jdbcType=VARCHAR},
#{data.ipv4OutSpeed,jdbcType=VARCHAR},
#{data.ipv6InSpeed,jdbcType=VARCHAR},
#{data.ipv6OutSpeed,jdbcType=VARCHAR},
#{data.totalIpv4InSpeed,jdbcType=VARCHAR},
#{data.totalIpv4OutSpeed,jdbcType=VARCHAR},
#{data.totalIpv6InSpeed,jdbcType=VARCHAR},
#{data.totalIpv6OutSpeed,jdbcType=VARCHAR},
#{data.ipV6,jdbcType=VARCHAR},
#{data.pingDropped,jdbcType=DECIMAL}
)
</foreach>
ON DUPLICATE KEY UPDATE
`in_speed` = IF(VALUES(`in_speed`) IS NOT NULL, VALUES(`in_speed`), `in_speed`),
`out_speed` = IF(VALUES(`out_speed`) IS NOT NULL, VALUES(`out_speed`), `out_speed`),
`ipv4_in_speed` = IF(VALUES(`ipv4_in_speed`) IS NOT NULL, VALUES(`ipv4_in_speed`), `ipv4_in_speed`),
`ipv4_out_speed` = IF(VALUES(`ipv4_out_speed`) IS NOT NULL, VALUES(`ipv4_out_speed`), `ipv4_out_speed`),
`ipv6_in_speed` = IF(VALUES(`ipv6_in_speed`) IS NOT NULL, VALUES(`ipv6_in_speed`), `ipv6_in_speed`),
`ipv6_out_speed` = IF(VALUES(`ipv6_out_speed`) IS NOT NULL, VALUES(`ipv6_out_speed`), `ipv6_out_speed`)
</insert>
<!-- 条件查询 --> <!-- 条件查询 -->
<select id="selectByCondition" resultType="EpsInitialTrafficData"> <select id="selectByCondition" resultType="EpsInitialTrafficData">
@@ -721,23 +721,31 @@ public class MessageHandler {
long millis = timestamp * 1000; long millis = timestamp * 1000;
Date createTime = new Date(millis / 1000 * 1000); // 去除毫秒 Date createTime = new Date(millis / 1000 * 1000); // 去除毫秒
String timeStr = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",createTime); String timeStr = DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss",createTime);
// 判断数据库中是否已存在数据 // 判断数据库中是否已存在数据
InitialBandwidthTraffic countQuery = new InitialBandwidthTraffic(); InitialBandwidthTraffic countQuery = new InitialBandwidthTraffic();
countQuery.setClientId(clientId); countQuery.setClientId(clientId);
countQuery.setCreateTime(createTime); countQuery.setCreateTime(createTime);
countQuery.setStartTime(timeStr); countQuery.setStartTime(timeStr);
int exitsCount = initialBandwidthTrafficService.countByClientIdAndTime(countQuery); int exitsCount = initialBandwidthTrafficService.countByClientIdAndTime(countQuery);
// 即使数据已存在,也需要处理临时表逻辑,确保后续计算正确
if(exitsCount > 0){ if(exitsCount > 0){
return; // 不直接返回,继续执行临时表处理逻辑
// 但跳过最终的数据入库操作
System.out.println("数据已存在,跳过入库操作,但继续处理临时表逻辑");
} }
// 创建比timestamp少5分钟的时间 // 创建比timestamp少5分钟的时间
long fiveMinutesEarlier = millis - (5 * 60 * 1000); // 减去5分钟的毫秒数 long fiveMinutesEarlier = millis - (5 * 60 * 1000); // 减去5分钟的毫秒数
Date fiveMinutesEarlierDate = new Date(fiveMinutesEarlier / 1000 * 1000); // 同样去除毫秒 Date fiveMinutesEarlierDate = new Date(fiveMinutesEarlier / 1000 * 1000); // 同样去除毫秒
// 查询临时表信息,计算实际流量值 // 查询临时表信息,计算实际流量值
InitialBandwidthTrafficTemp temp = new InitialBandwidthTrafficTemp(); InitialBandwidthTrafficTemp temp = new InitialBandwidthTrafficTemp();
temp.setCreateTime(fiveMinutesEarlierDate); temp.setCreateTime(fiveMinutesEarlierDate);
temp.setClientId(clientId); temp.setClientId(clientId);
List<InitialBandwidthTrafficTemp> tempList = initialBandwidthTrafficTempService.selectInitialBandwidthTrafficRecoverTempList(temp); List<InitialBandwidthTrafficTemp> tempList = initialBandwidthTrafficTempService.selectInitialBandwidthTrafficRecoverTempList(temp);
if(!tempList.isEmpty()){ if(!tempList.isEmpty()){
// 1. 构建快速查找的Map,使用MAC地址+网卡名称作为唯一键 // 1. 构建快速查找的Map,使用MAC地址+网卡名称作为唯一键
Map<String, InitialBandwidthTrafficTemp> tempMap = tempList.stream() Map<String, InitialBandwidthTrafficTemp> tempMap = tempList.stream()
@@ -834,7 +842,7 @@ public class MessageHandler {
delQuery.setClientId(clientId); delQuery.setClientId(clientId);
delQuery.setCreateTime(fiveMinutesEarlierDate); delQuery.setCreateTime(fiveMinutesEarlierDate);
initialBandwidthTrafficTempService.deleteTempMsgByClientIdAndTime(delQuery); initialBandwidthTrafficTempService.deleteTempMsgByClientIdAndTime(delQuery);
}else{ } else {
interfaces.forEach(iface -> { interfaces.forEach(iface -> {
iface.setClientId(clientId); iface.setClientId(clientId);
iface.setCreateTime(createTime); iface.setCreateTime(createTime);
@@ -855,19 +863,26 @@ public class MessageHandler {
iface.setIpv6OutSpeed(null); iface.setIpv6OutSpeed(null);
}); });
} }
InitialBandwidthTraffic data = new InitialBandwidthTraffic();
// 批量入库集合 // 只有在数据不存在时才执行入库操作
data.setList(interfaces); if (exitsCount == 0) {
// 临时表 用来计算流量速率 InitialBandwidthTraffic data = new InitialBandwidthTraffic();
initialBandwidthTrafficTempService.batchInsertServerRecoverTemp(interfaces); // 批量入库集合
// 初始流量数据入库 data.setList(interfaces);
initialBandwidthTrafficService.batchInsert(data); // 临时表 用来计算流量速率
EpsInitialTrafficDataRemote epsInitialTrafficDataRemote = new EpsInitialTrafficDataRemote(); initialBandwidthTrafficTempService.batchInsertServerRecoverTemp(interfaces);
epsInitialTrafficDataRemote.setStartTime(timeStr); // 初始流量数据入库
epsInitialTrafficDataRemote.setEndTime(timeStr); initialBandwidthTrafficService.batchInsertRecoverTraffic(data);
// 复制到业务初始库 EpsInitialTrafficDataRemote epsInitialTrafficDataRemote = new EpsInitialTrafficDataRemote();
remoteRevenueConfigService.autoSaveServiceTrafficData(epsInitialTrafficDataRemote, SecurityConstants.INNER); epsInitialTrafficDataRemote.setStartTime(timeStr);
}else{ epsInitialTrafficDataRemote.setEndTime(timeStr);
// 复制到业务初始库
remoteRevenueConfigService.autoSaveServiceRecoverTrafficData(epsInitialTrafficDataRemote, SecurityConstants.INNER);
} else {
// 数据已存在时,只更新临时表,确保后续计算正确
initialBandwidthTrafficTempService.batchInsertServerRecoverTemp(interfaces);
}
} else {
throw new RuntimeException("NET流量data数据为空"); throw new RuntimeException("NET流量data数据为空");
} }
} }
@@ -971,77 +986,77 @@ public class MessageHandler {
long timestamp = disks.get(0).getTimestamp(); long timestamp = disks.get(0).getTimestamp();
long millis = timestamp * 1000; long millis = timestamp * 1000;
Date createTime = new Date(millis / 1000 * 1000); Date createTime = new Date(millis / 1000 * 1000);
disks.forEach(disk -> {
disk.setClientId(clientId);
disk.setCreateTime(createTime);
});
// 关键:每个clientId有自己独立的key
// String diskCountKey = DISK_COUNT_PREFIX + clientId;
//
// // 1. 给这个客户端的所有磁盘次数+1
// Map<Object, Object> diskCountMap = redisTemplate.opsForHash().entries(diskCountKey);
// for (Map.Entry<Object, Object> entry : diskCountMap.entrySet()) {
// String diskName = (String) entry.getKey();
// String countStr = (String) entry.getValue();
//
// try {
// int count = Integer.parseInt(countStr) + 1;
// redisTemplate.opsForHash().put(diskCountKey, diskName, String.valueOf(count));
// } catch (NumberFormatException e) {
// redisTemplate.opsForHash().put(diskCountKey, diskName, "1");
// }
// }
//
// // 2. 处理本次上报的磁盘
// Set<String> reportedDisks = new HashSet<>();
// disks.forEach(disk -> { // disks.forEach(disk -> {
// String diskName = disk.getName();
// reportedDisks.add(diskName);
//
// // 本次上报的磁盘,次数重置为0
// redisTemplate.opsForHash().put(diskCountKey, diskName, "0");
//
// disk.setClientId(clientId); // disk.setClientId(clientId);
// disk.setCreateTime(createTime); // disk.setCreateTime(createTime);
// }); // });
// // 关键:每个clientId有自己独立的key
// // 3. 检查次数≥3的磁盘 String diskCountKey = DISK_COUNT_PREFIX + clientId;
// diskCountMap = redisTemplate.opsForHash().entries(diskCountKey);
// List<String> disksToRemove = new ArrayList<>(); // 1. 给这个客户端的所有磁盘次数+1
// Map<Object, Object> diskCountMap = redisTemplate.opsForHash().entries(diskCountKey);
// for (Map.Entry<Object, Object> entry : diskCountMap.entrySet()) { for (Map.Entry<Object, Object> entry : diskCountMap.entrySet()) {
// String diskName = (String) entry.getKey(); String diskName = (String) entry.getKey();
// String countStr = (String) entry.getValue(); String countStr = (String) entry.getValue();
//
// try { try {
// int count = Integer.parseInt(countStr); int count = Integer.parseInt(countStr) + 1;
// // 如果次数≥3且本次没上报 redisTemplate.opsForHash().put(diskCountKey, diskName, String.valueOf(count));
// if (count >= 3 && !reportedDisks.contains(diskName)) { } catch (NumberFormatException e) {
// AllDiskName allDiskName = new AllDiskName(); redisTemplate.opsForHash().put(diskCountKey, diskName, "1");
// allDiskName.setStatus(0); }
// allDiskName.setClientId(clientId); }
// allDiskName.setName(diskName);
// allDiskNameService.updateAllDiskName(allDiskName); // 2. 处理本次上报的磁盘
// disksToRemove.add(diskName); Set<String> reportedDisks = new HashSet<>();
// // 磁盘缺失,触发告警 disks.forEach(disk -> {
// RmAlarmLog rmAlarmLog = new RmAlarmLog(); String diskName = disk.getName();
// rmAlarmLog.setClientId(clientId); reportedDisks.add(diskName);
// rmAlarmLog.setAlarmTime(DateUtils.getNowDate());
// rmAlarmLog.setAlarmType(AlarmTypeEnum.磁盘缺失.getCode()); // 本次上报的磁盘,次数重置为0
// rmAlarmLog.setAlarmContent("服务器" + clientId + "磁盘缺失,磁盘名称:" + diskName); redisTemplate.opsForHash().put(diskCountKey, diskName, "0");
// rmAlarmLogService.insertRmAlarmLog(rmAlarmLog);
// sendAlarmPushUtil.sendAlarmPush(rmAlarmLog, AlarmTypeEnum.磁盘缺失.getMsg()); disk.setClientId(clientId);
// disk.setCreateTime(createTime);
// } });
// } catch (NumberFormatException e) {
// disksToRemove.add(diskName); // 3. 检查次数≥3的磁盘
// } diskCountMap = redisTemplate.opsForHash().entries(diskCountKey);
// } List<String> disksToRemove = new ArrayList<>();
//
// // 4. 删除已处理的磁盘记录 for (Map.Entry<Object, Object> entry : diskCountMap.entrySet()) {
// if (!disksToRemove.isEmpty()) { String diskName = (String) entry.getKey();
// redisTemplate.opsForHash().delete(diskCountKey, disksToRemove.toArray()); String countStr = (String) entry.getValue();
// }
try {
int count = Integer.parseInt(countStr);
// 如果次数≥3且本次没上报
if (count >= 3 && !reportedDisks.contains(diskName)) {
AllDiskName allDiskName = new AllDiskName();
allDiskName.setStatus(0);
allDiskName.setClientId(clientId);
allDiskName.setName(diskName);
allDiskNameService.updateAllDiskName(allDiskName);
disksToRemove.add(diskName);
// 磁盘缺失,触发告警
RmAlarmLog rmAlarmLog = new RmAlarmLog();
rmAlarmLog.setClientId(clientId);
rmAlarmLog.setAlarmTime(DateUtils.getNowDate());
rmAlarmLog.setAlarmType(AlarmTypeEnum.磁盘缺失.getCode());
rmAlarmLog.setAlarmContent("服务器" + clientId + "磁盘缺失,磁盘名称:" + diskName);
rmAlarmLogService.insertRmAlarmLog(rmAlarmLog);
sendAlarmPushUtil.sendAlarmPush(rmAlarmLog, AlarmTypeEnum.磁盘缺失.getMsg());
}
} catch (NumberFormatException e) {
disksToRemove.add(diskName);
}
}
// 4. 删除已处理的磁盘记录
if (!disksToRemove.isEmpty()) {
redisTemplate.opsForHash().delete(diskCountKey, disksToRemove.toArray());
}
// 5. 数据入库 // 5. 数据入库
initialDiskInfoService.batchInsertInitialDiskInfo(disks, createTime); initialDiskInfoService.batchInsertInitialDiskInfo(disks, createTime);
@@ -1961,7 +1976,7 @@ public class MessageHandler {
* 查询IP地址归属地信息,返回运营商和省份 * 查询IP地址归属地信息,返回运营商和省份
*/ */
private Map<String, String> queryIpLocation(String ip) { private Map<String, String> queryIpLocation(String ip) {
String apiUrl = "http://172.16.15.51:10000/?ip=" + ip; String apiUrl = "http://172.16.15.103:10000/?ip=" + ip;
CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpClient httpClient = HttpClients.createDefault();
HttpGet httpGet = new HttpGet(apiUrl); HttpGet httpGet = new HttpGet(apiUrl);
@@ -71,6 +71,7 @@ public interface InitialBandwidthTrafficMapper
* @param data 流量数据实体类 * @param data 流量数据实体类
*/ */
int batchInsert(InitialBandwidthTraffic data); int batchInsert(InitialBandwidthTraffic data);
int batchInsertRecoverTraffic(InitialBandwidthTraffic data);
/** /**
* 网络接口基础信息 * 网络接口基础信息
* @param initialBandwidthTraffic * @param initialBandwidthTraffic
@@ -71,6 +71,7 @@ public interface IInitialBandwidthTrafficService
* @param data 流量数据 * @param data 流量数据
*/ */
void batchInsert(InitialBandwidthTraffic data); void batchInsert(InitialBandwidthTraffic data);
void batchInsertRecoverTraffic(InitialBandwidthTraffic data);
/** /**
* 网络接口基础信息 * 网络接口基础信息
* @param initialBandwidthTraffic * @param initialBandwidthTraffic
@@ -183,6 +183,56 @@ public class InitialBandwidthTrafficServiceImpl implements IInitialBandwidthTraf
} }
}); });
} }
/**
* 保存多条数据到对应分表
* @param initialBandwidthTraffic 流量数据
*/
@Override
@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
public void batchInsertRecoverTraffic(InitialBandwidthTraffic initialBandwidthTraffic) {
if (initialBandwidthTraffic == null) {
return;
}
List<InitialBandwidthTraffic> dataList = initialBandwidthTraffic.getList();
if (dataList.isEmpty()){
return;
}
// 按表名分组批量插入
Map<String, List<InitialBandwidthTraffic>> groupedData = dataList.stream()
.map(data -> {
try {
InitialBandwidthTraffic processed = new InitialBandwidthTraffic();
BeanUtils.copyProperties(data,processed);
if (data.getCreateTime() == null) {
data.setCreateTime(DateUtils.getNowDate());
}
LocalDateTime createTime = data.getCreateTime().toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();
processed.setTableName(TableRouterUtil.getTableName(createTime));
return processed;
} catch (Exception e){
log.error("数据处理失败",e.getMessage());
return null;
}
}).collect(Collectors.groupingBy(
InitialBandwidthTraffic::getTableName,
LinkedHashMap::new, // 保持插入顺序
Collectors.toList()));
groupedData.forEach((tableName, list) -> {
try {
InitialBandwidthTraffic data = new InitialBandwidthTraffic();
BeanUtils.copyProperties(initialBandwidthTraffic,data);
data.setTableName(tableName);
data.setList(list);
initialBandwidthTrafficMapper.batchInsertRecoverTraffic(data);
} catch (Exception e) {
log.error("表{}插入失败", tableName, e);
throw new RuntimeException("批量插入失败", e);
}
});
}
/** /**
* 网络接口基础信息 * 网络接口基础信息
* @param initialBandwidthTraffic * @param initialBandwidthTraffic
@@ -143,7 +143,33 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
) )
</foreach> </foreach>
</insert> </insert>
<insert id="batchInsertRecoverTraffic" parameterType="InitialBandwidthTraffic">
INSERT INTO ${tableName} (
`name`, `mac`, `status`, `type`, ipV4, `in_dropped`, `out_dropped`,
`in_speed`, `out_speed`, `total_in_speed`, `total_out_speed`, duplex, speed,
create_by, update_by, client_id, create_time,
ipv4_in_speed, ipv4_out_speed, ipv6_in_speed, ipv6_out_speed,
total_ipv4_in_speed, total_ipv4_out_speed, total_ipv6_in_speed, total_ipv6_out_speed,
ipV6, ping_dropped
) VALUES
<foreach collection="list" item="item" separator=",">
(
#{item.name}, #{item.mac}, #{item.status}, #{item.type}, #{item.ipV4}, #{item.inDropped}, #{item.outDropped},
#{item.inSpeed}, #{item.outSpeed}, #{item.totalInSpeed}, #{item.totalOutSpeed}, #{item.duplex}, #{item.speed},
#{item.createBy}, #{item.updateBy}, #{item.clientId}, #{item.createTime},
#{item.ipv4InSpeed}, #{item.ipv4OutSpeed}, #{item.ipv6InSpeed}, #{item.ipv6OutSpeed},
#{item.totalIpv4InSpeed}, #{item.totalIpv4OutSpeed}, #{item.totalIpv6InSpeed}, #{item.totalIpv6OutSpeed},
#{item.ipV6}, #{item.pingDropped}
)
</foreach>
ON DUPLICATE KEY UPDATE
`in_speed` = IF(VALUES(`in_speed`) IS NOT NULL, VALUES(`in_speed`), `in_speed`),
`out_speed` = IF(VALUES(`out_speed`) IS NOT NULL, VALUES(`out_speed`), `out_speed`),
`ipv4_in_speed` = IF(VALUES(`ipv4_in_speed`) IS NOT NULL, VALUES(`ipv4_in_speed`), `ipv4_in_speed`),
`ipv4_out_speed` = IF(VALUES(`ipv4_out_speed`) IS NOT NULL, VALUES(`ipv4_out_speed`), `ipv4_out_speed`),
`ipv6_in_speed` = IF(VALUES(`ipv6_in_speed`) IS NOT NULL, VALUES(`ipv6_in_speed`), `ipv6_in_speed`),
`ipv6_out_speed` = IF(VALUES(`ipv6_out_speed`) IS NOT NULL, VALUES(`ipv6_out_speed`), `ipv6_out_speed`)
</insert>
<select id="getNetInterfaceDetailsMsg" parameterType="InitialBandwidthTraffic" resultType="InitialBandwidthTraffic"> <select id="getNetInterfaceDetailsMsg" parameterType="InitialBandwidthTraffic" resultType="InitialBandwidthTraffic">
select select
id, id,
@@ -229,6 +255,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<where> <where>
<if test="clientId != null and clientId != ''"> and client_id = #{clientId}</if> <if test="clientId != null and clientId != ''"> and client_id = #{clientId}</if>
<if test="startTime != null"> and create_time = #{startTime}</if> <if test="startTime != null"> and create_time = #{startTime}</if>
and in_speed is not null
</where> </where>
</select> </select>
</mapper> </mapper>