第8讲:记忆系统的监控与运维——Prometheus 指标、Grafana 面板与告警体系

一、监控架构

复制代码
┌──────────────────────────────────────────────────────────────────────────────┐
│                        记忆系统监控架构                                         │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                                │
│  ┌────────────────────────────────────────────────────────────────────────┐   │
│  │                          应用层 (Application)                             │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  │   │
│  │  │ Memory      │  │ Security    │  │ HA          │  │ Compress    │  │   │
│  │  │ Manager     │  │ Manager     │  │ Manager     │  │ Manager     │  │   │
│  │  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘  └──────┬──────┘  │   │
│  └─────────┼───────────────┼───────────────┼───────────────┼──────────┘   │
│            │               │               │               │               │
│            ▼               ▼               ▼               ▼               │
│  ┌────────────────────────────────────────────────────────────────────────┐   │
│  │                      指标收集层 (Metrics Collector)                      │   │
│  │                                                                        │   │
│  │  ┌──────────────────────────────────────────────────────────────────┐  │   │
│  │  │                  Prometheus HTTP Handler (/metrics)              │  │   │
│  │  └──────────────────────────────────────────────────────────────────┘  │   │
│  │                                                                        │   │
│  │  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  │   │
│  │  │ Counter     │  │ Gauge       │  │ Histogram   │  │ Summary     │  │   │
│  │  │ (计数)      │  │ (瞬时值)    │  │ (分布)      │  │ (分位数)    │  │   │
│  │  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘  │   │
│  └────────────────────────────────┬───────────────────────────────────────┘   │
│                                   │                                             │
│                                   ▼                                             │
│  ┌────────────────────────────────────────────────────────────────────────┐   │
│  │                     指标暴露层 (Exporter)                                │   │
│  │                                                                        │   │
│  │  ┌────────────────────┐  ┌────────────────────┐  ┌──────────────────┐  │   │
│  │  │ 内置 Metrics       │  │ 自定义 Collector   │  │ 健康检查端点     │  │   │
│  │  │ Go runtime         │  │ 业务指标           │  │ /healthz         │  │   │
│  │  │ 进程指标           │  │ 层级别指标         │  │ /readyz          │  │   │
│  │  └────────────────────┘  └────────────────────┘  └──────────────────┘  │   │
│  └────────────────────────────────┬───────────────────────────────────────┘   │
│                                   │                                             │
│                                   ▼                                             │
│  ┌────────────────────────────────────────────────────────────────────────┐   │
│  │                       数据存储与可视化层                                  │   │
│  │                                                                        │   │
│  │  ┌────────────────────┐  ┌────────────────────┐  ┌──────────────────┐  │   │
│  │  │ Prometheus Server  │  │ Grafana            │  │ Alertmanager     │  │   │
│  │  │ 时序数据库         │  │ 仪表盘             │  │ 告警管理         │  │   │
│  │  │ 抓取 / 查询        │  │ 图表 / 报警        │  │ 通知 / 静默      │  │   │
│  │  └────────────────────┘  └────────────────────┘  └──────────────────┘  │   │
│  └────────────────────────────────────────────────────────────────────────┘   │
│                                                                                │
│  ┌────────────────────────────────────────────────────────────────────────┐   │
│  │                       告警通知渠道                                       │   │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌────────┐ │   │
│  │  │ Email    │  │ Slack    │  │ WeChat   │  │ PagerDuty│  │ Webhook│ │   │
│  │  └──────────┘  └──────────┘  └──────────┘  └──────────┘  └────────┘ │   │
│  └────────────────────────────────────────────────────────────────────────┘   │
│                                                                                │
└──────────────────────────────────────────────────────────────────────────────┘

二、核心数据结构

复制代码
// memory/monitoring/types.go
package monitoring

import (
    "context"
    "sync"
    "time"
)

// MetricType 指标类型
type MetricType string

const (
    MetricCounter   MetricType = "counter"
    MetricGauge     MetricType = "gauge"
    MetricHistogram MetricType = "histogram"
    MetricSummary   MetricType = "summary"
)

// MetricLabel 指标标签
type MetricLabel struct {
    Name  string `json:"name"`
    Value string `json:"value"`
}

// MetricSample 指标样本
type MetricSample struct {
    Name      string         `json:"name"`
    Type      MetricType     `json:"type"`
    Value     float64        `json:"value"`
    Labels    []MetricLabel  `json:"labels,omitempty"`
    Timestamp time.Time      `json:"timestamp"`
    Help      string         `json:"help"`
}

// MemoryMetrics 记忆系统整体指标
type MemoryMetrics struct {
    // 操作计数
    TotalOps       int64            `json:"total_ops"`
    SuccessOps     int64            `json:"success_ops"`
    FailedOps      int64            `json:"failed_ops"`
    OpsByType      map[string]int64 `json:"ops_by_type"`      // save, get, search, delete
    OpsByLayer     map[string]int64 `json:"ops_by_layer"`     // working, episodic, semantic
    OpsByResult    map[string]int64 `json:"ops_by_result"`    // success, denied, error

    // 延迟
    LatencyP50     float64          `json:"latency_p50_ms"`
    LatencyP90     float64          `json:"latency_p90_ms"`
    LatencyP99     float64          `json:"latency_p99_ms"`
    AvgLatency     float64          `json:"avg_latency_ms"`

    // 存储
    TotalEntries   int64            `json:"total_entries"`
    EntriesByLayer map[string]int64 `json:"entries_by_layer"`
    StorageSize    int64            `json:"storage_size_bytes"`

    // 安全
    AuthCheckCount int64            `json:"auth_check_count"`
    AuthDeniedCount int64           `json:"auth_denied_count"`
    EncryptCount   int64            `json:"encrypt_count"`
    DecryptCount   int64            `json:"decrypt_count"`

    // 复制与高可用
    ReplicationLag map[string]int64 `json:"replication_lag"`
    FailoverCount  int64            `json:"failover_count"`
    IsLeader       bool             `json:"is_leader"`

    // 压缩
    CompressedCount int64           `json:"compressed_count"`
    ForgottenCount  int64           `json:"forgotten_count"`
    MergedCount     int64           `json:"merged_count"`

    UpdatedAt time.Time `json:"updated_at"`
}

// HealthStatus 健康检查状态
type HealthStatus struct {
    Status      string            `json:"status"`       // healthy, degraded, unhealthy
    Components  map[string]ComponentHealth `json:"components"`
    Uptime      string            `json:"uptime"`
    Version     string            `json:"version"`
    LastCheck   time.Time         `json:"last_check"`
}

type ComponentHealth struct {
    Status  string `json:"status"`  // up, down, degraded
    Message string `json:"message,omitempty"`
    Latency string `json:"latency,omitempty"`
}

// AlertRule 告警规则
type AlertRule struct {
    ID          string            `json:"id"`
    Name        string            `json:"name"`
    Metric      string            `json:"metric"`
    Condition   AlertCondition    `json:"condition"`
    Threshold   float64           `json:"threshold"`
    Duration    time.Duration     `json:"duration"`     // 持续多久才触发
    Severity    AlertSeverity     `json:"severity"`
    Labels      map[string]string `json:"labels"`
    Annotations map[string]string `json:"annotations"`
    Enabled     bool              `json:"enabled"`
}

