admin/AMT_REALTIME_STATUS.md
lvfengfree 2e28ad1472 feat: 拆分设备状态为AMT状态和Agent状态
- 数据库:添加 amt_status 和 agent_status 字段
- 后端:Device 实体类和 DeviceDTO 添加新状态字段
- 后端:DeviceService 添加状态检测和更新方法
- 后端:添加 AmtStatusCheckTask 定时任务(每30秒检测一次)
- 前端:设备列表页面拆分状态列显示
- 前端:统计卡片显示 AMT 和 Agent 在线/离线数量
- 网络扫描:自动设置 AMT 状态为在线
- 文档:添加 DEVICE_STATUS_SPLIT.md 和 AMT_REALTIME_STATUS.md
2026-03-01 19:18:32 +08:00

418 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# AMT 实时状态检测功能
## 功能概述
实现了 AMT 设备状态的实时检测和自动更新功能,无需手动刷新即可看到设备的在线/离线状态变化。
## 实现方案
### 后端实现
#### 1. 定时任务 (AmtStatusCheckTask.java)
**位置**: `backend/src/main/java/com/soybean/admin/task/AmtStatusCheckTask.java`
**功能**:
- 每 30 秒自动检测一次所有设备的 AMT 状态
- 使用线程池并发检测,提高效率
- 只在状态变化时更新数据库,减少写入操作
- 使用 Socket 连接检测 AMT 端口16992/16993可用性
**关键特性**:
```java
@Scheduled(fixedRate = 30000, initialDelay = 10000)
public void checkAmtStatus() {
// 每 30 秒执行一次
// 初始延迟 10 秒,等待应用完全启动
}
```
**检测逻辑**:
1. 查询所有有 IP 地址的设备
2. 并发检测每个设备的 AMT 端口连接性
3. 先尝试 HTTP (16992),失败则尝试 HTTPS (16993)
4. 根据连接结果更新设备的 `amt_status` 字段
5. 只有状态变化时才更新数据库和记录日志
**线程池配置**:
- 固定 20 个线程
- 使用 CompletableFuture 异步执行
- 等待所有检测完成后结束任务
#### 2. 启用定时任务
**修改**: `backend/src/main/java/com/soybean/admin/SoybeanAdminApplication.java`
添加 `@EnableScheduling` 注解启用 Spring 定时任务功能:
```java
@SpringBootApplication
@MapperScan("com.soybean.admin.mapper")
@EnableScheduling // 启用定时任务
public class SoybeanAdminApplication {
// ...
}
```
### 前端实现
#### 1. 自动轮询刷新
**位置**: `src/views/device/list/index.vue`
**功能**:
- 页面加载后每 10 秒自动刷新设备列表
- 组件卸载时自动清除定时器
- 显示"自动刷新中"状态标签
**实现代码**:
```typescript
onMounted(() => {
loadData();
// 启动定时刷新,每 10 秒刷新一次设备状态
const refreshInterval = setInterval(() => {
loadData();
}, 10000);
// 组件卸载时清除定时器
onUnmounted(() => {
clearInterval(refreshInterval);
});
});
```
#### 2. 手动刷新按钮
添加了"刷新状态"按钮,用户可以随时手动刷新:
```vue
<n-button @click="handleManualRefresh" :loading="loading">
<icon-mdi-refresh class="mr-4px text-16px" />
刷新状态
</n-button>
```
#### 3. 状态指示器
显示自动刷新状态:
```vue
<n-tag v-if="autoRefreshEnabled" type="success" size="small">
<icon-mdi-autorenew class="mr-4px" />
自动刷新中
</n-tag>
```
## 工作流程
### 完整流程图
```
后端定时任务 (每30秒)
检测所有设备 AMT 端口
更新数据库状态
前端轮询 (每10秒)
获取最新设备列表
更新界面显示
```
### 时间线示例
```
T=0s: 后端启动10秒后开始第一次检测
T=10s: 后端第一次检测所有设备
T=10s: 前端页面加载,开始第一次数据获取
T=20s: 前端第二次刷新
T=30s: 前端第三次刷新
T=40s: 后端第二次检测 + 前端第四次刷新
T=50s: 前端第五次刷新
...
```
## 性能优化
### 后端优化
1. **并发检测**: 使用 20 个线程并发检测,大幅提升检测速度
2. **快速超时**: Socket 连接超时设置为 3 秒,避免长时间等待
3. **增量更新**: 只在状态变化时更新数据库
4. **简单检测**: 只检测端口连接性,不进行完整的 AMT 认证
### 前端优化
1. **合理间隔**: 10 秒刷新间隔,平衡实时性和性能
2. **自动清理**: 组件卸载时清除定时器,避免内存泄漏
3. **加载状态**: 显示加载状态,提升用户体验
## 状态检测逻辑
### 检测方法
使用 TCP Socket 连接检测,而不是完整的 AMT 认证:
```java
private boolean checkAmtConnectivity(String ipAddress) {
try {
// 尝试连接 AMT HTTP 端口
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, 16992), 3000);
socket.close();
return true;
} catch (Exception e) {
// HTTP 失败,尝试 HTTPS
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ipAddress, 16993), 3000);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
}
```
### 优点
1. **快速**: 不需要完整的 SOAP 请求和认证
2. **轻量**: 只检测端口可用性
3. **可靠**: 能准确判断 AMT 服务是否运行
### 缺点
1. **不验证认证**: 不检查凭证是否正确
2. **端口占用**: 如果端口被其他服务占用,可能误判
## 使用说明
### 1. 执行数据库更新
如果还没有执行过数据库更新,先运行:
```bash
update_device_status.bat
```
### 2. 重新编译后端
```bash
cd backend
mvn clean package -DskipTests
```
### 3. 启动后端服务
```bash
start_backend.bat
```
后端启动后,会在 10 秒后开始第一次 AMT 状态检测,之后每 30 秒检测一次。
### 4. 打开前端页面
访问设备列表页面,会看到:
- 右上角显示"自动刷新中"标签
- 设备的 AMT 状态列实时更新
- 可以点击"刷新状态"按钮手动刷新
## 日志查看
### 后端日志
查看后端控制台输出,会看到类似日志:
```
开始 AMT 状态检测任务
开始检测 10 个设备的 AMT 状态
设备 Server-01 (192.168.8.100) AMT 状态变化: offline -> online
设备 Server-02 (192.168.8.101) AMT 状态变化: online -> offline
AMT 状态检测任务完成
```
### 前端日志
打开浏览器开发者工具,可以看到每 10 秒发送一次设备列表请求。
## 测试场景
### 场景 1: 设备上线
1. 启动一台 AMT 设备
2. 等待最多 30 秒(后端检测周期)
3. 前端会在下次刷新时显示设备状态变为"在线"
### 场景 2: 设备下线
1. 关闭一台 AMT 设备
2. 等待最多 30 秒(后端检测周期)
3. 前端会在下次刷新时显示设备状态变为"离线"
### 场景 3: 手动刷新
1. 点击"刷新状态"按钮
2. 立即获取最新的设备状态
3. 不需要等待自动刷新周期
## 配置参数
### 后端配置
`AmtStatusCheckTask.java` 中可以调整:
```java
// 检测周期(毫秒)
@Scheduled(fixedRate = 30000, initialDelay = 10000)
// fixedRate: 30000 = 30秒
// initialDelay: 10000 = 10秒初始延迟
// 线程池大小
private final ExecutorService executorService = Executors.newFixedThreadPool(20);
// 20 个线程
// Socket 超时时间(毫秒)
socket.connect(new InetSocketAddress(ipAddress, 16992), 3000);
// 3000 = 3秒
```
### 前端配置
`index.vue` 中可以调整:
```typescript
// 刷新周期(毫秒)
const refreshInterval = setInterval(() => {
loadData();
}, 10000); // 10000 = 10秒
```
## 性能影响
### 后端资源消耗
- **CPU**: 低(主要是网络 I/O 等待)
- **内存**: 低20 个线程 + 设备列表)
- **网络**: 每个设备每 30 秒一次连接检测
### 前端资源消耗
- **网络**: 每 10 秒一次 API 请求
- **内存**: 低(只更新设备列表数据)
- **CPU**: 低(简单的数据更新和渲染)
### 数据库影响
- **读取**: 每 30 秒读取所有设备列表
- **写入**: 只在状态变化时写入(增量更新)
- **索引**: 建议在 `ip_address``amt_status` 字段上建立索引
## 后续优化建议
### 1. WebSocket 推送
替代轮询方式,使用 WebSocket 实时推送状态变化:
**优点**:
- 更实时
- 减少网络请求
- 降低服务器负载
**实现**:
- 后端使用 Spring WebSocket
- 状态变化时主动推送到前端
- 前端监听 WebSocket 消息更新界面
### 2. 智能检测频率
根据设备状态调整检测频率:
- 在线设备: 每 60 秒检测一次
- 离线设备: 每 30 秒检测一次
- 新添加设备: 每 10 秒检测一次(前 5 分钟)
### 3. 批量状态查询接口
添加专门的状态查询接口,只返回状态信息:
```java
@GetMapping("/device/status")
public Result<Map<Long, String>> getDeviceStatus() {
// 只返回 id -> status 的映射
// 减少数据传输量
}
```
### 4. 状态变化通知
设备状态变化时发送通知:
- 邮件通知
- 短信通知
- 系统消息通知
- Webhook 回调
### 5. 历史状态记录
记录设备状态变化历史:
- 创建 `device_status_history`
- 记录每次状态变化的时间和原因
- 生成可用性报表
## 故障排查
### 问题 1: 状态不更新
**可能原因**:
- 后端定时任务未启动
- 数据库连接失败
- 网络不通
**排查方法**:
1. 查看后端日志是否有"开始 AMT 状态检测任务"
2. 检查数据库 `amt_status` 字段是否存在
3. 手动测试设备网络连接
### 问题 2: 前端不刷新
**可能原因**:
- 定时器未启动
- API 请求失败
- 组件已卸载
**排查方法**:
1. 打开浏览器开发者工具查看网络请求
2. 检查控制台是否有错误
3. 确认 `autoRefreshEnabled` 为 true
### 问题 3: 性能问题
**可能原因**:
- 设备数量过多
- 检测频率过高
- 网络延迟大
**解决方案**:
1. 增加检测周期(如改为 60 秒)
2. 增加线程池大小
3. 使用 WebSocket 替代轮询
## 总结
实现了完整的 AMT 实时状态检测功能:
✅ 后端定时任务自动检测(每 30 秒)
✅ 前端自动刷新显示(每 10 秒)
✅ 手动刷新按钮
✅ 状态指示器
✅ 并发检测优化
✅ 增量数据库更新
✅ 完整的日志记录
用户无需手动刷新,即可实时看到设备的 AMT 在线/离线状态变化。