mtr监控策略初版
This commit is contained in:
@@ -9,9 +9,9 @@
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.tongran.agent</groupId>
|
||||
<artifactId>tr-agent-client</artifactId>
|
||||
<artifactId>tr-mtragent-client</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
<name>tr-agent-client</name>
|
||||
<name>tr-mtragent-client</name>
|
||||
<description>tr-agent-client</description>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -56,6 +56,7 @@ public class GlobalConfig {
|
||||
public static long SCRIPT_TIME = 0L;
|
||||
public static long VERSION_TIME = 0L;
|
||||
public static long ROUTE_TIME = 0L;
|
||||
public static String MTRPOLICYMSG = "";
|
||||
/**
|
||||
* 采集标识
|
||||
*/
|
||||
|
||||
@@ -67,6 +67,8 @@ public enum MsgEnum {
|
||||
|
||||
Agent版本更新应答("AGENT_VERSION_UPDATE_RSP"),
|
||||
|
||||
MTR探测上报("MTR_DETECT"),
|
||||
|
||||
多网IP探测上报("NETWORK_DETECT");
|
||||
|
||||
private String value;
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.tongran.agent.client.core.eo;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* mtr策略信息
|
||||
*/
|
||||
@Data
|
||||
public class MtrPolicyConfigEO {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** 主键ID */
|
||||
private Long id;
|
||||
|
||||
/** 策略名称 */
|
||||
private String policyName;
|
||||
|
||||
/** 优先级 */
|
||||
private Long priority;
|
||||
|
||||
/** MTR客户端ID */
|
||||
private String mtrClientId;
|
||||
|
||||
/** 服务器集合(换行符分割) */
|
||||
private String serverGroup;
|
||||
/** 探测目标ip集合 */
|
||||
private String serveripGroup;
|
||||
|
||||
/** 是否探测(0-否,1-是) */
|
||||
private Long probeFlag;
|
||||
|
||||
/** 开始时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date startTime;
|
||||
|
||||
/** 结束时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date endTime;
|
||||
|
||||
/** 探测频率(秒) */
|
||||
private Long probeFrequency;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.tongran.agent.client.core.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class MtrVO {
|
||||
private String targetIp; // 目标IP
|
||||
private Long policyId; // 策略ID
|
||||
private double firstLossPercent; // 第一次探测丢包率
|
||||
private double finalLossPercent; // 最终丢包率
|
||||
private long timestamp; // 探测时间戳
|
||||
private boolean hasRetry; // 是否重试
|
||||
private String errorMsg; // 错误信息
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import com.alibaba.fastjson2.JSONObject;
|
||||
import com.tongran.agent.client.core.config.ApplicationProperties;
|
||||
import com.tongran.agent.client.core.config.GlobalConfig;
|
||||
import com.tongran.agent.client.core.enums.MsgEnum;
|
||||
import com.tongran.agent.client.core.eo.MtrPolicyConfigEO;
|
||||
import com.tongran.agent.client.core.session.SessionManager;
|
||||
import com.tongran.agent.client.core.vo.*;
|
||||
import com.tongran.agent.client.netty.MultiTargetNettyClient;
|
||||
@@ -59,6 +60,7 @@ public class BusinessTasks {
|
||||
private final AtomicInteger registerTask = new AtomicInteger(0);
|
||||
private final AtomicInteger connectionTask = new AtomicInteger(0);
|
||||
private final AtomicInteger networkDetectTask = new AtomicInteger(0);
|
||||
private final AtomicInteger mtrTask = new AtomicInteger(0);
|
||||
|
||||
|
||||
|
||||
@@ -108,6 +110,9 @@ public class BusinessTasks {
|
||||
@Resource
|
||||
private AgentService agentService;
|
||||
|
||||
@Resource
|
||||
private MtrService mtrService;
|
||||
|
||||
/**
|
||||
* 任务1:心跳上报任务
|
||||
*/
|
||||
@@ -900,6 +905,55 @@ public class BusinessTasks {
|
||||
AssertLog.info("发送多网IP探测定时任务执行 - task #{} completed", count);
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务30:MTR网络探测任务
|
||||
*/
|
||||
@Async("taskExecutor")
|
||||
public void mtrTask() {
|
||||
long timestamp = AgentUtil.roundMinutes(); // 使用5分钟整点时间
|
||||
int count = mtrTask.incrementAndGet();
|
||||
AssertLog.info("MTR网络探测定时任务执行 - 时间: {},task #{}", LocalDateTime.now(), count);
|
||||
|
||||
try {
|
||||
// 检查当前是否有有效的MTR策略
|
||||
if (StringUtils.isBlank(GlobalConfig.MTRPOLICYMSG)) {
|
||||
AssertLog.info("没有MTR策略配置,跳过本次执行");
|
||||
return;
|
||||
}
|
||||
|
||||
// 解析策略
|
||||
List<MtrPolicyConfigEO> mtrPolicyConfigEOList = JSON.parseArray(GlobalConfig.MTRPOLICYMSG, MtrPolicyConfigEO.class);
|
||||
if (CollectionUtil.isEmpty(mtrPolicyConfigEOList)) {
|
||||
AssertLog.info("MTR策略列表为空,跳过本次执行");
|
||||
return;
|
||||
}
|
||||
|
||||
// 判定客户端与服务端是否连接
|
||||
if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) {
|
||||
// 执行MTR探测并获取结果
|
||||
String data = "";
|
||||
List<MtrVO> list = mtrService.mtrList(timestamp, mtrPolicyConfigEOList);
|
||||
if (CollectionUtil.isNotEmpty(list)) {
|
||||
data = JSONArray.toJSONString(list);
|
||||
|
||||
// 发送MTR探测结果
|
||||
Message message = Message.builder()
|
||||
.clientId(GlobalConfig.CLIENT_ID)
|
||||
.dataType(MsgEnum.MTR探测上报.getValue())
|
||||
.data(data)
|
||||
.build();
|
||||
sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message);
|
||||
AssertLog.info("发送MTR探测信息包,结果数量: {}", list.size());
|
||||
} else {
|
||||
AssertLog.info("本次MTR探测无有效结果");
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("MTR定时任务执行异常", e);
|
||||
}
|
||||
|
||||
AssertLog.info("MTR网络探测定时任务执行 - task #{} completed", count);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.tongran.agent.client.service;
|
||||
|
||||
import com.tongran.agent.client.core.eo.MtrPolicyConfigEO;
|
||||
import com.tongran.agent.client.core.vo.MtrVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MtrService {
|
||||
List<MtrVO> mtrList(long timestamp, List<MtrPolicyConfigEO> mtrPolicyConfigEOList);
|
||||
}
|
||||
@@ -9,8 +9,10 @@ import com.tongran.agent.client.core.config.GlobalConfig;
|
||||
import com.tongran.agent.client.core.enums.MsgEnum;
|
||||
import com.tongran.agent.client.core.eo.AgentVersionUpdateEO;
|
||||
import com.tongran.agent.client.core.eo.CollectEO;
|
||||
import com.tongran.agent.client.core.eo.MtrPolicyConfigEO;
|
||||
import com.tongran.agent.client.core.eo.ScriptPolicyEO;
|
||||
import com.tongran.agent.client.core.session.SessionManager;
|
||||
import com.tongran.agent.client.core.vo.MtrVO;
|
||||
import com.tongran.agent.client.netty.MultiTargetNettyClient;
|
||||
import com.tongran.agent.client.netty.config.AgentNettyConfig;
|
||||
import com.tongran.agent.client.netty.model.Message;
|
||||
@@ -35,6 +37,9 @@ import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
@@ -825,11 +830,73 @@ public class AgentServiceImpl implements AgentService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(jsonObject.containsKey("mtrPolicys")){
|
||||
String mtrPolicys = jsonObject.getString("mtrPolicys");
|
||||
if(!mtrPolicys.equals(GlobalConfig.MTRPOLICYMSG)){
|
||||
GlobalConfig.MTRPOLICYMSG = mtrPolicys;
|
||||
List<MtrPolicyConfigEO> mtrPolicyConfigEOList = JSON.parseArray(mtrPolicys, MtrPolicyConfigEO.class);
|
||||
try {
|
||||
if (CollectionUtil.isEmpty(mtrPolicyConfigEOList)) {
|
||||
// 如果没有策略,取消定时任务
|
||||
dynamicTaskService.cancelTask("mtrTask");
|
||||
AssertLog.info("MTR策略为空,取消MTR定时任务");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查是否有有效的策略(在时间范围内的策略)
|
||||
boolean hasValidPolicy = false;
|
||||
long currentTimestamp = System.currentTimeMillis() / 1000;
|
||||
|
||||
for (MtrPolicyConfigEO policy : mtrPolicyConfigEOList) {
|
||||
if (isPolicyTimeValid(policy, currentTimestamp)) {
|
||||
hasValidPolicy = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasValidPolicy) {
|
||||
// 没有有效策略,取消定时任务
|
||||
dynamicTaskService.cancelTask("mtrTask");
|
||||
AssertLog.info("没有有效的MTR策略,取消MTR定时任务");
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算下一个5分钟整点的延迟时间
|
||||
long milli = AgentUtil.millisecondsToNext5Minute();
|
||||
|
||||
// 启动或更新定时任务
|
||||
dynamicTaskService.scheduleTask("mtrTask",
|
||||
businessTasks::mtrTask, milli, 300000L); // 5分钟间隔
|
||||
|
||||
AssertLog.info("MTR定时任务已启动/更新,延迟: {}ms, 间隔: 300000ms", milli);
|
||||
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("启动MTR定时任务异常", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 检查策略时间是否有效
|
||||
*/
|
||||
private boolean isPolicyTimeValid(MtrPolicyConfigEO policy, long currentTimestamp) {
|
||||
try {
|
||||
Date currentTime = new Date(currentTimestamp * 1000);
|
||||
Date startTime = policy.getStartTime();
|
||||
Date endTime = policy.getEndTime();
|
||||
|
||||
// 开始时间为空表示立即开始
|
||||
boolean startValid = startTime == null || !currentTime.before(startTime);
|
||||
// 结束时间为空表示永不过期
|
||||
boolean endValid = endTime == null || !currentTime.after(endTime);
|
||||
|
||||
return startValid && endValid;
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("检查策略时间有效性异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void checkTrAgent() {
|
||||
String CRON_FILE_PATH = properties.getScriptPath()+"/tr_live.cron";
|
||||
@@ -904,7 +971,7 @@ public class AgentServiceImpl implements AgentService {
|
||||
|
||||
@Override
|
||||
public boolean connection() {
|
||||
String clientId = MachineFingerprint.getHardwareFingerprint();
|
||||
String clientId = "MTR" + MachineFingerprint.getHardwareFingerprint();
|
||||
//初始化SN信息
|
||||
GlobalConfig.DEVICE_SN = AgentUtil.getDeviceSN();
|
||||
//检查外置目录是否存在
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.tongran.agent.client.service.impl;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.tongran.agent.client.core.eo.MtrPolicyConfigEO;
|
||||
import com.tongran.agent.client.core.vo.MtrVO;
|
||||
import com.tongran.agent.client.core.vo.NetVO;
|
||||
import com.tongran.agent.client.service.MtrService;
|
||||
import com.tongran.agent.client.utils.AgentUtil;
|
||||
import com.tongran.agent.client.utils.AssertLog;
|
||||
import org.springframework.stereotype.Service;
|
||||
import oshi.SystemInfo;
|
||||
import oshi.hardware.HardwareAbstractionLayer;
|
||||
import oshi.hardware.NetworkIF;
|
||||
import oshi.util.FormatUtil;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@Service
|
||||
public class MtrServiceImpl implements MtrService {
|
||||
/**
|
||||
* 执行MTR探测列表 - 异步版本
|
||||
*/
|
||||
public List<MtrVO> mtrList(long timestamp, List<MtrPolicyConfigEO> mtrPolicyConfigEOList) {
|
||||
List<CompletableFuture<MtrVO>> futures = new ArrayList<>();
|
||||
List<MtrVO> mtrResults = new ArrayList<>();
|
||||
|
||||
try {
|
||||
if (CollectionUtil.isEmpty(mtrPolicyConfigEOList)) {
|
||||
return mtrResults;
|
||||
}
|
||||
|
||||
// 为每个IP创建异步任务
|
||||
for (MtrPolicyConfigEO policy : mtrPolicyConfigEOList) {
|
||||
if (!isPolicyTimeValid(policy, timestamp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String[] targetIps = policy.getServeripGroup().split(";");
|
||||
for (String targetIp : targetIps) {
|
||||
String ip = targetIp.trim();
|
||||
if (!ip.isEmpty()) {
|
||||
// 异步执行每个IP的探测
|
||||
CompletableFuture<MtrVO> future = CompletableFuture.supplyAsync(() ->
|
||||
executeSingleMtrProbe(ip, policy, timestamp)
|
||||
);
|
||||
futures.add(future);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 等待所有任务完成
|
||||
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
|
||||
futures.toArray(new CompletableFuture[0])
|
||||
);
|
||||
|
||||
// 获取所有结果(设置超时时间,比如2分钟)
|
||||
allFutures.get(2, TimeUnit.MINUTES);
|
||||
|
||||
for (CompletableFuture<MtrVO> future : futures) {
|
||||
MtrVO result = future.get();
|
||||
if (result != null) {
|
||||
mtrResults.add(result);
|
||||
}
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("MTR异步探测异常", e);
|
||||
}
|
||||
|
||||
return mtrResults;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查策略时间是否有效
|
||||
*/
|
||||
private boolean isPolicyTimeValid(MtrPolicyConfigEO policy, long currentTimestamp) {
|
||||
try {
|
||||
// 将时间戳转换为Date对象进行比较
|
||||
Date currentTime = new Date(currentTimestamp * 1000);
|
||||
Date startTime = policy.getStartTime();
|
||||
Date endTime = policy.getEndTime();
|
||||
|
||||
// 开始时间为空表示立即开始
|
||||
boolean startValid = startTime == null || !currentTime.before(startTime);
|
||||
// 结束时间为空表示永不过期
|
||||
boolean endValid = endTime == null || !currentTime.after(endTime);
|
||||
|
||||
return startValid && endValid;
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("检查策略时间有效性异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行单个IP的MTR探测
|
||||
*/
|
||||
private MtrVO executeSingleMtrProbe(String targetIp, MtrPolicyConfigEO policy, long timestamp) {
|
||||
MtrVO mtrVO = new MtrVO();
|
||||
mtrVO.setTargetIp(targetIp);
|
||||
mtrVO.setPolicyId(policy.getId());
|
||||
mtrVO.setTimestamp(timestamp);
|
||||
|
||||
try {
|
||||
// 第一次MTR探测
|
||||
double firstLossPercent = executeMtrCommand(targetIp);
|
||||
mtrVO.setFirstLossPercent(firstLossPercent);
|
||||
|
||||
// 如果丢包率超过5%,30秒后重试
|
||||
if (firstLossPercent > 5.0) {
|
||||
AssertLog.info("目标IP {} 丢包率 {}% > 5%,30秒后重试探测", targetIp, firstLossPercent);
|
||||
|
||||
// 等待30秒
|
||||
Thread.sleep(30000);
|
||||
|
||||
// 第二次MTR探测
|
||||
double secondLossPercent = executeMtrCommand(targetIp);
|
||||
mtrVO.setFinalLossPercent(secondLossPercent);
|
||||
mtrVO.setHasRetry(true);
|
||||
|
||||
AssertLog.info("目标IP {} 重试探测完成,最终丢包率: {}%", targetIp, secondLossPercent);
|
||||
} else {
|
||||
mtrVO.setFinalLossPercent(firstLossPercent);
|
||||
mtrVO.setHasRetry(false);
|
||||
AssertLog.info("目标IP {} 丢包率 {}%,无需重试", targetIp, firstLossPercent);
|
||||
}
|
||||
|
||||
return mtrVO;
|
||||
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("MTR探测异常 - IP: {}", targetIp, e);
|
||||
mtrVO.setFinalLossPercent(-1.0); // -1表示探测失败
|
||||
mtrVO.setErrorMsg(e.getMessage());
|
||||
return mtrVO;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行mtr -r命令并解析结果
|
||||
*/
|
||||
private double executeMtrCommand(String targetIp) {
|
||||
Process process = null;
|
||||
try {
|
||||
// 执行mtr -r -c 10命令
|
||||
ProcessBuilder processBuilder = new ProcessBuilder("mtr", "-r", "-c", "10", targetIp);
|
||||
process = processBuilder.start();
|
||||
|
||||
// 读取命令输出
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
String line;
|
||||
String lastValidLine = null;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
// 跳过标题行,记录最后一条有效数据行
|
||||
if (!line.trim().isEmpty() &&
|
||||
!line.startsWith("Start:") &&
|
||||
!line.startsWith("HOST:") &&
|
||||
Character.isDigit(line.trim().charAt(0))) {
|
||||
lastValidLine = line;
|
||||
}
|
||||
}
|
||||
|
||||
// 等待命令执行完成
|
||||
boolean finished = process.waitFor(2, TimeUnit.MINUTES);
|
||||
if (!finished) {
|
||||
process.destroy();
|
||||
throw new RuntimeException("MTR命令执行超时");
|
||||
}
|
||||
|
||||
if (lastValidLine == null) {
|
||||
throw new RuntimeException("MTR命令无有效输出");
|
||||
}
|
||||
|
||||
// 解析丢包率
|
||||
return parseLossPercentFromMtrOutput(lastValidLine);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("MTR命令执行异常: " + e.getMessage());
|
||||
} finally {
|
||||
if (process != null) {
|
||||
process.destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从MTR输出中解析丢包率
|
||||
*/
|
||||
private double parseLossPercentFromMtrOutput(String mtrOutputLine) {
|
||||
try {
|
||||
// 使用正则表达式匹配Loss%列
|
||||
Pattern pattern = Pattern.compile("(\\d+\\.?\\d*)%");
|
||||
Matcher matcher = pattern.matcher(mtrOutputLine);
|
||||
|
||||
if (matcher.find()) {
|
||||
return Double.parseDouble(matcher.group(1));
|
||||
}
|
||||
|
||||
throw new RuntimeException("未找到Loss%数据: " + mtrOutputLine);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("解析Loss%失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ logging:
|
||||
netty:
|
||||
server:
|
||||
host: 120.211.95.173
|
||||
port: 6620
|
||||
port: 6610
|
||||
client:
|
||||
client-id: client-001
|
||||
reconnect-interval: 5
|
||||
|
||||
@@ -5,8 +5,8 @@ spring:
|
||||
pathmatch:
|
||||
matching-strategy: ant_path_matcher
|
||||
application:
|
||||
name: tr-agent-client
|
||||
version: 1.1.4
|
||||
name: tr-mtragent-client
|
||||
version: 1.0.0
|
||||
conf-path: /usr/local/tongran/conf
|
||||
script-path: /usr/local/tongran/sbin
|
||||
tmp-path: /usr/local/tongran/tmp
|
||||
|
||||
Reference in New Issue
Block a user