type AlertCondition string

const (
    CondGreaterThan     AlertCondition = "gt"
    CondLessThan        AlertCondition = "lt"
    CondEqual           AlertCondition = "eq"
    CondNotEqual        AlertCondition = "ne"
    CondGreaterOrEqual  AlertCondition = "gte"
    CondLessOrEqual     AlertCondition = "lte"
)

type AlertSeverity string

const (
    SevCritical AlertSeverity = "critical"
    SevWarning  AlertSeverity = "warning"
    SevInfo     AlertSeverity = "info"
)

// MonitoringConfig 监控配置
type MonitoringConfig struct {
    Enabled          bool              `yaml:"enabled"`
    ListenAddr       string            `yaml:"listen_addr"`       // :9090
    MetricsPath      string            `yaml:"metrics_path"`      // /metrics
    HealthPath       string            `yaml:"health_path"`       // /healthz
    CollectInterval  string            `yaml:"collect_interval"`  // 15s
    ExportGoMetrics  bool              `yaml:"export_go_metrics"`
    ExportProcessMetrics bool          `yaml:"export_process_metrics"`
    HistogramBuckets []float64         `yaml:"histogram_buckets"`
    AlertRules       []AlertRule       `yaml:"alert_rules"`
}

// MetricsCollector 指标收集器接口
type MetricsCollector interface {
    Collect(ctx context.Context) ([]MetricSample, error)
    Name() string
}

三、指标收集器

复制代码
// memory/monitoring/collector.go
package monitoring

import (
    "context"
    "fmt"
    "log"
    "runtime"
    "sync"
    "time"

    "github.com/prometheus/client_golang/prometheus"
    "github.com/shirou/gopsutil/v3/cpu"
    "github.com/shirou/gopsutil/v3/disk"
    "github.com/shirou/gopsutil/v3/mem"
    "github.com/shirou/gopsutil/v3/net"
)

// MemoryCollector 记忆系统指标收集器
type MemoryCollector struct {
    metrics *MemoryMetrics
    mu      sync.RWMutex

    // Prometheus 指标
    totalOps        *prometheus.CounterVec
    latencyHist     *prometheus.HistogramVec
    activeEntries   prometheus.Gauge
    storageSize     prometheus.Gauge
    replicationLag  *prometheus.GaugeVec
    authDenied      *prometheus.CounterVec
    encryptOps      *prometheus.CounterVec
    compressOps     *prometheus.CounterVec

    collectors []MetricsCollector
    interval   time.Duration
    stopCh     chan struct{}
}

func NewMemoryCollector(config MonitoringConfig) *MemoryCollector {
    mc := &MemoryCollector{
        metrics: &MemoryMetrics{
            OpsByType:     make(map[string]int64),
            OpsByLayer:    make(map[string]int64),
            OpsByResult:   make(map[string]int64),
            EntriesByLayer: make(map[string]int64),
            ReplicationLag: make(map[string]int64),
        },
        interval: parseDuration(config.CollectInterval, 15*time.Second),
        stopCh:   make(chan struct{}),
    }

    // 初始化 Prometheus 指标
    mc.totalOps = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "memory_total_operations",
            Help: "Total number of memory operations",
        },
        []string{"type", "layer", "result"},
    )

    mc.latencyHist = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "memory_operation_latency_seconds",
            Help:    "Operation latency distribution",
            Buckets: config.HistogramBuckets,
        },
        []string{"type"},
    )

    mc.activeEntries = prometheus.NewGauge(
        prometheus.GaugeOpts{
            Name: "memory_active_entries",
            Help: "Number of active memory entries",
        },
    )

    mc.storageSize = prometheus.NewGauge(
        prometheus.GaugeOpts{
            Name: "memory_storage_size_bytes",
            Help: "Total storage size in bytes",
        },
    )

    mc.replicationLag = prometheus.NewGaugeVec(
        prometheus.GaugeOpts{
            Name: "memory_replication_lag",
            Help: "Replication lag in entries",
        },
        []string{"node_id"},
    )

    mc.authDenied = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "memory_auth_denied_total",
            Help: "Total authentication denials",
        },
        []string{"reason"},
    )

    mc.encryptOps = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "memory_encryption_operations_total",
            Help: "Total encryption/decryption operations",
        },
        []string{"operation"}, // encrypt, decrypt
    )

    mc.compressOps = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "memory_compress_operations_total",
            Help: "Total compression operations",
        },
        []string{"operation"}, // compress, forget, merge
    )

    // 注册指标
    prometheus.MustRegister(
        mc.totalOps,
        mc.latencyHist,
        mc.activeEntries,
        mc.storageSize,
        mc.replicationLag,
        mc.authDenied,
        mc.encryptOps,
        mc.compressOps,
    )

    return mc
}

// Start 启动自动收集
func (mc *MemoryCollector) Start() {
    ticker := time.NewTicker(mc.interval)
    go func() {
        for {
            select {
            case <-ticker.C:
                mc.collectSystemMetrics()
                mc.collectCustomMetrics()
            case <-mc.stopCh:
                ticker.Stop()
                return
            }
        }
    }()
    log.Printf("[MONITOR] Metrics collector started, interval=%v", mc.interval)
}

// Stop 停止收集
func (mc *MemoryCollector) Stop() {
    close(mc.stopCh)
}

// RecordOperation 记录操作
func (mc *MemoryCollector) RecordOperation(opType, layer, result string, latency time.Duration) {
    mc.mu.Lock()
    mc.metrics.TotalOps++
    if result == "success" {
        mc.metrics.SuccessOps++
    } else {
        mc.metrics.FailedOps++
    }
    mc.metrics.OpsByType[opType]++
    mc.metrics.OpsByLayer[layer]++
    mc.metrics.OpsByResult[result]++
    mc.metrics.AvgLatency = (mc.metrics.AvgLatency*float64(mc.metrics.TotalOps-1) +
        float64(latency.Milliseconds())) / float64(mc.metrics.TotalOps)
    mc.mu.Unlock()

    // Prometheus 指标
    mc.totalOps.WithLabelValues(opType, layer, result).Inc()
    mc.latencyHist.WithLabelValues(opType).Observe(latency.Seconds())
}

// RecordAuthDenial 记录认证拒绝
func (mc *MemoryCollector) RecordAuthDenial(reason string) {
    mc.mu.Lock()
    mc.metrics.AuthDeniedCount++
    mc.mu.Unlock()

    mc.authDenied.WithLabelValues(reason).Inc()
}

// RecordEncryption 记录加密操作
func (mc *MemoryCollector) RecordEncryption(operation string) {
    mc.mu.Lock()
    if operation == "encrypt" {
        mc.metrics.EncryptCount++
    } else {
        mc.metrics.DecryptCount++
    }
    mc.mu.Unlock()

    mc.encryptOps.WithLabelValues(operation).Inc()
}

