feat: 完善堡垒机与 Agent 智能运维能力
- 支持 Windows Agent 构建、安装脚本和统一上报协议 - 增强 RDP 剪贴板、虚拟盘和文件传输能力 - 新增 AIOps 上下文工具、告警 RCA trace 落库和回放接口 - 重构 docs 模块文档并补充终端、堡垒机、监控、AI Agent 设计
This commit is contained in:
1 parent
a9513c2056
commit
e0d652d211
169 files changed
+12192
-9116
No files matched your search
@@ -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)
|
||||
```
|
||||
Reference in new issue
Block a user