1、开发agent采集磁盘类型、磁盘已用空间方法。

2、开发磁盘测试IOPS方法。
3、开发磁盘分区卸载方法
This commit is contained in:
gaoyutao
2026-01-15 18:16:34 +08:00
parent f9a4de8c97
commit f5c3ae500b
4 changed files with 307 additions and 10 deletions
@@ -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<>();