系统监控
CmdAdmin 提供完善的系统监控功能,包括服务器监控和 Redis 缓存监控。
服务器监控
实时监控服务器的运行状态,包括 CPU、内存、磁盘和 JVM。
监控指标
CPU 监控
| 指标 | 说明 |
|---|---|
| 系统负载 | 系统整体 CPU 使用率 |
| 用户使用率 | 用户进程 CPU 使用率 |
| 系统使用率 | 系统进程 CPU 使用率 |
| 平均负载 | 1分钟/5分钟/15分钟平均负载 |
内存监控
| 指标 | 说明 |
|---|---|
| 总内存 | 服务器总内存 |
| 已用内存 | 已使用的内存 |
| 剩余内存 | 可用内存 |
| 使用率 | 内存使用百分比 |
磁盘监控
| 指标 | 说明 |
|---|---|
| 总空间 | 磁盘总容量 |
| 已用空间 | 已使用的空间 |
| 剩余空间 | 可用空间 |
| 使用率 | 磁盘使用百分比 |
JVM 监控
| 指标 | 说明 |
|---|---|
| JVM 名称 | Java 虚拟机名称 |
| JVM 版本 | Java 版本信息 |
| 启动时间 | JVM 启动时间 |
| 运行时长 | JVM 已运行时间 |
| 堆内存 | 堆内存使用情况 |
| 非堆内存 | 非堆内存使用情况 |
API 接口
java
@RestController
@RequestMapping("/system/monitor")
public class ServerMonitorController {
/**
* 获取服务器基本信息
*/
@GetMapping("/info")
public Result<ServerInfo> getServerInfo() {
ServerInfo info = new ServerInfo();
info.setOsName(System.getProperty("os.name"));
info.setOsVersion(System.getProperty("os.version"));
info.setJavaVersion(System.getProperty("java.version"));
info.setJvmName(System.getProperty("java.vm.name"));
info.setJvmVersion(System.getProperty("java.vm.version"));
info.setJvmStartTime(new Date(ManagementFactory.getRuntimeMXBean().getStartTime()));
return Result.ok(info);
}
/**
* 获取服务器负载信息
*/
@GetMapping("/load")
public Result<ServerLoad> getServerLoad() {
ServerLoad load = new ServerLoad();
// CPU 信息
OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
load.setCpuUsage(getCpuUsage());
load.setCpuLoad(osBean.getSystemLoadAverage());
// 内存信息
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
load.setJvmMemoryUsed(heapUsage.getUsed());
load.setJvmMemoryMax(heapUsage.getMax());
// 磁盘信息
File root = new File("/");
load.setDiskTotal(root.getTotalSpace());
load.setDiskFree(root.getFreeSpace());
return Result.ok(load);
}
}前端展示
vue
<template>
<div class="monitor-container">
<!-- CPU 监控卡片 -->
<el-card class="monitor-card">
<template #header>
<span>CPU 监控</span>
</template>
<div class="cpu-info">
<el-progress
:percentage="cpuUsage"
:color="cpuColor"
type="dashboard"
/>
<div class="detail">
<p>系统负载:{{ systemLoad }}%</p>
<p>用户负载:{{ userLoad }}%</p>
<p>平均负载:{{ avgLoad }}</p>
</div>
</div>
</el-card>
<!-- 内存监控卡片 -->
<el-card class="monitor-card">
<template #header>
<span>内存监控</span>
</template>
<div class="memory-info">
<el-progress
:percentage="memoryUsage"
:color="memoryColor"
type="dashboard"
/>
<div class="detail">
<p>总内存:{{ formatSize(memoryTotal) }}</p>
<p>已用:{{ formatSize(memoryUsed) }}</p>
<p>剩余:{{ formatSize(memoryFree) }}</p>
</div>
</div>
</el-card>
<!-- 磁盘监控卡片 -->
<el-card class="monitor-card">
<template #header>
<span>磁盘监控</span>
</template>
<div class="disk-info">
<el-progress
:percentage="diskUsage"
:color="diskColor"
type="dashboard"
/>
<div class="detail">
<p>总空间:{{ formatSize(diskTotal) }}</p>
<p>已用:{{ formatSize(diskUsed) }}</p>
<p>剩余:{{ formatSize(diskFree) }}</p>
</div>
</div>
</el-card>
<!-- JVM 监控卡片 -->
<el-card class="monitor-card">
<template #header>
<span>JVM 监控</span>
</template>
<div class="jvm-info">
<p>JVM 名称:{{ jvmName }}</p>
<p>JVM 版本:{{ jvmVersion }}</p>
<p>启动时间:{{ jvmStartTime }}</p>
<p>运行时长:{{ jvmUptime }}</p>
<p>堆内存:{{ formatSize(jvmHeapUsed) }} / {{ formatSize(jvmHeapMax) }}</p>
</div>
</el-card>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { getServerInfo, getServerLoad } from '@/api/monitor'
const cpuUsage = ref(0)
const memoryUsage = ref(0)
const diskUsage = ref(0)
// 定时刷新数据
let timer = null
const fetchData = async () => {
const { data } = await getServerLoad()
cpuUsage.value = data.cpuUsage
memoryUsage.value = data.memoryUsage
diskUsage.value = data.diskUsage
}
onMounted(() => {
fetchData()
timer = setInterval(fetchData, 5000) // 每5秒刷新
})
onUnmounted(() => {
clearInterval(timer)
})
</script>Redis 缓存监控
监控 Redis 连接状态和缓存使用情况。
监控指标
| 指标 | 说明 |
|---|---|
| 连接状态 | Redis 是否连接正常 |
| 版本信息 | Redis 服务器版本 |
| 运行模式 | 单机/集群/哨兵模式 |
| 已用内存 | Redis 使用的内存 |
| 内存峰值 | 内存使用峰值 |
| Key 数量 | 当前数据库 Key 数量 |
| 命中率 | 缓存命中率 |
| 已连接客户端 | 当前连接数 |
缓存管理
java
@RestController
@RequestMapping("/system/cache")
public class SysCacheController {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 获取缓存列表
*/
@GetMapping("/list")
public Result<List<CacheInfo>> list() {
Properties info = redisTemplate.execute(
connection -> connection.serverCommands().info()
);
List<CacheInfo> list = new ArrayList<>();
// 解析 Redis info 信息...
return Result.ok(list);
}
/**
* 获取缓存详情
*/
@GetMapping("/info")
public Result<CacheDetail> info(@RequestParam String key) {
CacheDetail detail = new CacheDetail();
detail.setKey(key);
detail.setType(redisTemplate.type(key).name());
detail.setTtl(redisTemplate.getExpire(key));
detail.setValue(redisTemplate.opsForValue().get(key));
return Result.ok(detail);
}
/**
* 删除缓存
*/
@DeleteMapping("/delete")
public Result<Void> delete(@RequestParam String key) {
redisTemplate.delete(key);
return Result.ok();
}
/**
* 批量删除缓存
*/
@DeleteMapping("/batchDelete")
public Result<Void> batchDelete(@RequestBody List<String> keys) {
redisTemplate.delete(keys);
return Result.ok();
}
/**
* 清空所有缓存
*/
@DeleteMapping("/clear")
public Result<Void> clear() {
Set<String> keys = redisTemplate.keys("*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
return Result.ok();
}
}前端缓存管理界面
vue
<template>
<div class="cache-container">
<!-- 缓存统计 -->
<el-row :gutter="20">
<el-col :span="6">
<el-statistic title="Key 数量" :value="cacheStats.keyCount" />
</el-col>
<el-col :span="6">
<el-statistic title="已用内存" :value="formatSize(cacheStats.usedMemory)" />
</el-col>
<el-col :span="6">
<el-statistic title="命中率" :value="cacheStats.hitRate" suffix="%" />
</el-col>
<el-col :span="6">
<el-statistic title="连接数" :value="cacheStats.connectedClients" />
</el-col>
</el-row>
<!-- 缓存列表 -->
<el-table :data="cacheList" v-loading="loading">
<el-table-column prop="key" label="Key" show-overflow-tooltip />
<el-table-column prop="type" label="类型" width="100" />
<el-table-column prop="ttl" label="过期时间" width="150">
<template #default="{ row }">
{{ row.ttl > 0 ? formatDuration(row.ttl) : '永不过期' }}
</template>
</el-table-column>
<el-table-column prop="size" label="大小" width="100">
<template #default="{ row }">
{{ formatSize(row.size) }}
</template>
</el-table-column>
<el-table-column label="操作" width="200" fixed="right">
<template #default="{ row }">
<el-button type="primary" link @click="viewDetail(row)">查看</el-button>
<el-button type="danger" link @click="deleteCache(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 批量操作 -->
<div class="batch-actions">
<el-button type="danger" @click="clearAll">清空所有缓存</el-button>
</div>
</div>
</template>在线用户监控
查看当前在线用户列表,支持强制下线。
java
@RestController
@RequestMapping("/system/online")
public class OnlineUserController {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
/**
* 获取在线用户列表
*/
@GetMapping("/list")
public Result<List<OnlineUser>> list() {
Set<String> keys = redisTemplate.keys("login_token:*");
List<OnlineUser> list = new ArrayList<>();
for (String key : keys) {
LoginUser user = (LoginUser) redisTemplate.opsForValue().get(key);
if (user != null) {
OnlineUser online = new OnlineUser();
online.setUserId(user.getUserId());
online.setUsername(user.getUsername());
online.setLoginTime(user.getLoginTime());
online.setLoginIp(user.getLoginIp());
online.setLoginLocation(user.getLoginLocation());
online.setBrowser(user.getBrowser());
online.setOs(user.getOs());
list.add(online);
}
}
return Result.ok(list);
}
/**
* 强制下线
*/
@DeleteMapping("/kickout/{token}")
public Result<Void> kickout(@PathVariable String token) {
redisTemplate.delete("login_token:" + token);
return Result.ok();
}
}监控告警
可以配置告警规则,当指标超过阈值时发送通知:
java
@Component
public class MonitorAlertJob implements Job {
@Autowired
private ServerMonitorService monitorService;
@Override
public void execute(JobExecutionContext context) {
ServerLoad load = monitorService.getServerLoad();
// CPU 告警
if (load.getCpuUsage() > 80) {
sendAlert("CPU 使用率超过 80%: " + load.getCpuUsage() + "%");
}
// 内存告警
if (load.getMemoryUsage() > 85) {
sendAlert("内存使用率超过 85%: " + load.getMemoryUsage() + "%");
}
// 磁盘告警
if (load.getDiskUsage() > 90) {
sendAlert("磁盘使用率超过 90%: " + load.getDiskUsage() + "%");
}
}
private void sendAlert(String message) {
// 发送邮件/短信/钉钉通知...
}
}注意事项
- 性能影响:监控数据采集会消耗少量系统资源,建议合理设置采集频率
- 数据安全:缓存管理接口需要严格权限控制,防止误删重要数据
- 告警阈值:根据实际业务场景调整告警阈值
- 历史数据:考虑将监控历史数据持久化,便于趋势分析