Browse Source

后台管理硬件监控添加gpu信息

zhaohan 10 months ago
parent
commit
ea43c3c8a6

+ 3 - 0
ruoyi-admin/src/main/resources/application-prod.yml

@@ -96,6 +96,9 @@ file:
   #上传附件访问地址
   #上传附件访问地址
   base-url: http://8.137.127.56:5666
   base-url: http://8.137.127.56:5666
 
 
+  #燧原硬件信息接口
+enflame:
+  url: http://60.164.133.40:19997
 mcp:
 mcp:
   server:
   server:
     url: http://localhost:8085
     url: http://localhost:8085

+ 100 - 17
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/HardwareInfoService.java

@@ -1,11 +1,16 @@
 package org.ruoyi.chat.service;
 package org.ruoyi.chat.service;
 
 
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import lombok.Data;
 import lombok.Data;
+import org.ruoyi.chat.util.HttpUtils;
+import org.springframework.beans.factory.annotation.Value;
 import oshi.SystemInfo;
 import oshi.SystemInfo;
 import oshi.hardware.CentralProcessor;
 import oshi.hardware.CentralProcessor;
 import oshi.hardware.GlobalMemory;
 import oshi.hardware.GlobalMemory;
 import oshi.hardware.HardwareAbstractionLayer;
 import oshi.hardware.HardwareAbstractionLayer;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
+import com.fasterxml.jackson.core.type.TypeReference;
 
 
 import java.util.List;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