// RecordCompression 记录压缩操作
func (mc *MemoryCollector) RecordCompression(operation string) {
    mc.mu.Lock()
    switch operation {
    case "compress":
        mc.metrics.CompressedCount++
    case "forget":
        mc.metrics.ForgottenCount++
    case "merge":
        mc.metrics.MergedCount++
    }
    mc.mu.Unlock()

    mc.compressOps.WithLabelValues(operation).Inc()
}

// UpdateEntriesCount 更新条目计数
func (mc *MemoryCollector) UpdateEntriesCount(layer string, count int64) {
    mc.mu.Lock()
    mc.metrics.EntriesByLayer[layer] = count
    total := int64(0)
    for _, c := range mc.metrics.EntriesByLayer {
        total += c
    }
    mc.metrics.TotalEntries = total
    mc.mu.Unlock()

    mc.activeEntries.Set(float64(total))
}

// UpdateStorageSize 更新存储大小
func (mc *MemoryCollector) UpdateStorageSize(size int64) {
    mc.mu.Lock()
    mc.metrics.StorageSize = size
    mc.mu.Unlock()

    mc.storageSize.Set(float64(size))
}

// UpdateReplicationLag 更新复制延迟
func (mc *MemoryCollector) UpdateReplicationLag(nodeID string, lag int64) {
    mc.mu.Lock()
    mc.metrics.ReplicationLag[nodeID] = lag
    mc.mu.Unlock()

    mc.replicationLag.WithLabelValues(nodeID).Set(float64(lag))
}

// GetMetrics 获取当前指标快照
func (mc *MemoryCollector) GetMetrics() *MemoryMetrics {
    mc.mu.RLock()
    defer mc.mu.RUnlock()

    snapshot := *mc.metrics
    snapshot.UpdatedAt = time.Now()
    return &snapshot
}

// collectSystemMetrics 收集系统指标
func (mc *MemoryCollector) collectSystemMetrics() {
    // CPU 使用率
    cpuPercent, err := cpu.Percent(0, false)
    if err == nil && len(cpuPercent) > 0 {
        prometheus.MustRegister(prometheus.NewGaugeFunc(
            prometheus.GaugeOpts{
                Name: "system_cpu_usage_percent",
                Help: "System CPU usage percentage",
            },
            func() float64 { return cpuPercent[0] },
        ))
    }

    // 内存使用
    memInfo, err := mem.VirtualMemory()
    if err == nil {
        prometheus.MustRegister(prometheus.NewGaugeFunc(
            prometheus.GaugeOpts{
                Name: "system_memory_usage_bytes",
                Help: "System memory usage in bytes",
            },
            func() float64 { return float64(memInfo.Used) },
        ))
    }

    // Go runtime 指标
    if mc.config.ExportGoMetrics {
        var m runtime.MemStats
        runtime.ReadMemStats(&m)
        // goroutines
        prometheus.MustRegister(prometheus.NewGaugeFunc(
            prometheus.GaugeOpts{
                Name: "go_goroutines",
                Help: "Number of goroutines",
            },
            func() float64 { return float64(runtime.NumGoroutine()) },
        ))
        // GC 次数
        prometheus.MustRegister(prometheus.NewGaugeFunc(
            prometheus.GaugeOpts{
                Name: "go_gc_total",
                Help: "Total GC cycles",
            },
            func() float64 { return float64(m.NumGC) },
        ))
    }
}

// collectCustomMetrics 收集自定义指标
func (mc *MemoryCollector) collectCustomMetrics() {
    for _, collector := range mc.collectors {
        samples, err := collector.Collect(context.Background())
        if err != nil {
            log.Printf("[MONITOR] Collector %s failed: %v", collector.Name(), err)
            continue
        }
        for _, sample := range samples {
            mc.processSample(sample)
        }
    }
}

// processSample 处理指标样本
func (mc *MemoryCollector) processSample(sample MetricSample) {
    labels := make([]string, len(sample.Labels)*2)
    for i, label := range sample.Labels {
        labels[i*2] = label.Name
        labels[i*2+1] = label.Value
    }

    switch sample.Type {
    case MetricCounter:
        counter := prometheus.NewCounterVec(
            prometheus.CounterOpts{
                Name: sample.Name,
                Help: sample.Help,
            },
            getLabelNames(sample.Labels),
        )
        counter.WithLabelValues(labels...).Add(sample.Value)
        prometheus.MustRegister(counter)

    case MetricGauge:
        gauge := prometheus.NewGaugeVec(
            prometheus.GaugeOpts{
                Name: sample.Name,
                Help: sample.Help,
            },
            getLabelNames(sample.Labels),
        )
        gauge.WithLabelValues(labels...).Set(sample.Value)
        prometheus.MustRegister(gauge)
    }
}

// RegisterCollector 注册自定义收集器
func (mc *MemoryCollector) RegisterCollector(collector MetricsCollector) {
    mc.collectors = append(mc.collectors, collector)
}

func getLabelNames(labels []MetricLabel) []string {
    names := make([]string, len(labels))
    for i, l := range labels {
        names[i] = l.Name
    }
    return names
}

func parseDuration(s string, defaultVal time.Duration) time.Duration {
    d, err := time.ParseDuration(s)
    if err != nil {
        return defaultVal
    }
    return d
}

四、健康检查

复制代码
// memory/monitoring/health.go
package monitoring

import (
    "context"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "sync"
    "time"
)

// HealthChecker 健康检查器
type HealthChecker struct {
    components map[string]HealthCheckFunc
    status     *HealthStatus
    mu         sync.RWMutex
    startTime  time.Time
    version    string
}

type HealthCheckFunc func(ctx context.Context) ComponentHealth

func NewHealthChecker(version string) *HealthChecker {
    return &HealthChecker{
        components: make(map[string]HealthCheckFunc),
        status: &HealthStatus{
            Status:     "healthy",
            Components: make(map[string]ComponentHealth),
            Version:    version,
        },
        startTime: time.Now(),
        version:   version,
    }
}

// RegisterCheck 注册健康检查函数
func (hc *HealthChecker) RegisterCheck(name string, fn HealthCheckFunc) {
    hc.mu.Lock()
    defer hc.mu.Unlock()
    hc.components[name] = fn
}

// Check 执行所有健康检查
func (hc *HealthChecker) Check(ctx context.Context) *HealthStatus {
    hc.mu.Lock()
    defer hc.mu.Unlock()

    status := &HealthStatus{
        Status:     "healthy",
        Components: make(map[string]ComponentHealth),
        Uptime:     time.Since(hc.startTime).String(),
        Version:    hc.version,
        LastCheck:  time.Now(),
    }

    for name, fn := range hc.components {
        componentStatus := fn(ctx)
        status.Components[name] = componentStatus

        if componentStatus.Status == "down" {
            status.Status = "unhealthy"
        } else if componentStatus.Status == "degraded" && status.Status == "healthy" {
            status.Status = "degraded"
        }
    }

    hc.status = status
    return status
}

