1、优化子网卡流量图形展示。

2、优化接口名称存储逻辑,减少死锁。
3、增加cpu利用率内存利用率字段。
This commit is contained in:
gaoyutao
2025-12-17 18:18:19 +08:00
parent 597b5dad01
commit 343028ade5
12 changed files with 286 additions and 95 deletions
@@ -17,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
@@ -153,6 +154,20 @@ public class RmResourceRegistrationController extends BaseController
List<RmResourceRegistration> list = rmResourceRegistrationService.selectRmResourceRegistrationList(rmResourceRegistration);
return success(list);
}
@GetMapping("/getAlarmFlag")
public AjaxResult getAlarmFlag()
{
List<RmResourceRegistration> list = rmResourceRegistrationService.selectRmResourceRegistrationList(new RmResourceRegistration());
for (RmResourceRegistration item : list) {
boolean isAlarm = (item.getCpuUtil() != null && item.getCpuUtil().compareTo(BigDecimal.valueOf(80)) >= 0) ||
(item.getMemUtil() != null && item.getMemUtil().compareTo(BigDecimal.valueOf(60)) >= 0);
if (isAlarm) {
return success(true); // 只要有一个告警就返回
}
}
return success(false);
}
/**
* 自动注册服务器
@@ -81,5 +81,7 @@ public class AllInterfaceName extends BaseEntity
private String label;
/** 是否需要展开 */
private boolean expand;
/** 是否业务网卡 */
private boolean businessFlag;
}
@@ -257,4 +257,10 @@ public class RmResourceRegistration extends BaseEntity
private String bandwidthRate;
/** 昨日95值排序 1正序 2倒叙 3不排序 */
private Integer bandwidthResultSort;
/** cpu利用率 */
private BigDecimal cpuUtil;
/** 内存使用率 */
private BigDecimal memUtil;
/** 是否告警 */
private boolean alarmFlag;
}
@@ -122,4 +122,8 @@ public interface RmResourceRegistrationMapper
*/
int countChildNetwork(@Param("clientId") String clientId,
@Param("interfaceName") String interfaceName);
List<RmResourceRegistration> getCpuUtil(@Param("clientIdsStr") String clientIdsStr);
List<RmResourceRegistration> getMemUtil(@Param("clientIdsStr") String clientIdsStr);
}
@@ -15,7 +15,9 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
@@ -58,6 +60,7 @@ public class AllInterfaceNameServiceImpl implements IAllInterfaceNameService
if (allInterfaceNameList == null || allInterfaceNameList.isEmpty()) {
return allInterfaceNameList;
}
// 用于存储非子网卡的接口
List<AllInterfaceName> nonSubInterfaces = new ArrayList<>();
for (AllInterfaceName interfaceName : allInterfaceNameList) {
@@ -77,21 +80,31 @@ public class AllInterfaceNameServiceImpl implements IAllInterfaceNameService
if (nonSubInterfaces.isEmpty()) {
return nonSubInterfaces;
}
// 缓存匹配结果,避免重复计算
Map<AllInterfaceName, Boolean> matchStatusMap = new HashMap<>();
for (AllInterfaceName interfaceName : nonSubInterfaces) {
boolean isMatched = isInterfaceMatched(interfaceName);
matchStatusMap.put(interfaceName, isMatched);
// 只设置服务器类型的businessFlag
if ("1".equals(interfaceName.getResourceType())) {
interfaceName.setBusinessFlag(isMatched);
}
}
// 使用自定义排序
return nonSubInterfaces.stream()
.sorted((a, b) -> {
// 根据实际业务逻辑判断是否匹配
// 这里用接口名不为null且包含特定字符作为示例
boolean aMatched = a.getInterfaceName() != null && a.getInterfaceName().contains("eth");
boolean bMatched = b.getInterfaceName() != null && b.getInterfaceName().contains("eth");
boolean aMatched = matchStatusMap.get(a);
boolean bMatched = matchStatusMap.get(b);
// 匹配的排在前面(返回-1),不匹配的排在后面(返回1)
if (aMatched && !bMatched) {
return -1;
} else if (!aMatched && bMatched) {
return 1;
} else {
return 0; // 都匹配或都不匹配,保持原有顺序
return 0;
}
})
.collect(Collectors.toList());
@@ -647,6 +647,9 @@ public class EpsInitialTrafficDataServiceImpl implements EpsInitialTrafficDataSe
}
deoloyDevice = clientIds.toString();
}
if(deoloyDevice == null){
return null;
}
String clientIds = deoloyDevice.replace("\n",",");
EpsInitialTrafficData queryParam = new EpsInitialTrafficData();
queryParam.setStartTime(startTime);
@@ -16,6 +16,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
@@ -256,34 +257,17 @@ public class EpsServerRevenueConfigServiceImpl implements IEpsServerRevenueConfi
}
if (!records.isEmpty()) {
try {
allInterfaceNameMapper.batchInsert(records);
log.info("批量处理接口名称完成,记录数: {}", records.size());
}catch (Exception e){
// 处理死锁异常
if (isDeadlockException(e)) {
// 找到第一个非null的clientId
String deadlockClientId = records.stream()
.map(AllInterfaceName::getClientId)
.filter(StringUtils::isNotBlank)
.findFirst()
.orElse("unknown");
log.error("检测到死锁,涉及的clientId: {}", deadlockClientId);
} else {
// 非死锁异常,重新抛出
log.error("批量处理接口名称失败:{}", e.getMessage());
}
}
// 排序防止死锁
records.sort(Comparator
.comparing(AllInterfaceName::getInterfaceName)
.thenComparing(AllInterfaceName::getClientId)
.thenComparing(AllInterfaceName::getSwitchIp)
.thenComparing(AllInterfaceName::getResourceType));
allInterfaceNameMapper.batchInsert(records);
log.info("批量处理完成,记录数: {}", records.size());
}
}
private boolean isDeadlockException(Exception e) {
String message = e.getMessage();
return message != null && (
message.contains("deadlock") ||
message.contains("Deadlock") ||
message.contains("1213") // MySQL死锁错误码
);
}
private boolean isValidData(EpsInitialTrafficData data) {
return StringUtils.isNotBlank(data.getName())
&& StringUtils.isNotBlank(data.getMac())
@@ -368,24 +368,15 @@ public class InitialSwitchInfoDetailsServiceImpl implements IInitialSwitchInfoDe
}
if (!records.isEmpty()) {
try {
allInterfaceNameMapper.batchInsert(records);
log.info("批量处理交换机接口名称完成,记录数: {}", records.size());
}catch (Exception e){
// 处理死锁异常
if (isDeadlockException(e)) {
// 找到第一个非null的clientId
String deadlockClientId = records.stream()
.map(AllInterfaceName::getClientId)
.filter(StringUtils::isNotBlank)
.findFirst()
.orElse("unknown");
log.error("检测到死锁,涉及的clientId: {}", deadlockClientId);
} else {
// 非死锁异常,重新抛出
log.error("批量处理交换机接口名称失败:{}", e.getMessage());
}
}
// 排序防止死锁
records.sort(Comparator
.comparing(AllInterfaceName::getInterfaceName)
.thenComparing(AllInterfaceName::getClientId)
.thenComparing(AllInterfaceName::getSwitchIp)
.thenComparing(AllInterfaceName::getResourceType));
allInterfaceNameMapper.batchInsert(records);
log.info("批量处理完成,记录数: {}", records.size());
}
}
private boolean isDeadlockException(Exception e) {
@@ -25,6 +25,7 @@ import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import static com.tongran.common.core.utils.PageUtils.startPage;
@@ -128,7 +129,6 @@ public class RmResourceRegistrationServiceImpl implements IRmResourceRegistratio
// 3. 内存分页
int total = filteredList.size();
// 注意:这里要用copy,因为后续要修改数据
List<RmResourceRegistration> pageList = applyPagination(filteredList, pageNum, pageSize);
List<RmResourceRegistration> currentPageData = new ArrayList<>(pageList);
@@ -255,12 +255,51 @@ public class RmResourceRegistrationServiceImpl implements IRmResourceRegistratio
RmResourceRegistration::getBandwidthResult,
Comparator.nullsLast(Comparator.reverseOrder())
);
} else if (sortType == 4) { // 告警优先排序
comparator = (a, b) -> {
// 设置告警标志
boolean aAlarm = isAlarm(a);
boolean bAlarm = isAlarm(b);
a.setAlarmFlag(aAlarm);
b.setAlarmFlag(bAlarm);
// 告警优先级最高
if (aAlarm && !bAlarm) return -1;
if (!aAlarm && bAlarm) return 1;
if (aAlarm && bAlarm) {
// 告警内按最大资源使用率倒序
BigDecimal aMax = getMaxUtilization(a);
BigDecimal bMax = getMaxUtilization(b);
if (aMax == null && bMax == null) return 0;
if (aMax == null) return 1;
if (bMax == null) return -1;
return bMax.compareTo(aMax);
}
return 0;
};
}
if (comparator != null) {
list.sort(comparator);
}
}
private boolean isAlarm(RmResourceRegistration item) {
return (item.getCpuUtil() != null && item.getCpuUtil().compareTo(BigDecimal.valueOf(80)) >= 0) ||
(item.getMemUtil() != null && item.getMemUtil().compareTo(BigDecimal.valueOf(60)) >= 0);
}
private BigDecimal getMaxUtilization(RmResourceRegistration item) {
BigDecimal max = BigDecimal.ZERO;
if (item.getCpuUtil() != null && item.getCpuUtil().compareTo(max) > 0) {
max = item.getCpuUtil();
}
if (item.getMemUtil() != null && item.getMemUtil().compareTo(max) > 0) {
max = item.getMemUtil();
}
return max.equals(BigDecimal.ZERO) ? null : max;
}
/**
* 内存分页
*/
@@ -286,64 +325,92 @@ public class RmResourceRegistrationServiceImpl implements IRmResourceRegistratio
}
long startTime = System.currentTimeMillis();
// 设置每批大小
int batchSize = 200;
int totalBatches = (int) Math.ceil((double) pageList.size() / batchSize);
for (int batchNum = 0; batchNum < totalBatches; batchNum++) {
int fromIndex = batchNum * batchSize;
int toIndex = Math.min(fromIndex + batchSize, pageList.size());
List<RmResourceRegistration> batchList = pageList.subList(fromIndex, toIndex);
// 收集当前批次需要查询的clientId
String clientIdsStr = batchList.stream()
String clientIdsStr = batchList.parallelStream()
.map(RmResourceRegistration::getClientId)
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.joining(","));
if (StringUtils.isBlank(clientIdsStr)) {
continue;
}
try {
// 使用批量查询接口
RmNetworkInterfaceRemote queryParam = new RmNetworkInterfaceRemote();
queryParam.setClientIds(clientIdsStr);
queryParam.setNewFlag(1);
// 并行查询
CompletableFuture<List<RmResourceRegistration>> cpuFuture = CompletableFuture
.supplyAsync(() -> rmResourceRegistrationMapper.getCpuUtil(clientIdsStr));
R<List<RmNetworkInterfaceRemote>> result = remoteRocketMqService.getNetworkInterfaceList(queryParam, SecurityConstants.INNER);
CompletableFuture<List<RmResourceRegistration>> memFuture = CompletableFuture
.supplyAsync(() -> rmResourceRegistrationMapper.getMemUtil(clientIdsStr));
if (result == null || result.getData() == null || result.getData().isEmpty()) {
continue;
}
CompletableFuture<List<RmNetworkInterfaceRemote>> networkFuture = CompletableFuture
.supplyAsync(() -> {
RmNetworkInterfaceRemote queryParam = new RmNetworkInterfaceRemote();
queryParam.setClientIds(clientIdsStr);
queryParam.setNewFlag(1);
R<List<RmNetworkInterfaceRemote>> result = remoteRocketMqService.getNetworkInterfaceList(queryParam, SecurityConstants.INNER);
return result != null ? result.getData() : Collections.emptyList();
});
List<RmNetworkInterfaceRemote> networkList = result.getData();
CompletableFuture.allOf(cpuFuture, memFuture, networkFuture).join();
List<RmResourceRegistration> cpuUtilList = cpuFuture.get();
List<RmResourceRegistration> memUtilList = memFuture.get();
List<RmNetworkInterfaceRemote> networkList = networkFuture.get();
// 构建查找Map
Map<String, BigDecimal> cpuUtilMap = cpuUtilList.stream()
.filter(item -> item.getClientId() != null && item.getCpuUtil() != null)
.collect(Collectors.toMap(
RmResourceRegistration::getClientId,
RmResourceRegistration::getCpuUtil
));
Map<String, BigDecimal> memUtilMap = memUtilList.stream()
.filter(item -> item.getClientId() != null && item.getMemUtil() != null)
.collect(Collectors.toMap(
RmResourceRegistration::getClientId,
RmResourceRegistration::getMemUtil
));
// 按clientId分组
Map<String, List<RmNetworkInterfaceRemote>> networkMap = networkList.stream()
.filter(Objects::nonNull)
.filter(item -> item.getClientId() != null)
.collect(Collectors.groupingBy(RmNetworkInterfaceRemote::getClientId));
// 批量设置当前批次
for (RmResourceRegistration registration : batchList) {
// 并行处理
batchList.parallelStream().forEach(registration -> {
String clientId = registration.getClientId();
if (clientId != null) {
BigDecimal cpuUtil = cpuUtilMap.get(clientId);
if (cpuUtil != null) {
registration.setCpuUtil(cpuUtil);
}
BigDecimal memUtil = memUtilMap.get(clientId);
if (memUtil != null) {
registration.setMemUtil(memUtil);
}
List<RmNetworkInterfaceRemote> clientNetworks = networkMap.get(clientId);
if (clientNetworks != null && !clientNetworks.isEmpty()) {
setNetWorkMsgWithNetworkList(registration, clientNetworks);
}
}
}
});
} catch (Exception e) {
log.error("第{}批查询网络信息异常", batchNum + 1, e);
log.error("第{}批查询资源信息异常", batchNum + 1, e);
}
// 添加小延迟,避免对下游服务造成压力
if (batchNum < totalBatches - 1) {
try {
Thread.sleep(10);
@@ -352,6 +419,8 @@ public class RmResourceRegistrationServiceImpl implements IRmResourceRegistratio
}
}
}
log.info("批量设置资源信息完成,耗时: {}ms", System.currentTimeMillis() - startTime);
}
/**
* 使用批量查询的结果设置网络信息
@@ -446,6 +515,16 @@ public class RmResourceRegistrationServiceImpl implements IRmResourceRegistratio
*/
public void setNetWorkMsg(RmResourceRegistration registration) {
String clientId = registration.getClientId();
// 根据clientId查询cpu利用率
List<RmResourceRegistration> cpuUtilList = rmResourceRegistrationMapper.getCpuUtil(clientId);
// 根据clientId查询mem利用率
List<RmResourceRegistration> memUtilList = rmResourceRegistrationMapper.getMemUtil(clientId);
if(cpuUtilList != null && !cpuUtilList.isEmpty()){
registration.setCpuUtil(cpuUtilList.get(0).getCpuUtil());
}
if(memUtilList != null && !memUtilList.isEmpty()){
registration.setMemUtil(memUtilList.get(0).getMemUtil());
}
// 根据clientId查询网卡信息
RmNetworkInterfaceRemote queryParam = new RmNetworkInterfaceRemote();
queryParam.setClientId(clientId);
@@ -279,4 +279,42 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select count(1) from rm_network_interface_child
where client_id = #{clientId} and parent_interface = #{interfaceName}
</select>
<select id="getCpuUtil" resultType="RmResourceRegistration">
SELECT
d.client_id as clientId,
d.uti as cpuUtil
FROM initial_cpu_info d
INNER JOIN (
SELECT
client_id,
MAX(create_time) as latest_time
FROM initial_cpu_info
WHERE client_id in
<foreach collection="clientIdsStr.split(',')" item="clientId" open="(" separator="," close=")">
#{clientId}
</foreach>
GROUP BY client_id
) latest ON d.client_id = latest.client_id
AND d.create_time = latest.latest_time
</select>
<select id="getMemUtil" resultType="RmResourceRegistration">
SELECT
d.client_id as clientId,
ROUND(d.collect_value, 1) as memUtil
FROM initial_system_other_collect_data d
INNER JOIN (
SELECT
client_id,
MAX(create_time) as max_time
FROM initial_system_other_collect_data
WHERE collect_type='memoryUtilizationCollect'
AND client_id in
<foreach collection="clientIdsStr.split(',')" item="clientId" open="(" separator="," close=")">
#{clientId}
</foreach>
GROUP BY client_id
) latest ON d.client_id = latest.client_id
AND d.create_time = latest.max_time
AND d.collect_type='memoryUtilizationCollect'
</select>
</mapper>