@@ -15,20 +20,26 @@ public class HardwareInfoService {
 
 
     private final SystemInfo systemInfo = new SystemInfo();
     private final SystemInfo systemInfo = new SystemInfo();
     private final HardwareAbstractionLayer hal = systemInfo.getHardware();
     private final HardwareAbstractionLayer hal = systemInfo.getHardware();
+    private final ObjectMapper objectMapper = new ObjectMapper();
     private long[] prevTicks = null;
     private long[] prevTicks = null;
+    @Value("${enflame.url}")
+    private String enflameApiUrl;
 
 
+    /**
+     * 获取本机硬件 + 集群 Supervisor 节点信息
+     */
     public HardwareData getHardwareData() {
     public HardwareData getHardwareData() {
         CentralProcessor processor = hal.getProcessor();
         CentralProcessor processor = hal.getProcessor();
         GlobalMemory memory = hal.getMemory();
         GlobalMemory memory = hal.getMemory();
 
 
-        // CPU 使用率(准确版)
-        double cpuLoad = getCpuLoad(processor);
+        // 1. 本机 CPU 使用率
+        double cpuUsage = getCpuLoad(processor);
 
 
-        // 内存信息
+        // 2. 本机内存
         long totalMemory = memory.getTotal();
         long totalMemory = memory.getTotal();
         long availableMemory = memory.getAvailable();
         long availableMemory = memory.getAvailable();
 
 
-        // 磁盘信息
+        // 3. 磁盘信息
         List<DiskData> disks = systemInfo.getOperatingSystem().getFileSystem().getFileStores().stream()
         List<DiskData> disks = systemInfo.getOperatingSystem().getFileSystem().getFileStores().stream()
                 .map(store -> new DiskData(
                 .map(store -> new DiskData(
                         store.getMount(),
                         store.getMount(),
@@ -36,47 +47,87 @@ public class HardwareInfoService {
                         store.getUsableSpace()))
                         store.getUsableSpace()))
                 .collect(Collectors.toList());
                 .collect(Collectors.toList());
 
 
-        // 网络信息
+        // 4. 网络信息
         List<NetworkData> networks = hal.getNetworkIFs().stream()
         List<NetworkData> networks = hal.getNetworkIFs().stream()
+                .filter(net -> net.getBytesRecv() > 0 || net.getBytesSent() > 0) // 可选:过滤无流量的网卡
                 .map(net -> new NetworkData(
                 .map(net -> new NetworkData(
                         net.getName(),
                         net.getName(),
                         net.getBytesRecv(),
                         net.getBytesRecv(),
                         net.getBytesSent()))
                         net.getBytesSent()))
                 .collect(Collectors.toList());
                 .collect(Collectors.toList());
 
 
-        return new HardwareData(cpuLoad, totalMemory, availableMemory, disks, networks);
+        // 5. 获取集群中 Supervisor 节点信息
+        ClusterNodeInfo clusterNodeInfo = getSupervisorNodeInfo();
+
+        // 6. 返回合并数据
+        return new HardwareData(cpuUsage, totalMemory, availableMemory, disks, networks, clusterNodeInfo);
     }
     }
 
 
-    public double getCpuLoad(CentralProcessor processor) {
+    /**
+     * 计算 CPU 使用率(两次采样之间)
+     */
+    private double getCpuLoad(CentralProcessor processor) {
         if (prevTicks == null) {
         if (prevTicks == null) {
             prevTicks = processor.getSystemCpuLoadTicks();
             prevTicks = processor.getSystemCpuLoadTicks();
-            return 0; // 第一次调用无法计算,返回0或其他默认值
+            return 0.0;
         }
         }
         long[] ticks = processor.getSystemCpuLoadTicks();
         long[] ticks = processor.getSystemCpuLoadTicks();
         double load = processor.getSystemCpuLoadBetweenTicks(prevTicks);
         double load = processor.getSystemCpuLoadBetweenTicks(prevTicks);
         prevTicks = ticks;
         prevTicks = ticks;
-        return load * 100;
+        return Math.round(load * 10000) / 100.0; // 保留两位小数
+    }
+
+    /**
+     * 从燧原集群 API 获取 Supervisor 节点信息
+     */
+    private ClusterNodeInfo getSupervisorNodeInfo() {
+        String url = enflameApiUrl + "/v1/cluster/info?detailed=true";
+        try {
+            String jsonResponse = HttpUtils.sendHttpGet(url);
+            if (jsonResponse == null || jsonResponse.trim().isEmpty()) {
+                System.err.println("API 返回为空或连接失败: " + url);
+                return null;
+            }
+
+            // 解析为 ClusterNodeInfo 列表
+            List<ClusterNodeInfo> nodes = objectMapper.readValue(jsonResponse, new TypeReference<List<ClusterNodeInfo>>() {});
+
+            // 查找 node_type 为 "Supervisor" 的节点
+            return nodes.stream()
+                    .filter(node -> "Worker".equals(node.getNodeType()))
+                    .findFirst()
+                    .orElse(null);
+
+        } catch (Exception e) {
+            System.err.println("请求或解析集群信息失败: " + e.getMessage());
+            e.printStackTrace();
+            return null; // 前端可据此显示“集群离线”或“加载中”
+        }
     }
     }
 
 
-    // DTO 类
+    // ==================== DTO 数据传输对象 ====================
+
     @Data
     @Data
     public static class HardwareData {
     public static class HardwareData {
-        private double cpuUsage; // %
-        private long totalMemory; // bytes
-        private long availableMemory; // bytes
+        private double cpuUsage; // 本机 CPU 使用率 (%)
+        private long totalMemory; // 本机总内存 (bytes)
+        private long availableMemory; // 本机可用内存 (bytes)
         private List<DiskData> disks;
         private List<DiskData> disks;
         private List<NetworkData> networks;
         private List<NetworkData> networks;
+        private ClusterNodeInfo clusterNodeInfo; // 集群 Supervisor 节点信息
 
 
-
-        public HardwareData(double cpuUsage, long totalMemory, long availableMemory, List<DiskData> disks, List<NetworkData> networks) {
+        public HardwareData(double cpuUsage, long totalMemory, long availableMemory,
+                            List<DiskData> disks, List<NetworkData> networks,
+                            ClusterNodeInfo clusterNodeInfo) {
             this.cpuUsage = cpuUsage;
             this.cpuUsage = cpuUsage;
             this.totalMemory = totalMemory;
             this.totalMemory = totalMemory;
             this.availableMemory = availableMemory;
             this.availableMemory = availableMemory;
             this.disks = disks;
             this.disks = disks;
             this.networks = networks;
             this.networks = networks;
+            this.clusterNodeInfo = clusterNodeInfo;
         }
         }
-
     }
     }
+
     @Data
     @Data
     public static class DiskData {
     public static class DiskData {
         private String mountPoint;
         private String mountPoint;
@@ -88,8 +139,8 @@ public class HardwareInfoService {
             this.totalSpace = totalSpace;
             this.totalSpace = totalSpace;
             this.usableSpace = usableSpace;
             this.usableSpace = usableSpace;
         }
         }
-
     }
     }
+
     @Data
     @Data
     public static class NetworkData {
     public static class NetworkData {
         private String name;
         private String name;
@@ -101,6 +152,38 @@ public class HardwareInfoService {
             this.bytesReceived = bytesReceived;
             this.bytesReceived = bytesReceived;
             this.bytesSent = bytesSent;
             this.bytesSent = bytesSent;
         }
         }
+    }
+
+    @Data
+    public static class ClusterNodeInfo {
+        @JsonProperty("node_type")
+        private String nodeType;
+
+        @JsonProperty("ip_address")
+        private String ipAddress;
+
+        @JsonProperty("gpu_count")
+        private Integer gpuCount;
+
+        @JsonProperty("gpu_vram_total")
+        private Long gpuVramTotal;
+
+        @JsonProperty("gpu_vram_available")
+        private Long gpuVramAvailable;
+
+        @JsonProperty("cpu_available")
+        private Double cpuAvailable;
+
+        @JsonProperty("cpu_count")
+        private Integer cpuCount;
+
+        @JsonProperty("mem_used")
+        private Long memUsed;
+
+        @JsonProperty("mem_available")
+        private Long memAvailable;
 
 
+        @JsonProperty("mem_total")
+        private Long memTotal;
     }
     }
 }
 }

+ 229 - 0
ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/HttpUtils.java