// HTTPHandler HTTP 健康检查处理器
func (hc *HealthChecker) HTTPHandler(w http.ResponseWriter, r *http.Request) {
    ctx := r.Context()
    status := hc.Check(ctx)

    w.Header().Set("Content-Type", "application/json")

    switch r.URL.Path {
    case "/healthz":
        // 存活检查
        if status.Status == "unhealthy" {
            w.WriteHeader(http.StatusServiceUnavailable)
        } else {
            w.WriteHeader(http.StatusOK)
        }

    case "/readyz":
        // 就绪检查
        if status.Status == "unhealthy" || status.Status == "degraded" {
            w.WriteHeader(http.StatusServiceUnavailable)
        } else {
            w.WriteHeader(http.StatusOK)
        }

    default:
        w.WriteHeader(http.StatusOK)
    }

    json.NewEncoder(w).Encode(status)
}

// PredefinedChecks 预定义的健康检查

// DatabaseHealthCheck 数据库健康检查
func DatabaseHealthCheck(db interface{ Ping() error }) HealthCheckFunc {
    return func(ctx context.Context) ComponentHealth {
        start := time.Now()
        err := db.Ping()
        latency := time.Since(start)

        if err != nil {
            return ComponentHealth{
                Status:  "down",
                Message: fmt.Sprintf("database unreachable: %v", err),
                Latency: latency.String(),
            }
        }

        return ComponentHealth{
            Status:  "up",
            Message: "database connected",
            Latency: latency.String(),
        }
    }
}

// MemoryStoreHealthCheck 记忆存储健康检查
func MemoryStoreHealthCheck(store interface{ Count(ctx context.Context) (int64, error) }) HealthCheckFunc {
    return func(ctx context.Context) ComponentHealth {
        start := time.Now()
        count, err := store.Count(ctx)
        latency := time.Since(start)

        if err != nil {
            return ComponentHealth{
                Status:  "degraded",
                Message: fmt.Sprintf("store query failed: %v", err),
                Latency: latency.String(),
            }
        }

        return ComponentHealth{
            Status:  "up",
            Message: fmt.Sprintf("store healthy, %d entries", count),
            Latency: latency.String(),
        }
    }
}

// ClusterHealthCheck 集群健康检查
func ClusterHealthCheck(cluster interface{ GetLeader() string }) HealthCheckFunc {
    return func(ctx context.Context) ComponentHealth {
        leader := cluster.GetLeader()
        if leader == "" {
            return ComponentHealth{
                Status:  "down",
                Message: "no leader elected",
            }
        }

        return ComponentHealth{
            Status:  "up",
            Message: fmt.Sprintf("leader: %s", leader),
        }
    }
}

// EncryptionHealthCheck 加密模块健康检查
func EncryptionHealthCheck(encryptor interface{ Healthy() bool }) HealthCheckFunc {
    return func(ctx context.Context) ComponentHealth {
        if encryptor.Healthy() {
            return ComponentHealth{
                Status:  "up",
                Message: "encryption module healthy",
            }
        }

        return ComponentHealth{
            Status:  "degraded",
            Message: "encryption module degraded",
        }
    }
}

// DiskSpaceHealthCheck 磁盘空间健康检查
func DiskSpaceHealthCheck(path string, thresholdPercent float64) HealthCheckFunc {
    return func(ctx context.Context) ComponentHealth {
        diskInfo, err := disk.Usage(path)
        if err != nil {
            return ComponentHealth{
                Status:  "degraded",
                Message: fmt.Sprintf("cannot get disk info: %v", err),
            }
        }

        usedPercent := diskInfo.UsedPercent
        if usedPercent > thresholdPercent {
            return ComponentHealth{
                Status:  "degraded",
                Message: fmt.Sprintf("disk usage %.1f%% exceeds threshold %.1f%%", usedPercent, thresholdPercent),
            }
        }

        return ComponentHealth{
            Status:  "up",
            Message: fmt.Sprintf("disk usage %.1f%%", usedPercent),
        }
    }
}

五、告警管理器

复制代码
// memory/monitoring/alert.go
package monitoring

import (
    "context"
    "fmt"
    "log"
    "sync"
    "time"
)

// AlertManager 告警管理器
type AlertManager struct {
    rules      []AlertRule
    alerts     []*Alert
    evaluator  AlertEvaluator
    notifiers  []AlertNotifier
    silenceMap map[string]time.Time // rule_id -> until
    mu         sync.RWMutex
    evalInterval time.Duration
    stopCh     chan struct{}
}

type Alert struct {
    ID          string            `json:"id"`
    RuleID      string            `json:"rule_id"`
    Name        string            `json:"name"`
    Severity    AlertSeverity     `json:"severity"`
    Status      AlertStatus       `json:"status"` // firing, resolved
    Value       float64           `json:"value"`
    Threshold   float64           `json:"threshold"`
    StartedAt   time.Time         `json:"started_at"`
    ResolvedAt  *time.Time        `json:"resolved_at,omitempty"`
    Labels      map[string]string `json:"labels"`
    Annotations map[string]string `json:"annotations"`
}

type AlertStatus string

const (
    AlertFiring   AlertStatus = "firing"
    AlertResolved AlertStatus = "resolved"
)

type AlertEvaluator interface {
    Evaluate(rule AlertRule, metrics *MemoryMetrics) (bool, float64, error)
}

type AlertNotifier interface {
    Send(ctx context.Context, alert *Alert) error
    Name() string
}

func NewAlertManager(rules []AlertRule, evaluator AlertEvaluator, interval time.Duration) *AlertManager {
    am := &AlertManager{
        rules:        rules,
        alerts:       make([]*Alert, 0),
        evaluator:    evaluator,
        notifiers:    make([]AlertNotifier, 0),
        silenceMap:   make(map[string]time.Time),
        evalInterval: interval,
        stopCh:       make(chan struct{}),
    }
    return am
}

// Start 启动告警评估循环
func (am *AlertManager) Start(ctx context.Context, metricsProvider func() *MemoryMetrics) {
    ticker := time.NewTicker(am.evalInterval)
    go func() {
        for {
            select {
            case <-ticker.C:
                metrics := metricsProvider()
                am.evaluateAll(ctx, metrics)
            case <-am.stopCh:
                ticker.Stop()
                return
            }
        }
    }()
    log.Printf("[ALERT] Alert manager started, interval=%v, rules=%d", am.evalInterval, len(am.rules))
}

// Stop 停止告警评估
func (am *AlertManager) Stop() {
    close(am.stopCh)
}

// RegisterNotifier 注册通知器
func (am *AlertManager) RegisterNotifier(notifier AlertNotifier) {
    am.mu.Lock()
    defer am.mu.Unlock()
    am.notifiers = append(am.notifiers, notifier)
}

// SilenceRule 静默规则一段时间
func (am *AlertManager) SilenceRule(ruleID string, duration time.Duration) {
    am.mu.Lock()
    defer am.mu.Unlock()
    am.silenceMap[ruleID] = time.Now().Add(duration)
    log.Printf("[ALERT] Rule %s silenced until %v", ruleID, time.Now().Add(duration))
}

