merge: 合并远程 A2 告警引擎分布式安全更新,保留本地日志中心等最新改动

This commit is contained in:
Logan committed 2026-06-26 23:19:42 +08:00
commit 23e9e3da62
137 files changed
+947 -611

No files matched your search

+90 -5
View File
@@ -1,32 +1,117 @@
package controller
import (
"context"
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"log"
"time"
"ezops/model"
ezredis "ezops/pkg/redis"
"gorm.io/gorm"
)
// AlertEngine 告警引擎 — 定时扫描 Agent 上报数据并触发告警 // Logan.Li
// AlertEngine 告警引擎 — 定时扫描 Agent 上报数据并触发告警
// 支持分布式锁:多副本部署时仅 Leader 执行检查,避免重复告警
type AlertEngine struct {
db *gorm.DB
db *gorm.DB
cache ezredis.Cache // 可选 Redis 缓存(分布式锁)
instanceID string // 当前实例唯一标识
}
func NewAlertEngine(db *gorm.DB) *AlertEngine {
return &AlertEngine{db: db}
const (
alertEngineLockKey = "aiops:alert_engine:lock"
alertEngineLockTTL = 60 * time.Second // 锁 TTL:2x tick 间隔,保证处理时间内不释放
)
// NewAlertEngine 创建告警引擎实例
// cache 参数用于分布式锁(多副本部署)。nil 时为单实例模式,不竞争锁。
func NewAlertEngine(db *gorm.DB, cache ezredis.Cache) *AlertEngine {
// 生成唯一实例 ID(随机 hex,防止多副本 PID/hostname 碰撞)
idBytes := make([]byte, 8)
_, _ = rand.Read(idBytes)
instanceID := fmt.Sprintf("ae-%s", hex.EncodeToString(idBytes))
return &AlertEngine{
db: db,
cache: cache,
instanceID: instanceID,
}
}
// Check 每 30 秒调用一次
// Check 每 30 秒调用一次。多副本模式下通过分布式锁保证仅 Leader 执行。
// 无 cache(单实例/缓存初始化失败)→ 直接执行
// 有 cache(Docker/K8s 多副本)→ SetNX 原子抢锁
// Redis 故障 → fail-open(继续执行,避免告警遗漏)
func (e *AlertEngine) Check() {
if !e.tryAcquireLock() {
log.Printf("[AlertEngine] 非 Leader 副本(%s),跳过本轮检查", e.instanceID)
return
}
defer e.releaseLock()
e.checkResourceAlerts()
e.checkOfflineAlerts()
e.checkPortAlerts()
e.autoResolveAlerts()
}
// tryAcquireLock 尝试获取分布式锁,返回是否获得 Leader 角色
func (e *AlertEngine) tryAcquireLock() bool {
if e.cache == nil {
return true // 单实例模式
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
acquired, err := e.cache.SetNX(ctx, alertEngineLockKey, e.instanceID, alertEngineLockTTL)
if err != nil {
log.Printf("[AlertEngine] 获取分布式锁失败(%s),fail-open 继续: %v", e.instanceID, err)
return true
}
return acquired
}
// releaseLock 释放分布式锁(仅当当前实例持有锁时才释放,防止误删其他副本的锁)
func (e *AlertEngine) releaseLock() {
if e.cache == nil {
return
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
val, err := e.cache.Get(ctx, alertEngineLockKey)
if err != nil {
return
}
if val == e.instanceID {
_ = e.cache.Del(ctx, alertEngineLockKey)
}
}
// GetEngineStatus 返回告警引擎运行状态(用于运维监控)
func (e *AlertEngine) GetEngineStatus() map[string]interface{} {
isLeader := true
lockHolder := ""
if e.cache != nil {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if val, err := e.cache.Get(ctx, alertEngineLockKey); err == nil {
lockHolder = val
isLeader = lockHolder == "" || lockHolder == e.instanceID
}
}
return map[string]interface{}{
"is_leader": isLeader,
"instance_id": e.instanceID,
"lock_holder": lockHolder,
"distributed": e.cache != nil,
"tick_interval": 30,
"lock_ttl_sec": int(alertEngineLockTTL / time.Second),
}
}
// 检查 CPU/内存/磁盘/进程/TCP连接/端口 阈值
func (e *AlertEngine) checkResourceAlerts() {
var rules []model.AgentRule