@@ -0,0 +1,229 @@
+package org.ruoyi.chat.util;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.util.EntityUtils;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class HttpUtils {
+
+
+
+    /**
+     * 发送POST请求,参数为json格式
+     * @param httpUrl
+     * @param
+     * @return
+     */
+    public static  String sendHttpPostByJson(String httpUrl, String jsonParam) {
+        CloseableHttpClient httpClient = null;
+        CloseableHttpResponse response = null;
+        String responseContent = null;
+        HttpPost httpPost = new HttpPost(httpUrl);
+        httpPost.addHeader("Content-Type", "application/json");
+        try {
+            httpPost.setEntity(new StringEntity(jsonParam));
+            httpClient = HttpClients.createDefault();
+            response = httpClient.execute(httpPost);
+            // 状态码 System.out.println(response.getStatusLine().getStatusCode() + "\n");
+            HttpEntity entity = response.getEntity();
+            responseContent = EntityUtils.toString(entity, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            e.printStackTrace();
+        } catch (ClientProtocolException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                // 关闭连接,释放资源
+                if (response != null) {
+                    response.close();
+                }
+                if (httpClient != null) {
+                    httpClient.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return responseContent;
+    }
+
+    /**
+     * 发送 post请求
+     * @param httpUrl 地址
+     * @param maps 参数
+     */
+    public String sendHttpHeaderPost(String httpUrl, Map<String, String> maps, String token) {
+        HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost
+        httpPost.setHeader("AccessToken", token);
+        // 创建参数队列
+        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
+        for (String key : maps.keySet()) {
+            nameValuePairs.add(new BasicNameValuePair(key, maps.get(key)));
+        }
+        try {
+            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return sendHttpPost(httpPost);
+    }
+
+    /**
+     * 发送 post请求
+     * @param httpUrl 地址
+     */
+    public String sendHttpPost(String httpUrl) {
+        System.out.println(httpUrl);
+        HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost
+        return sendHttpPost(httpPost);
+    }
+
+    /**
+     * 发送 post请求
+     * @param httpUrl 地址
+     * @param params 参数(格式:key1=value1&key2=value2)
+     */
+    public String sendHttpPost(String httpUrl, String params) {
+        HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost
+        try {
+            //设置参数
+            StringEntity stringEntity = new StringEntity(params, "UTF-8");
+            stringEntity.setContentType("application/x-www-form-urlencoded");
+            httpPost.setEntity(stringEntity);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return sendHttpPost(httpPost);
+    }
+
+    /**
+     * 发送 post请求
+     * @param httpUrl 地址
+     * @param maps 参数
+     */
+    public String sendHttpPost(String httpUrl, Map<String, String> maps) {
+        HttpPost httpPost = new HttpPost(httpUrl);// 创建httpPost
+        // 创建参数队列
+        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
+        for (String key : maps.keySet()) {
+            nameValuePairs.add(new BasicNameValuePair(key, maps.get(key)));
+        }
+        try {
+            httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs, "UTF-8"));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return sendHttpPost(httpPost);
+    }
+
+
+
+    /**
+     * 发送Post请求
+     * @param httpPost
+     * @return
+     */
+    private String sendHttpPost(HttpPost httpPost) {
+        CloseableHttpClient httpClient = null;
+        CloseableHttpResponse response = null;
+        HttpEntity entity = null;
+        String responseContent = null;
+        try {
+            // 创建默认的httpClient实例.
+            httpClient = HttpClients.createDefault();
+            // 执行请求
+            response = httpClient.execute(httpPost);
+            entity = response.getEntity();
+            responseContent = EntityUtils.toString(entity, "UTF-8");
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                // 关闭连接,释放资源
+                if (response != null) {
+                    response.close();
+                }
+                if (httpClient != null) {
+                    httpClient.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return responseContent;
+    }
+
+    /**
+     * 发送 get请求
+     *
+     * @param httpUrl
+     */
+    public static String sendHttpGet(String httpUrl) {
+        HttpGet httpGet = new HttpGet(httpUrl);// 创建get请求
+        return sendHttpGet(httpGet);
+    }
+
+    /**
+     * 发送Get请求
+     * @param
+     * @return
+     */
+    private static String sendHttpGet(HttpGet httpGet) {
+        // 鍒涘缓璇锋眰閰嶇疆,璁剧疆杩炴帴鍜岃姹傝秴鏃舵椂闂
+        RequestConfig requestConfig = RequestConfig.custom()
+            .setConnectTimeout(5000)
+            .setSocketTimeout(5000)
+            .build();
+
+        CloseableHttpClient httpClient = null;
+        CloseableHttpResponse response = null;
+        HttpEntity entity = null;
+        String responseContent = null;
+        try {
+            // 鍒涘缓榛樿鐨刪ttpClient瀹炰緥锛屽苟璁剧疆璇锋眰閰嶇疆
+            httpClient = HttpClients.custom()
+                .setDefaultRequestConfig(requestConfig)
+                .build();
+            // 鎵ц璇锋眰
+            response = httpClient.execute(httpGet);
+            entity = response.getEntity();
+            responseContent = EntityUtils.toString(entity, "UTF-8");
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            try {
+                // 鍏抽棴杩炴帴锛岄噴鏀捐祫婧
+                if (response != null) {
+                    response.close();
+                }
+                if (httpClient != null) {
+                    httpClient.close();
+                }
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        }
+        return responseContent;
+    }
+
+
+}
+