feat: 完善堡垒机与 Agent 智能运维能力

- 支持 Windows Agent 构建、安装脚本和统一上报协议

- 增强 RDP 剪贴板、虚拟盘和文件传输能力

- 新增 AIOps 上下文工具、告警 RCA trace 落库和回放接口

- 重构 docs 模块文档并补充终端、堡垒机、监控、AI Agent 设计
This commit is contained in:
Logan.Li committed 2026-07-05 23:49:36 +08:00
1 parent a9513c2056
commit e0d652d211
169 files changed
+12192 -9116

No files matched your search

+183
View File
@@ -0,0 +1,183 @@
# Redis 缓存策略文档
> 版本: v0.43 | 最后更新: 2026-06-24
## 缓存总览
| 模块 | 缓存 | 方式 | Key 格式 | TTL | 说明 |
|------|:--:|------|----------|-----|------|
| Agent 指标热数据 | ✅ | Sorted Set | `agent:metrics:{hostname}:{metric}` | 7 天 | 聚合后批量写 MySQL |
| 流水线日志 | ✅ | pub/sub + String | `pipeline:log:{runId}` | 30 min | 实时推送 + 历史缓存 |
| Dashboard 统计 | ✅ | String (JSON) | `dashboard:stats` | 30 s | ~25 次 SQL → 1 次 Redis Get |
| 服务器列表 | ✅ | String (JSON) | `servers:list:{kw}:{st}:{reg}:{p}:{ps}` | 10 s | JOIN 查询 → 缓存命中 ~1ms |
| 告警中心 | ❌ | — | — | — | 表小,直接查 MySQL |
| K8s 资源 | ❌ | — | — | — | 走 K8s API,不经过 MySQL |
## 缓存后端
支持双后端,通过配置 `driver` 字段切换:
| Driver | 场景 | 依赖 |
|--------|------|------|
| `redis` | Docker / 生产环境 | 外部 Redis 7 容器 |
| `redka` | 二进制独立部署 | 内嵌,零依赖 |
```yaml
# config.yaml
redis:
driver: redis # redis | redka
host: aiops-redis # Docker 容器名
port: 6379
password: ""
db: 0
```
初始化逻辑在 `backend/cmd/main.go:129`,如果 Redis 不可用则 `cache = nil`,业务自动回退到无缓存模式。
## 缓存接口
```go
// pkg/redis/redis.go
type Cache interface {
Get(ctx, key) (string, error)
Set(ctx, key, value, expiration) error
Del(ctx, keys...) error
// ... ZAdd / ZRangeByScore / Publish 等
}
```
## 各缓存详解
### 1. Dashboard 统计 — `dashboard:stats`
**缓存位置**: `handlers/dashboard.go:GetStats`
**变更频率**: 低(统计数据,30s 延迟可接受)
**Key**: 全局单键 `dashboard:stats`
**实现流程**:
```
请求 → cache.Get("dashboard:stats")
├─ hit → json.Unmarshal → 返回(跳过 ~25 次 SQL)
└─ miss → MySQL 聚合查询 → json.Marshal → cache.Set(30s) → 返回
```
**写入不是异步的**:`cache.Set` 使用 `context.Background()`,缓存写失败不影响 HTTP 响应。
```go
// 读缓存
if cached, err := h.cache.Get(c.Request.Context(), cacheKey); err == nil && cached != "" {
var stats models.DashboardStats
if json.Unmarshal([]byte(cached), &stats) == nil {
c.JSON(200, Response{Data: stats})
return
}
}
// ... 查询逻辑 ...
// 写缓存
if data, err := json.Marshal(stats); err == nil {
_ = h.cache.Set(context.Background(), cacheKey, string(data), 30*time.Second)
}
```
### 2. 服务器列表 — `servers:list:*`
**缓存位置**: `handlers/server.go:ListServers`
**变更频率**: 低(服务器列表相对稳定,10s TTL 足够短)
**Key 格式**: `servers:list:{keyword}:{status}:{region_id}:{page}:{page_size}`
- 按查询参数区分,不同过滤条件独立缓存
- 写操作不主动失效(TTL 10s 自动过期)
**实现流程**:
```
请求 → cache.Get("servers:list:{params}")
├─ hit → json.Unmarshal → 返回(跳过 Preload JOIN)
└─ miss → MySQL 查询 → json.Marshal → cache.Set(10s) → 返回
```
```go
// 读缓存
if h.cache != nil {
if cached, err := h.cache.Get(c.Request.Context(), cacheKey); err == nil && cached != "" {
var resp models.Response
if json.Unmarshal([]byte(cached), &resp) == nil {
c.JSON(200, resp)
return
}
}
}
// ... 查询逻辑 ...
// 写缓存
if h.cache != nil {
if data, err := json.Marshal(resp); err == nil {
_ = h.cache.Set(context.Background(), cacheKey, string(data), 10*time.Second)
}
}
```
### 3. Agent 指标热数据
**缓存位置**: `handlers/agent.go`
**Key 格式**: `agent:metrics:{hostname}:{metric}` (Sorted Set)
- Agent 上报数据先写 Redis Sorted Set(速度快)
- 定时任务批量聚合后写入 MySQL(持久化)
- TTL 7 天,历史数据以 MySQL 为准
### 4. 流水线日志
**缓存位置**: `handlers/ws_pipeline_log.go` + `handlers/pipeline.go`
- **实时推送**: Redis Pub/Sub,构建输出实时流式推送到前端
- **历史缓存**: `pipeline:log:{runId}`,TTL 30 min
- 超过 30 min 的日志从 MySQL 回查
## 容错设计
| 场景 | 行为 |
|------|------|
| Redis 不可用(启动时) | `cache = nil`,日志 Warn,正常启动 |
| Redis 不可用(运行时) | `cache.Get()` 返回 error → 走 MySQL |
| 缓存值反序列化失败 | 走 MySQL(原逻辑) |
| 缓存写失败 | 静默忽略(`_ = h.cache.Set(...)`) |
**关键原则:缓存是加速层,不是依赖。任何缓存故障都不影响功能正确性。**
## 缓存大小估算
| Key | 单条大小 | 数量 | 估算总量 |
|-----|---------|------|---------|
| `dashboard:stats` | ~3 KB | 1 | ~3 KB |
| `servers:list:*` | ~5 KB/组合 | ~5-10(常用过滤组合) | ~50 KB |
| `agent:metrics:*` | ~200 B/指标 | ~15 指标 × 7 主机 | ~21 KB |
| `pipeline:log:*` | ~50 KB/运行 | ~5 并发 | ~250 KB |
| **合计** | | | **< 500 KB** |
## 性能对比
| 端点 | 缓存前 | 缓存命中 | 加速比 |
|------|--------|---------|--------|
| `GET /dashboard/stats` | ~150ms (~25 SQL) | ~1ms | ~150x |
| `GET /servers` | ~10ms (Preload JOIN) | ~1ms | ~10x |
## Handler 缓存字段一览
所有带缓存的 handler 都持有 `cache ezredis.Cache` 字段,由 `routes.go` 统一注入:
```go
// routes.go
redisCache, _ := cache.(ezredis.Cache)
dashboardHandler := handlers.NewDashboardHandler(db, redisCache)
serverHandler := handlers.NewServerHandler(db, cfg.JWT.Secret, redisCache)
pipelineHandler := handlers.NewPipelineHandler(db, redisCache)
wsLogHandler := handlers.NewWSPipelineLogHandler(db, redisCache)
agentHandler := handlers.NewAgentHandler(db, redisCache, metricsHub)
```