// evaluateAll 评估所有规则
func (am *AlertManager) evaluateAll(ctx context.Context, metrics *MemoryMetrics) {
    am.mu.RLock()
    rules := am.rules
    am.mu.RUnlock()

    for _, rule := range rules {
        if !rule.Enabled {
            continue
        }

        // 检查是否被静默
        am.mu.RLock()
        silenceUntil, silenced := am.silenceMap[rule.ID]
        am.mu.RUnlock()
        if silenced && time.Now().Before(silenceUntil) {
            continue
        }

        // 评估规则
        triggered, value, err := am.evaluator.Evaluate(rule, metrics)
        if err != nil {
            log.Printf("[ALERT] Evaluate rule %s failed: %v", rule.ID, err)
            continue
        }

        if triggered {
            am.fireAlert(ctx, rule, value)
        } else {
            am.resolveAlert(ctx, rule)
        }
    }
}

// fireAlert 触发告警
func (am *AlertManager) fireAlert(ctx context.Context, rule AlertRule, value float64) {
    am.mu.Lock()
    defer am.mu.Unlock()

    // 检查是否已经触发了相同的告警
    for _, alert := range am.alerts {
        if alert.RuleID == rule.ID && alert.Status == AlertFiring {
            return // 已触发,不重复发送
        }
    }

    alert := &Alert{
        ID:        fmt.Sprintf("alert-%d", time.Now().UnixNano()),
        RuleID:    rule.ID,
        Name:      rule.Name,
        Severity:  rule.Severity,
        Status:    AlertFiring,
        Value:     value,
        Threshold: rule.Threshold,
        StartedAt: time.Now(),
        Labels:    rule.Labels,
        Annotations: rule.Annotations,
    }

    am.alerts = append(am.alerts, alert)

    // 发送通知
    for _, notifier := range am.notifiers {
        if err := notifier.Send(ctx, alert); err != nil {
            log.Printf("[ALERT] Notifier %s failed: %v", notifier.Name(), err)
        }
    }

    log.Printf("[ALERT] FIRING: %s (value=%.2f, threshold=%.2f)", rule.Name, value, rule.Threshold)
}

// resolveAlert 解决告警
func (am *AlertManager) resolveAlert(ctx context.Context, rule AlertRule) {
    am.mu.Lock()
    defer am.mu.Unlock()

    for i, alert := range am.alerts {
        if alert.RuleID == rule.ID && alert.Status == AlertFiring {
            now := time.Now()
            am.alerts[i].Status = AlertResolved
            am.alerts[i].ResolvedAt = &now

            log.Printf("[ALERT] RESOLVED: %s", rule.Name)
            break
        }
    }
}

// GetActiveAlerts 获取活跃告警
func (am *AlertManager) GetActiveAlerts() []*Alert {
    am.mu.RLock()
    defer am.mu.RUnlock()

    var active []*Alert
    for _, alert := range am.alerts {
        if alert.Status == AlertFiring {
            active = append(active, alert)
        }
    }
    return active
}

// DefaultAlertEvaluator 默认告警评估器
type DefaultAlertEvaluator struct {
    duration time.Duration
}

func NewDefaultAlertEvaluator(duration time.Duration) *DefaultAlertEvaluator {
    return &DefaultAlertEvaluator{duration: duration}
}

func (e *DefaultAlertEvaluator) Evaluate(rule AlertRule, metrics *MemoryMetrics) (bool, float64, error) {
    var value float64

    switch rule.Metric {
    case "memory_failover_count":
        value = float64(metrics.FailoverCount)
    case "memory_replication_lag_max":
        maxLag := int64(0)
        for _, lag := range metrics.ReplicationLag {
            if lag > maxLag {
                maxLag = lag
            }
        }
        value = float64(maxLag)
    case "memory_auth_denied_rate":
        total := float64(metrics.AuthCheckCount)
        if total == 0 {
            return false, 0, nil
        }
        value = float64(metrics.AuthDeniedCount) / total * 100
    case "memory_latency_p99":
        value = metrics.LatencyP99
    case "memory_storage_usage":
        value = float64(metrics.StorageSize)
    case "memory_total_entries":
        value = float64(metrics.TotalEntries)
    default:
        return false, 0, fmt.Errorf("unknown metric: %s", rule.Metric)
    }

    switch rule.Condition {
    case CondGreaterThan:
        return value > rule.Threshold, value, nil
    case CondLessThan:
        return value < rule.Threshold, value, nil
    case CondGreaterOrEqual:
        return value >= rule.Threshold, value, nil
    case CondLessOrEqual:
        return value <= rule.Threshold, value, nil
    default:
        return false, value, nil
    }
}

六、通知器实现

复制代码
// memory/monitoring/notifiers.go
package monitoring

import (
    "bytes"
    "context"
    "encoding/json"
    "fmt"
    "log"
    "net/http"
    "time"
)

// SlackNotifier Slack 通知器
type SlackNotifier struct {
    webhookURL string
    channel    string
    username   string
    client     *http.Client
}

func NewSlackNotifier(webhookURL, channel, username string) *SlackNotifier {
    return &SlackNotifier{
        webhookURL: webhookURL,
        channel:    channel,
        username:   username,
        client:     &http.Client{Timeout: 10 * time.Second},
    }
}

func (sn *SlackNotifier) Name() string {
    return "slack"
}

