1、开发agent采集磁盘类型、磁盘已用空间方法。
2、开发磁盘测试IOPS方法。 3、开发磁盘分区卸载方法
This commit is contained in:
@@ -71,6 +71,8 @@ public enum MsgEnum {
|
||||
|
||||
macvlan状态上报("MACVLAN_STATUS_RSP"),
|
||||
|
||||
iops结果上报("IOPS_RESULT"),
|
||||
|
||||
多网IP探测上报("NETWORK_DETECT");
|
||||
|
||||
private String value;
|
||||
|
||||
@@ -45,6 +45,10 @@ public class DiskVO implements Serializable {
|
||||
|
||||
@Schema(description = "时间戳")
|
||||
private long timestamp;
|
||||
@Schema(description = "磁盘类型")
|
||||
private String type;
|
||||
@Schema(description = "已用空间")
|
||||
private long usedSpace;
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -907,8 +907,157 @@ public class AgentServiceImpl implements AgentService {
|
||||
PppoeEO pppoeEO = JSON.parseObject(pppoeConfig, PppoeEO.class);
|
||||
handlePppoeConfig(pppoeEO);
|
||||
}
|
||||
if(jsonObject.containsKey("diskIopsTest")){
|
||||
String diskName = jsonObject.getString("diskIopsTest");
|
||||
handleDiskIops(diskName);
|
||||
}
|
||||
if(jsonObject.containsKey("umountDisk")){
|
||||
String diskName = jsonObject.getString("umountDisk");
|
||||
handleUmountDisk(diskName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void handleUmountDisk(String diskName) {
|
||||
try {
|
||||
// 查询所有挂载点
|
||||
String[] grepCmd = {"sh", "-c", "mount | grep '" + diskName + "' | awk '{print $1}'"};
|
||||
ProcessBuilder grepPb = new ProcessBuilder(grepCmd);
|
||||
Process grepProcess = grepPb.start();
|
||||
|
||||
BufferedReader grepReader = new BufferedReader(new InputStreamReader(grepProcess.getInputStream()));
|
||||
String partition;
|
||||
List<String> partitions = new ArrayList<>();
|
||||
|
||||
// 收集所有分区
|
||||
while ((partition = grepReader.readLine()) != null) {
|
||||
partition = partition.trim();
|
||||
if (!partition.isEmpty() && partition.startsWith("/dev/")) {
|
||||
partitions.add(partition);
|
||||
}
|
||||
}
|
||||
|
||||
grepReader.close();
|
||||
grepProcess.waitFor();
|
||||
|
||||
// 如果没有分区,直接返回
|
||||
if (partitions.isEmpty()) {
|
||||
AssertLog.info("没有找到与{}相关的挂载分区", diskName);
|
||||
return;
|
||||
}
|
||||
|
||||
// 卸载所有分区
|
||||
for (String part : partitions) {
|
||||
try {
|
||||
AssertLog.info("正在卸载:{}", part);
|
||||
ProcessBuilder umountPb = new ProcessBuilder("umount", part);
|
||||
Process umountProcess = umountPb.start();
|
||||
int exitCode = umountProcess.waitFor();
|
||||
|
||||
if (exitCode == 0) {
|
||||
AssertLog.info("成功卸载: {}", part);
|
||||
} else {
|
||||
// 尝试强制卸载
|
||||
ProcessBuilder forcePb = new ProcessBuilder("umount", "-f", part);
|
||||
Process forceProcess = forcePb.start();
|
||||
int forceCode = forceProcess.waitFor();
|
||||
|
||||
if (forceCode == 0) {
|
||||
AssertLog.info("强制卸载成功:{} ", part);
|
||||
} else {
|
||||
AssertLog.info("卸载失败: ", part);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
AssertLog.info("卸载 {} 时出错: {}",diskName, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException | InterruptedException e) {
|
||||
AssertLog.info("卸载 {} 时出错: {}",diskName, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDiskIops(String diskName) {
|
||||
JSONObject json = new JSONObject();
|
||||
AssertLog.info("开始测试磁盘{}的iops", diskName);
|
||||
// 使用CompletableFuture并行执行
|
||||
CompletableFuture<String> readFuture = CompletableFuture.supplyAsync(() -> {
|
||||
return testIops(diskName, "read");
|
||||
});
|
||||
|
||||
CompletableFuture<String> writeFuture = CompletableFuture.supplyAsync(() -> {
|
||||
return testIops(diskName, "write");
|
||||
});
|
||||
|
||||
try {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
timestamp = Math.round(timestamp / 1000.0);
|
||||
// 等待两个测试都完成(最多70秒)
|
||||
String readIops = readFuture.get(70, TimeUnit.SECONDS);
|
||||
String writeIops = writeFuture.get(70, TimeUnit.SECONDS);
|
||||
|
||||
json.put("name", diskName);
|
||||
json.put("readIops", readIops);
|
||||
json.put("writeIops", writeIops);
|
||||
json.put("timestamp",timestamp);
|
||||
// 判定客户端与服务端是否连接
|
||||
if (Objects.nonNull(sessionManager.getSessionById(GlobalConfig.CLIENT_ID))) {
|
||||
Message message = Message.builder().clientId(GlobalConfig.CLIENT_ID).dataType(MsgEnum.iops结果上报.getValue())
|
||||
.data(json.toString()).build();
|
||||
sessionManager.writeAndFlush(sessionManager.getSessionById(GlobalConfig.CLIENT_ID).getChannel(), message);
|
||||
AssertLog.info("发送iops结果上报应答={}",JSON.toJSONString(message));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
AssertLog.info("测试磁盘IOPS失败:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String testIops(String diskName, String rwType) {
|
||||
try {
|
||||
String cmd = String.format(
|
||||
"fio --name=tt1 --filename=/dev/%s --size=1G --bs=4k --rw=%s --ioengine=libaio --runtime=60 --direct=1 --time_based --group_reporting",
|
||||
diskName, rwType
|
||||
);
|
||||
|
||||
Process process = Runtime.getRuntime().exec(new String[]{"bash", "-c", cmd});
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
StringBuilder output = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
output.append(line).append("\n");
|
||||
}
|
||||
|
||||
process.waitFor();
|
||||
reader.close();
|
||||
|
||||
return parseIops(output.toString());
|
||||
|
||||
} catch (Exception e) {
|
||||
AssertLog.error("测试磁盘IOPS失败:{}", e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private String parseIops(String output) {
|
||||
// 示例:" read: IOPS=12.7k, BW=49.6MiB/s (52.1MB/s)(2979MiB/60001msec)"
|
||||
String[] lines = output.split("\n");
|
||||
for (String line : lines) {
|
||||
if (line.trim().startsWith("read:") || line.trim().startsWith("write:")) {
|
||||
// 查找 IOPS= 部分
|
||||
String[] parts = line.split("IOPS=");
|
||||
if (parts.length > 1) {
|
||||
String iopsPart = parts[1].split(",")[0];
|
||||
return iopsPart.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理PPPoE配置
|
||||
* @param pppoeEO PPPoE配置对象
|
||||
|
||||
@@ -9,9 +9,9 @@ import oshi.SystemInfo;
|
||||
import oshi.hardware.HWDiskStore;
|
||||
import oshi.software.os.OSFileStore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
|
||||
@Service
|
||||
public class DiskServiceImpl implements DiskService {
|
||||
@@ -19,29 +19,47 @@ public class DiskServiceImpl implements DiskService {
|
||||
public List<DiskVO> diskList(long timestamp) {
|
||||
List<DiskVO> tempList = new ArrayList<>();
|
||||
List<DiskVO> resultList = new ArrayList<>();
|
||||
Map<String, String> typeMap = getDiskTypeMap();
|
||||
Map<String, Long> usedSpaceMap = getDiskUsedSpaceMap();
|
||||
SystemInfo si = new SystemInfo();
|
||||
System.out.println("=========================================================");
|
||||
|
||||
// 获取磁盘IO信息
|
||||
System.out.println("\n=== 磁盘IO信息 ===");
|
||||
for (HWDiskStore disk : si.getHardware().getDiskStores()) {
|
||||
DiskVO diskVO = DiskVO.builder().timestamp(timestamp).build();
|
||||
diskVO.setName(disk.getName());//磁盘名称
|
||||
diskVO.setSerial(disk.getSerial());//序列号
|
||||
diskVO.setTotal(disk.getSize());//磁盘大小
|
||||
diskVO.setWriteTimes(disk.getWrites());//磁盘写入次数
|
||||
diskVO.setReadTimes(disk.getReads());//磁盘读取次数
|
||||
diskVO.setWriteBytes(disk.getReadBytes());//磁盘写入字节
|
||||
diskVO.setReadBytes(disk.getWriteBytes());//磁盘读取字节
|
||||
|
||||
// 处理磁盘名称:去掉/dev/前缀
|
||||
String diskFullName = disk.getName();
|
||||
String diskName = diskFullName.replace("/dev/", "");
|
||||
diskVO.setName(diskName); // 保持原样存储
|
||||
diskVO.setSerial(disk.getSerial()); // 序列号
|
||||
diskVO.setTotal(disk.getSize()); // 磁盘大小
|
||||
diskVO.setWriteTimes(disk.getWrites()); // 磁盘写入次数
|
||||
diskVO.setReadTimes(disk.getReads()); // 磁盘读取次数
|
||||
diskVO.setWriteBytes(disk.getReadBytes()); // 磁盘写入字节
|
||||
diskVO.setReadBytes(disk.getWriteBytes()); // 磁盘读取字节
|
||||
|
||||
// 获取磁盘类型和已用空间(使用不带/dev/前缀的名称)
|
||||
String type = typeMap.get(diskName);
|
||||
Long usedSpace = usedSpaceMap.get(diskName);
|
||||
|
||||
diskVO.setType(type != null ? type : "UNKNOWN");
|
||||
diskVO.setUsedSpace(usedSpace != null ? usedSpace : 0L);
|
||||
|
||||
tempList.add(diskVO);
|
||||
|
||||
System.out.println("磁盘名称: " + diskVO.getName());
|
||||
System.out.println("序列号: " + diskVO.getSerial());
|
||||
System.out.println("磁盘类型: " + diskVO.getType());
|
||||
System.out.println("已用空间: " + diskVO.getUsedSpace());
|
||||
System.out.println("磁盘大小: " + diskVO.getTotal());
|
||||
System.out.println("磁盘写入次数: " + diskVO.getWriteTimes());
|
||||
System.out.println("磁盘读取次数: " + diskVO.getReadTimes());
|
||||
System.out.println("磁盘写入字节: " + diskVO.getWriteBytes());
|
||||
System.out.println("磁盘读取字节: " + diskVO.getReadBytes());
|
||||
}
|
||||
|
||||
try{
|
||||
// 第一次采样
|
||||
List<HWDiskStore> disks1 = si.getHardware().getDiskStores();
|
||||
@@ -64,6 +82,8 @@ public class DiskServiceImpl implements DiskService {
|
||||
diskVO.setWriteSpeed(readDiff);//磁盘写入速率
|
||||
diskVO.setReadSpeed(writeDiff);//磁盘读取速率
|
||||
System.out.println("磁盘名称: " + diskVO.getName());
|
||||
System.out.println("磁盘类型: " + diskVO.getType());
|
||||
System.out.println("已用空间: " + diskVO.getUsedSpace());
|
||||
System.out.println("磁盘写入速率: " + diskVO.getWriteSpeed());
|
||||
System.out.println("磁盘读取速率: " + diskVO.getReadSpeed());
|
||||
}
|
||||
@@ -75,6 +95,128 @@ public class DiskServiceImpl implements DiskService {
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取磁盘类型映射(设备名 -> 类型)
|
||||
*/
|
||||
public Map<String, String> getDiskTypeMap() {
|
||||
Map<String, String> diskTypeMap = new HashMap<>();
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder("lsblk", "-d", "-o", "name,rota");
|
||||
Process process = pb.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
String line;
|
||||
reader.readLine(); // 跳过标题行
|
||||
while ((line = reader.readLine()) != null) {
|
||||
String[] parts = line.trim().split("\\s+");
|
||||
if (parts.length >= 2) {
|
||||
String diskName = parts[0];
|
||||
String rota = parts[1];
|
||||
String type = "1".equals(rota) ? "HDD" : "SSD";
|
||||
|
||||
diskTypeMap.put(diskName, type);
|
||||
}
|
||||
}
|
||||
process.waitFor();
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return diskTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取磁盘已用空间映射(设备名 -> 已用字节数)
|
||||
* 使用lsblk获取准确的磁盘-分区关系
|
||||
*/
|
||||
public Map<String, Long> getDiskUsedSpaceMap() {
|
||||
Map<String, Long> diskUsedMap = new HashMap<>();
|
||||
Map<String, String> partitionToDisk = getPartitionToDiskMap();
|
||||
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder("df", "-B1", "--output=source,used");
|
||||
Process process = pb.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
reader.readLine(); // 跳过标题行
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty() || line.startsWith("Filesystem")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String[] parts = line.split("\\s+");
|
||||
if (parts.length >= 2 && parts[0].startsWith("/dev/")) {
|
||||
String device = parts[0];
|
||||
String usedStr = parts[1];
|
||||
|
||||
try {
|
||||
long used = Long.parseLong(usedStr);
|
||||
String deviceName = device.replace("/dev/", "");
|
||||
|
||||
// 通过lsblk获取的映射关系找到对应的物理磁盘
|
||||
String diskName = partitionToDisk.get(deviceName);
|
||||
if (diskName == null) {
|
||||
// 如果没有找到映射,可能是磁盘本身(不是分区)
|
||||
diskName = deviceName;
|
||||
}
|
||||
|
||||
if (diskName != null) {
|
||||
diskUsedMap.merge(diskName, used, Long::sum);
|
||||
}
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
process.waitFor();
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return diskUsedMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用lsblk获取磁盘-分区映射关系
|
||||
* @return Map<分区设备名, 物理磁盘设备名>
|
||||
*/
|
||||
private Map<String, String> getPartitionToDiskMap() {
|
||||
Map<String, String> partitionToDiskMap = new HashMap<>();
|
||||
try {
|
||||
ProcessBuilder pb = new ProcessBuilder("lsblk", "-l", "-o", "name,type");
|
||||
Process process = pb.start();
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||
|
||||
String line;
|
||||
reader.readLine(); // 跳过标题行
|
||||
String currentDisk = null;
|
||||
|
||||
while ((line = reader.readLine()) != null) {
|
||||
line = line.trim();
|
||||
if (line.isEmpty()) continue;
|
||||
|
||||
String[] parts = line.split("\\s+");
|
||||
if (parts.length >= 2) {
|
||||
String device = parts[0];
|
||||
String type = parts[1];
|
||||
|
||||
if ("disk".equals(type)) {
|
||||
// 这是物理磁盘
|
||||
currentDisk = device;
|
||||
} else if ("part".equals(type) && currentDisk != null) {
|
||||
// 这是分区,关联到当前磁盘
|
||||
partitionToDiskMap.put(device, currentDisk);
|
||||
}
|
||||
}
|
||||
}
|
||||
process.waitFor();
|
||||
reader.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return partitionToDiskMap;
|
||||
}
|
||||
@Override
|
||||
public List<PointVO> pointList(long timestamp) {
|
||||
List<PointVO> list = new ArrayList<>();
|
||||
|
||||
Reference in New Issue
Block a user