Skip to main content
实战阶段 II:大脑(Master)已经就绪,现在我们需要编写派往各处的“斥候”——Agent。这个 Go 程序将运行在业务服务器上。它必须满足运维的三大铁律:占用低(不能干扰业务)、零依赖(部署时不许安装 Runtime)、自愈强(Master 挂了不能崩)。

学习内容 (30 mins)

如何获取 CPU 使用率?
  • Linux 原理: 读取 /proc/stat 文件,计算时间片差值。
  • Go 原理: 我们不需要自己解析文件。gopsutil 库封装了底层系统调用 (syscall),能跨平台(Linux/Windows/Mac)一致地获取信息。
  • 注意事项: 获取 CPU 使用率需要采样时间。比如采样 1 秒,意味着函数会阻塞 1 秒来计算这一秒内的平均负载。
为什么不用 net/http 标准库?
  • 标准库: 功能太基础,设置超时、重试、JSON 序列化都要自己写很多代码。
  • Resty: 类似 Python 的 Requests 库。它内置了 Automatic Retries (自动重试) 和 Connection Pooling (连接池),这对 Agent 这种需要长期运行的网络程序至关重要。
DevOps 的魔法
  • 场景: 你在 Mac 上开发,但生产服务器是 Linux,甚至还有几台 Windows。
  • 做法: 只需要在编译时指定 GOOS=linuxGOARCH=amd64
  • 结果: Go 编译器会直接生成目标平台机器码。这也是 Go 在运维领域吊打 Python 的核心原因——分发极其容易

开发任务 (90 mins)

1

步骤 1: 初始化项目与依赖

确保你已经初始化了 Go 项目并拉取了库。
2

步骤 2: 编写采集与上报逻辑

单文件 main.go 搞定一切。我们将结构体定义、采集逻辑、上报逻辑写在一起。
代码解释
  • cpu.Percent(1*time.Second, false):采样 1 秒计算 CPU 使用率,会阻塞 1 秒
  • resty.New():创建 HTTP 客户端,支持连接池和自动重试
  • time.NewTicker(5 * time.Second):定时器,每 5 秒触发一次
  • for range ticker.C:阻塞主线程,响应定时器事件
Agent 的设计哲学
  • 轻量级:资源占用小,不影响业务
  • 自愈能力:Master 挂了不崩溃,自动重试
  • 零依赖:编译后是单个二进制,无需运行时
验证步骤:
  1. 启动 Master: 确保 Pt.1 开发的 Master 服务正在运行
  2. 运行 Agent: go run main.go
  3. 观察终端:
    • Agent 端显示: 📤 Reporting... ✅ Sent.
    • Master 端显示: POST /api/v1/report 201
  4. 断在 Master: 关掉 Master 服务。Agent 应该报错 Connection Refused,但不会崩溃退出,而是等待下一次 Ticker。这就是健壮性
  5. 恢复 Master: 重新启动 Master,Agent 应该自动恢复上报
常见错误
  • CPU 始终为 0: 因为 cpu.Percent(0, false) 没给采样时间。必须给 1*time.Second 或更多。
  • Panic: index out of range: 如果系统极度繁忙导致获取不到 CPU 数据,cpuPercent 可能是空的。生产代码需要 check len(cpuPercent) > 0
3

步骤 3: 跨平台编译实战

假设公司的服务器是 Linux 的。

拓展任务 (30 mins)

配置化改造

任务:目前 MasterURL 是写死的。挑战:改造代码,优先读取环境变量 MASTER_URL。如果没有环境变量,再读取同目录下 config.json 文件。这是标准的云原生应用配置加载顺序。

IP 获取难题

任务:如何获取机器的真实 Outbound IP?提示:不要遍历网卡(可能会拿到虚拟 IP)。

今日产出物

  • monitor_agent_linux - 可直接 scp 到服务器运行的二进制文件
  • main.go - 具备重试和超时控制的 Agent 源码

参考代码

查看参考代码

GitHub 完整代码仓库

Resty 文档

Go 最流行的 HTTP 客户端库

实际应用场景

Sidecar 模式

  • 在 K8s 中,Agent 也可以作为 Sidecar 容器和业务容器跑在一个 Pod 里。
  • 虽然 Agent 是 Go 写的二进制,但依然可以封装进极小的 Docker 镜像(使用 scratchalpine 基础镜像)。
Next Step: 左手 Python Master,右手 Go Agent。现在,我们要把它们装进 Docker 容器里,完成终极交付 (Pt.3)

上一阶段: Master 开发

Day 30 | Pt.1 后端服务开发

下一阶段: 部署交付

Day 30 | Pt.3 毕业交付与总结