# MFD Monitor Agent 架构与工作流程 本文档汇总当前代码中的实际运行流程,供开发、排障和评审时快速理解 agent 如何从配置加载到采集、缓存、查询、上报和服务化运行。 ## 进程职责 MFD Monitor Agent 采用单进程一体化架构。一个 agent 进程同时负责: - 周期采集主机状态 - 保存最近一次 `HostStatus` 内存缓存 - 提供本地 HTTP API - 可选地向中心端主动 POST 上报 - 执行 Linux/Windows 服务安装、启动、停止和卸载命令 HTTP 查询与主动上报读取同一份缓存,不在请求路径上触发实时系统扫描。 ## 包职责 | 包 | 职责 | |----|------| | `cmd/agent` | CLI 分发、配置加载、进程生命周期、HTTP server 启停 | | `internal/config` | 默认配置、JSON 读取、首次配置生成、环境变量覆盖、配置校验 | | `internal/status` | `/status` 与主动上报共用的 `HostStatus` JSON 数据模型 | | `internal/collector` | 平台相关主机、网络、资源、进程、TCP 监听采集 | | `internal/snapshot` | 子采集器聚合、partial 错误记录、并发安全缓存 | | `internal/httpapi` | `GET /health` 与 `GET /status`,查询参数 token 鉴权 | | `internal/reporter` | 周期性 POST 缓存快照,失败重试与日志记录 | | `internal/service` | Linux systemd 与 Windows SCM 服务生命周期封装 | ## 启动与生命周期 `agent` 无参数时等价于 `agent run`。 `agent run [-config config.json]` 流程: 1. 解析 `-config`,未指定时使用当前工作目录 `config.json`。 2. 调用 `config.LoadOrCreate`。配置不存在时创建默认 JSON 并生成随机 `http.token`。 3. 创建 `snapshot.Cache`,启动后台采集循环。 4. 若 `report.enabled=true`,启动主动上报循环。 5. 启动 HTTP server,默认监听 `0.0.0.0:8080`。 6. 收到 `SIGINT` 或 `SIGTERM` 后优雅关闭 HTTP server。 服务命令 `install`、`uninstall`、`start`、`stop` 使用 `config.Load` 读取已有配置,不会自动创建配置文件。 ## 配置加载流程 配置来源按以下顺序生效: 1. `config.Default()` 提供默认值。 2. JSON 文件覆盖默认值。 3. `MFD_AGENT_*` 环境变量覆盖 JSON。 4. `validate` 校验安全和必填项。 关键规则: - `http.token` 必填;`agent run` 首次生成配置时会自动写入随机 token。 - `report.enabled=true` 时 `report.endpoint` 必填。 - 自动生成的配置文件权限为 `0600`,因为其中包含 API token。 - 非法布尔或时长环境变量会被忽略,保留文件中的原值。 ## 采集与缓存流程 `snapshot.Cache.Run` 启动后立即采集一次,随后按 `collect.interval` 周期刷新。 每轮采集流程: 1. 用 `collect.timeout` 创建整体超时 context。 2. 构造新的 `HostStatus`,默认 `agent.snapshot_status=ok`。 3. 依次执行 `system`、`network`、`resource`、`process`、`socket` 采集器。 4. 子采集器失败时记录到 `errors[]`,整份快照降级为 `partial`,其他字段继续保留。 5. 用锁一次性发布最新快照,供 HTTP 与 reporter 并发读取。 `processes.status` 与 `tcp_listeners.status` 支持 `ok`、`partial`、`error`。例如 Linux 读取 `/proc//fd` 权限不足时,TCP 端口仍会返回,但进程映射可能不完整并标记为 `partial`。 ## HTTP 查询流程 所有 API 都要求查询参数 token: ```text GET /health?token= GET /status?token= ``` 处理流程: 1. `withQueryTokenAuth` 使用恒定时间比较校验 token。 2. token 缺失、错误或配置 token 为空时返回 `401`。 3. 非 `GET` 方法返回 `405`。 4. `/health` 读取缓存元数据。首次快照未就绪时返回 `503` 和 `{"status":"starting"}`。 5. `/status` 返回完整缓存 `HostStatus`。首次快照未就绪时返回 `503`。 HTTP 请求不会触发采集,避免高并发查询放大系统扫描成本。 ## 主动上报流程 启用条件: ```json { "report": { "enabled": true, "endpoint": "http://center.example.internal/agent/status" } } ``` 运行流程: 1. `reporter.Run` 按 `report.interval` 定时执行。 2. 从 `snapshot.Cache` 读取最新 `HostStatus`。 3. 首次快照未就绪时跳过本轮。 4. 以 `application/json` POST 到 `report.endpoint`。 5. 非 2xx、网络错误或超时视为失败。 6. 失败后等待短暂退避并重试一次。 7. 最终失败只记录日志,不影响采集循环或本地 HTTP 服务。 上报载荷与 `/status` 响应结构完全一致。 ## 服务生命周期流程 ### Linux systemd `agent install -config /path/config.json -exe /path/agent`: 1. 检查当前用户必须为 root。 2. 生成 `/etc/systemd/system/.service`。 3. `ExecStart` 写入 ` run -config `。 4. 执行 `systemctl daemon-reload`。 5. 执行 `systemctl enable `。 `start`、`stop` 调用 `systemctl start/stop`。`uninstall` 尽力 `disable --now`,删除 unit 文件后再次 `daemon-reload`。 ### Windows SCM Windows 通过 `sc.exe` 管理服务,不依赖 NSSM。 `install` 使用 `sc.exe create` 注册自动启动服务,`binPath` 为: ```text "" run -config "" ``` `start`、`stop`、`uninstall` 分别调用 `sc.exe start`、`sc.exe stop`、`sc.exe delete`。安装、删除和启停通常需要管理员权限。 ## HostStatus 数据模型 `HostStatus` 是唯一对外状态模型,同时用于: - `GET /status` 响应体 - 主动上报 POST body - 测试中的快照断言 顶层字段包括: - `agent`:版本、启动时间、快照时间、快照状态 - `host`:机器标识、主机名、平台、架构、运行时长 - `network`:网卡明细、IPv4/IPv6、MAC - `cpu`:逻辑核心、物理核心、使用率、负载、型号 - `memory`:内存容量与使用率 - `disks`:文件系统容量与使用率 - `processes`:采集状态与完整进程列表 - `tcp_listeners`:采集状态与 TCP 监听端口到进程映射 - `errors`:子采集器失败原因 ## 平台差异 Linux 采集主要读取 `/proc`、`/etc/os-release`、`net.Interfaces` 和 `statfs`。进程与 socket 映射受 `/proc/` 权限和进程生命周期竞争影响。 Windows 采集使用 Win32 API、Toolhelp、注册表、PSAPI、iphlpapi 和一次尽力 WMIC 命令。部分字段需要高权限读取进程句柄或令牌,失败时降级为空字段或 `partial`。 非 Linux/Windows 平台保留基础主机和网络采集,进程与 TCP 监听采集明确返回不支持并标记 `partial`。