func (sn *SlackNotifier) Send(ctx context.Context, alert *Alert) error {
    color := "#36a64f"
    if alert.Severity == SevCritical {
        color = "#ff0000"
    } else if alert.Severity == SevWarning {
        color = "#ffa500"
    }

    payload := map[string]interface{}{
        "channel": sn.channel,
        "username": sn.username,
        "attachments": []map[string]interface{}{
            {
                "color": color,
                "title": fmt.Sprintf("[%s] %s", alert.Severity, alert.Name),
                "text": fmt.Sprintf(
                    "Value: %.2f\nThreshold: %.2f\nStarted: %s",
                    alert.Value, alert.Threshold, alert.StartedAt.Format(time.RFC3339),
                ),
                "fields": []map[string]interface{}{
                    {"title": "Rule ID", "value": alert.RuleID, "short": true},
                    {"title": "Status", "value": string(alert.Status), "short": true},
                },
                "footer": "Memory System Monitor",
                "ts": time.Now().Unix(),
            },
        },
    }

    data, _ := json.Marshal(payload)
    resp, err := sn.client.Post(sn.webhookURL, "application/json", bytes.NewReader(data))
    if err != nil {
        return fmt.Errorf("send slack: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusOK {
        return fmt.Errorf("slack returned %d", resp.StatusCode)
    }

    return nil
}

// EmailNotifier 邮件通知器
type EmailNotifier struct {
    smtpHost string
    smtpPort int
    from     string
    to       []string
}

func NewEmailNotifier(smtpHost string, smtpPort int, from string, to []string) *EmailNotifier {
    return &EmailNotifier{
        smtpHost: smtpHost,
        smtpPort: smtpPort,
        from:     from,
        to:       to,
    }
}

func (en *EmailNotifier) Name() string {
    return "email"
}

func (en *EmailNotifier) Send(ctx context.Context, alert *Alert) error {
    subject := fmt.Sprintf("[%s] %s - Memory System Alert", alert.Severity, alert.Name)
    body := fmt.Sprintf(`
Alert Details:
==============
Name:      %s
Severity:  %s
Rule ID:   %s
Value:     %.2f
Threshold: %.2f
Started:   %s
Status:    %s

Labels:
%s
Annotations:
%s
`,
        alert.Name, alert.Severity, alert.RuleID,
        alert.Value, alert.Threshold,
        alert.StartedAt.Format(time.RFC3339),
        alert.Status,
        formatMap(alert.Labels),
        formatMap(alert.Annotations),
    )

    msg := fmt.Sprintf("From: %s\r\nTo: %s\r\nSubject: %s\r\n\r\n%s",
        en.from, en.to[0], subject, body)

    // 实际发送需要使用 net/smtp
    log.Printf("[EMAIL NOTIFIER] Would send email:\n%s", msg)
    return nil
}

// WebhookNotifier Webhook 通知器
type WebhookNotifier struct {
    url    string
    secret string
    client *http.Client
}

func NewWebhookNotifier(url, secret string) *WebhookNotifier {
    return &WebhookNotifier{
        url:    url,
        secret: secret,
        client: &http.Client{Timeout: 10 * time.Second},
    }
}

func (wn *WebhookNotifier) Name() string {
    return "webhook"
}

func (wn *WebhookNotifier) Send(ctx context.Context, alert *Alert) error {
    payload := map[string]interface{}{
        "event":     "alert",
        "timestamp": time.Now().Unix(),
        "alert":     alert,
    }

    data, _ := json.Marshal(payload)
    req, err := http.NewRequestWithContext(ctx, "POST", wn.url, bytes.NewReader(data))
    if err != nil {
        return fmt.Errorf("create request: %w", err)
    }

    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-Secret", wn.secret)

    resp, err := wn.client.Do(req)
    if err != nil {
        return fmt.Errorf("send webhook: %w", err)
    }
    defer resp.Body.Close()

    if resp.StatusCode >= 300 {
        return fmt.Errorf("webhook returned %d", resp.StatusCode)
    }

    return nil
}

func formatMap(m map[string]string) string {
    if m == nil {
        return "(none)"
    }
    var result string
    for k, v := range m {
        result += fmt.Sprintf("  %s: %s\n", k, v)
    }
    return result
}

七、Grafana 仪表盘配置

复制代码
// grafana/dashboard.json
{
  "dashboard": {
    "title": "Memory System Dashboard",
    "tags": ["memory", "monitoring"],
    "timezone": "browser",
    "panels": [
      {
        "title": "Operations Overview",
        "type": "stat",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "rate(memory_total_operations[5m])",
            "legendFormat": "Total Ops/s"
          }
        ],
        "gridPos": {"h": 4, "w": 4, "x": 0, "y": 0}
      },
      {
        "title": "Active Entries",
        "type": "stat",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "memory_active_entries",
            "legendFormat": "Entries"
          }
        ],
        "gridPos": {"h": 4, "w": 4, "x": 4, "y": 0}
      },
      {
        "title": "Storage Size",
        "type": "stat",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "memory_storage_size_bytes",
            "legendFormat": "Bytes"
          }
        ],
        "gridPos": {"h": 4, "w": 4, "x": 8, "y": 0}
      },
      {
        "title": "Operations by Type",
        "type": "piechart",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "sum(rate(memory_total_operations[5m])) by (type)",
            "legendFormat": "{{type}}"
          }
        ],
// grafana/dashboard.json (续)
        "gridPos": {"h": 8, "w": 6, "x": 0, "y": 4}
      },
      {
        "title": "Operation Latency (P99)",
        "type": "graph",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "histogram_quantile(0.99, sum(rate(memory_operation_latency_seconds_bucket[5m])) by (le))",
            "legendFormat": "P99"
          },
          {
            "expr": "histogram_quantile(0.90, sum(rate(memory_operation_latency_seconds_bucket[5m])) by (le))",
            "legendFormat": "P90"
          },
          {
            "expr": "histogram_quantile(0.50, sum(rate(memory_operation_latency_seconds_bucket[5m])) by (le))",
            "legendFormat": "P50"
          }
        ],
        "gridPos": {"h": 8, "w": 6, "x": 6, "y": 4}
      },
      {
        "title": "Replication Lag",
        "type": "graph",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "memory_replication_lag",
            "legendFormat": "{{node_id}}"
          }
        ],
        "gridPos": {"h": 6, "w": 6, "x": 0, "y": 12}
      },
      {
        "title": "Auth Denied Rate",
        "type": "graph",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "rate(memory_auth_denied_total[5m])",
            "legendFormat": "Denied/s"
          }
        ],
        "gridPos": {"h": 6, "w": 6, "x": 6, "y": 12}
      },
      {
        "title": "Encryption Operations",
        "type": "graph",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "rate(memory_encryption_operations_total[5m])",
            "legendFormat": "{{operation}}"
          }
        ],
        "gridPos": {"h": 6, "w": 6, "x": 0, "y": 18}
      },
      {
        "title": "System Resources",
        "type": "graph",
        "datasource": "Prometheus",
        "targets": [
          {
            "expr": "system_cpu_usage_percent",
            "legendFormat": "CPU %"
          },
          {
            "expr": "system_memory_usage_bytes",
            "legendFormat": "Memory"
          },
          {
            "expr": "go_goroutines",
            "legendFormat": "Goroutines"
          }
        ],
        "gridPos": {"h": 6, "w": 6, "x": 6, "y": 18}
      }
    ]
  }
}

八、Prometheus 告警规则

复制代码
# prometheus/alerts.yml
groups:
  - name: memory_system_alerts
    interval: 30s
    rules:

      # 高可用告警
      - alert: HighReplicationLag
        expr: memory_replication_lag > 1000
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Replication lag is high on {{ $labels.node_id }}"
          description: "Node {{ $labels.node_id }} has {{ $value }} entries behind the leader"

      - alert: FailoverTriggered
        expr: rate(memory_failover_count[5m]) > 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Failover has been triggered"
          description: "A failover event occurred in the last 5 minutes"

      - alert: NoLeader
        expr: absent(memory_is_leader)
        for: 10s
        labels:
          severity: critical
        annotations:
          summary: "No cluster leader"
          description: "The cluster has no elected leader"

      # 性能告警
      - alert: HighLatency
        expr: histogram_quantile(0.99, rate(memory_operation_latency_seconds_bucket[5m])) > 0.5
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High operation latency detected"
          description: "P99 latency is {{ $value }}s (threshold: 0.5s)"

      - alert: OperationErrors
        expr: rate(memory_total_operations{result="error"}[5m]) / rate(memory_total_operations[5m]) > 0.01
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High error rate"
          description: "Error rate is {{ $value | humanizePercentage }}"

      # 安全告警
      - alert: BruteForceAttack
        expr: rate(memory_auth_denied_total[1m]) > 10
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Possible brute force attack"
          description: "Auth denied rate is {{ $value }}/s in the last minute"

      - alert: EncryptionKeyExpiring
        expr: memory_encryption_key_expiry_days < 7
        for: 1h
        labels:
          severity: warning
        annotations:
          summary: "Encryption key expiring soon"
          description: "Key {{ $labels.key_id }} expires in {{ $value }} days"

      # 存储告警
      - alert: StorageAlmostFull
        expr: system_disk_usage_percent > 85
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Disk space running low"
          description: "Disk usage is {{ $value }}%"

      - alert: TooManyEntries
        expr: memory_active_entries > 10000000
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "Too many memory entries"
          description: "Active entries ({{ $value }}) exceed 10 million, consider compression"

      # 系统告警
      - alert: HighGoroutineCount
        expr: go_goroutines > 10000
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High goroutine count"
          description: "{{ $value }} goroutines running"

      - alert: ProcessDown
        expr: up{job="memory-system"} == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Memory system process is down"
          description: "Instance {{ $labels.instance }} has been down for more than 1 minute"

九、生产坑位

# 坑位 现象 解决方案
1 指标基数爆炸​ 高基数标签(如 user_id)导致 Prometheus 内存耗尽 限制标签基数;使用聚合指标替代原始标签;分层聚合
2 收集间隔过短​ 频繁采集影响业务性能 合理设置收集间隔(≥15s);使用批处理;异步采集
3 告警风暴​ 一个根因触发多条关联告警 使用告警分组;依赖关系分析;抑制规则
4 健康检查误报​ 短暂网络抖动导致健康检查失败 增加重试机制;滑动窗口检测;区分存活/就绪检查
5 监控数据丢失​ 监控系统自身宕机导致数据断层 本地缓存 + 远程写入;多副本 Prometheus;Thanos 联邦
6 Grafana 面板过多​ 数百个面板难以维护 使用模板变量;动态面板;按团队/服务分类
7 告警疲劳​ 频繁收到低优先级告警导致忽视 严格分级(Critical/Warning/Info);静默维护窗口;自动降噪

十、评测指标

指标 说明 目标值 测量方式
指标采集延迟 从产生到可查询的延迟 < 30秒 Prometheus 抓取间隔 + 处理时间
告警响应时间 从触发到通知送达 < 1分钟 端到端测试
监控系统可用性 监控组件自身的可用性 >= 99.99% 健康检查
指标存储容量 每天产生的时序数据量 < 100GB/天 实际测量
查询响应时间 Grafana 面板加载时间 < 5秒 实际测量
告警准确率 有效告警占总告警比例 >= 95% 人工审核抽样
误报率 错误触发的告警比例 < 5% 告警回放分析

十一、使用示例

复制代码
// examples/monitoring_demo.go
package main

import (
    "context"
    "fmt"
    "log"
    "math/rand"
    "net/http"
    "time"

    "memory/monitoring"
)

func main() {
    ctx := context.Background()

    fmt.Println("=== 记忆系统监控演示 ===\n")

    // 1. 初始化监控配置
    config := monitoring.MonitoringConfig{
        Enabled:         true,
        ListenAddr:      ":9090",
        MetricsPath:     "/metrics",
        HealthPath:      "/healthz",
        CollectInterval: "15s",
        ExportGoMetrics: true,
        HistogramBuckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5},
    }

    // 2. 初始化指标收集器
    collector := monitoring.NewMemoryCollector(config)
    collector.Start()
    defer collector.Stop()
    fmt.Println("✓ 指标收集器已启动")

    // 3. 初始化健康检查器
    healthChecker := monitoring.NewHealthChecker("1.0.0")

    // 注册健康检查
    healthChecker.RegisterCheck("memory_store", func(ctx context.Context) monitoring.ComponentHealth {
        return monitoring.ComponentHealth{
            Status:  "up",
            Message: "in-memory store healthy",
            Latency: "2ms",
        }
    })

    healthChecker.RegisterCheck("encryption", func(ctx context.Context) monitoring.ComponentHealth {
        return monitoring.ComponentHealth{
            Status:  "up",
            Message: "AES-256-GCM encryption healthy",
        }
    })

    healthChecker.RegisterCheck("cluster", func(ctx context.Context) monitoring.ComponentHealth {
        return monitoring.ComponentHealth{
            Status:  "up",
            Message: "leader: node-1",
        }
    })

    fmt.Println("✓ 健康检查器已初始化")

    // 4. 初始化告警管理器
    alertRules := []monitoring.AlertRule{
        {
            ID:        "rule-001",
            Name:      "High Replication Lag",
            Metric:    "memory_replication_lag_max",
            Condition: monitoring.CondGreaterThan,
            Threshold: 1000,
            Duration:  5 * time.Minute,
            Severity:  monitoring.SevWarning,
            Enabled:   true,
        },
        {
            ID:        "rule-002",
            Name:      "High Auth Denied Rate",
            Metric:    "memory_auth_denied_rate",
            Condition: monitoring.CondGreaterThan,
            Threshold: 10,
            Duration:  1 * time.Minute,
            Severity:  monitoring.SevCritical,
            Enabled:   true,
        },
        {
            ID:        "rule-003",
            Name:      "High Latency P99",
            Metric:    "memory_latency_p99",
            Condition: monitoring.CondGreaterThan,
            Threshold: 500,
            Duration:  5 * time.Minute,
            Severity:  monitoring.SevWarning,
            Enabled:   true,
        },
    }

    evaluator := monitoring.NewDefaultAlertEvaluator(5 * time.Minute)
    alertManager := monitoring.NewAlertManager(alertRules, evaluator, 30*time.Second)

    // 注册通知器
    slackNotifier := monitoring.NewSlackNotifier(
        "https://hooks.slack.com/services/xxx",
        "#monitoring",
        "Memory Bot",
    )
    alertManager.RegisterNotifier(slackNotifier)

    webhookNotifier := monitoring.NewWebhookNotifier(
        "https://api.example.com/webhook/alert",
        "shared-secret",
    )
    alertManager.RegisterNotifier(webhookNotifier)

    alertManager.Start(ctx, collector.GetMetrics)
    defer alertManager.Stop()
    fmt.Println("✓ 告警管理器已启动")

    // 5. 启动 HTTP 服务暴露指标和健康检查
    http.Handle(config.MetricsPath, promhttp.Handler())
    http.HandleFunc(config.HealthPath, healthChecker.HTTPHandler)
    http.HandleFunc("/readyz", healthChecker.HTTPHandler)

    go func() {
        addr := config.ListenAddr
        log.Printf("[HTTP] Metrics server listening on %s", addr)
        if err := http.ListenAndServe(addr, nil); err != nil {
            log.Fatalf("http server: %v", err)
        }
    }()

    // 6. 模拟业务操作并记录指标
    fmt.Println("\n=== 模拟业务操作 ===")

    opTypes := []string{"save", "get", "search", "delete"}
    layers := []string{"working", "episodic", "semantic"}
    results := []string{"success", "success", "success", "success", "error"} // 80% success

    for i := 0; i < 20; i++ {
        opType := opTypes[rand.Intn(len(opTypes))]
        layer := layers[rand.Intn(len(layers))]
        result := results[rand.Intn(len(results))]
        latency := time.Duration(rand.Intn(200)+1) * time.Millisecond

        collector.RecordOperation(opType, layer, result, latency)

        // 偶尔记录认证拒绝
        if rand.Float64() < 0.1 {
            collector.RecordAuthDenial("insufficient_permissions")
        }

        // 偶尔记录加密操作
        if rand.Float64() < 0.3 {
            collector.RecordEncryption("encrypt")
        }

        time.Sleep(500 * time.Millisecond)
    }

    // 7. 更新存储指标
    collector.UpdateEntriesCount("working", 1250)
    collector.UpdateEntriesCount("episodic", 8500)
    collector.UpdateEntriesCount("semantic", 3200)
    collector.UpdateStorageSize(157286400) // 150MB

    // 8. 更新复制延迟
    collector.UpdateReplicationLag("node-2", 42)
    collector.UpdateReplicationLag("node-3", 156)

    // 9. 获取当前指标
    fmt.Println("\n=== 当前指标快照 ===")
    metrics := collector.GetMetrics()
    fmt.Printf("总操作数: %d\n", metrics.TotalOps)
    fmt.Printf("成功: %d, 失败: %d\n", metrics.SuccessOps, metrics.FailedOps)
    fmt.Printf("平均延迟: %.2f ms\n", metrics.AvgLatency)
    fmt.Printf("总条目数: %d\n", metrics.TotalEntries)
    fmt.Printf("存储大小: %.2f MB\n", float64(metrics.StorageSize)/1024/1024)
    fmt.Printf("认证拒绝: %d\n", metrics.AuthDeniedCount)
    fmt.Printf("加密操作: %d 加密 / %d 解密\n", metrics.EncryptCount, metrics.DecryptCount)
    fmt.Printf("复制延迟: ")
    for node, lag := range metrics.ReplicationLag {
        fmt.Printf("%s=%d ", node, lag)
    }
    fmt.Println()

    // 10. 健康检查
    fmt.Println("\n=== 健康检查 ===")
    health := healthChecker.Check(ctx)
    fmt.Printf("整体状态: %s\n", health.Status)
    fmt.Printf("运行时间: %s\n", health.Uptime)
    for name, component := range health.Components {
        fmt.Printf("  %s: %s (%s)\n", name, component.Status, component.Message)
    }

    // 11. 查看活跃告警
    fmt.Println("\n=== 活跃告警 ===")
    activeAlerts := alertManager.GetActiveAlerts()
    if len(activeAlerts) == 0 {
        fmt.Println("暂无活跃告警")
    } else {
        for _, alert := range activeAlerts {
            fmt.Printf("  [%s] %s (value=%.2f)\n", alert.Severity, alert.Name, alert.Value)
        }
    }

    fmt.Println("\n=== 访问指标 ===")
    fmt.Printf("Prometheus 指标: http://localhost%s%s\n", config.ListenAddr, config.MetricsPath)
    fmt.Printf("健康检查: http://localhost%s%s\n", config.ListenAddr, config.HealthPath)
    fmt.Printf("就绪检查: http://localhost%s/readyz\n", config.ListenAddr)

    fmt.Println("\n演示完成!")
}

十二、本讲总结

复制代码
┌──────────────────────────────────────────────────────────────────────────┐
│                    第8讲 核心收获                                          │
│                                                                           │
│  ✅ 实现了指标收集器:                                                     │
│     - Prometheus Counter/Gauge/Histogram                                  │
│     - 操作计数、延迟分布、存储量、复制延迟                                │
│     - 系统指标(CPU/内存/磁盘)                                           │
│     - Go Runtime 指标(goroutine/GC)                                    │
│                                                                           │
│  ✅ 实现了健康检查器:                                                     │
│     - 存活检查 (/healthz)                                                 │
│     - 就绪检查 (/readyz)                                                  │
│     - 组件级健康(数据库/存储/集群/加密)                                │
│     - 磁盘空间预警                                                        │
│                                                                           │
│  ✅ 实现了告警管理器:                                                     │
│     - 多维度告警规则(延迟/错误率/复制延迟/安全)                        │
│     - 告警分级(Critical/Warning/Info)                                  │
│     - 静默机制                                                            │
│     - 多通知渠道(Slack/Email/Webhook)                                  │
│                                                                           │
│  ✅ 提供了 Grafana 仪表盘配置                                              │
│  ✅ 提供了 Prometheus 告警规则配置                                         │
│  ✅ 覆盖了 7 个生产坑位与解决方案                                         │
│  ✅ 定义了监控系统的关键评测指标                                          │
│                                                                           │
└──────────────────────────────────────────────────────────────────────────┘

十三、下一讲预告

第9讲:《记忆系统的性能优化与基准测试------缓存策略、连接池、批量操作与压测方法论》

你将学到:

  • 多级缓存策略(L1/L2/L3)
  • 连接池优化(gRPC/数据库)
  • 批量操作与管道化
  • 读写分离与负载均衡
  • 基准测试框架(Benchmark)
  • 性能调优实战案例

🧰 开发之余的小工具推荐

在监控系统运维中,经常需要处理时间戳转换、持续时间计算和指标数值格式化。zz365.top 的 Unix 时间戳转换工具可以快速将监控日志中的 Unix 时间戳转为可读日期,帮助定位故障时间点。其 JSON 格式化工具则可以美化 Prometheus 告警规则的 JSON 配置,便于审查和调试。所有处理均在浏览器本地完成,不会泄露你的监控配置信息。

相关推荐
java_logo1 小时前
Docker 部署青龙面板:轻松搭建定时任务管理平台
运维·docker·容器·定时任务·青龙面板·轩辕镜像·qinglong
时间售卖铺1 小时前
MySQL 安装部署
运维·数据库·mysql·云原生
亚川楼宇自控系统数据中心厂家1 小时前
消防风机一体化监控系统结合楼宇自控 协同管控原理科普
运维
邪修king1 小时前
Re:Linux系统篇(三十七):进程间通信Chapter4:System V 共享内存深度解析:为什么它是最快的 IPC?
android·linux·运维
桌管小李1 小时前
终端安全一体化实战:AI 审计、行为分析、零信任、防拍照与远程运维全解析
运维·服务器·网络·人工智能·windows·安全·macos
流星白龙2 小时前
【Docker】14.存储卷与管理卷Volume
运维·docker·容器
迪康Defender2 小时前
端点安全选型观察:一体化平台与传统 EDR 的场景差异
运维·经验分享·安全·自动化·学习方法·远程工作·安全架构
amcomputer2 小时前
Docker 常用命令总结:从安装到日常使用
运维·docker·容器