一个本地资源采集 agent —— 作为 2-3 个月的学习主线,边做边补基础
目标读者:用过 AI 辅助写代码,能跑通程序,但想真正把基础夯实的学习者
这个项目天然覆盖了后端/系统工程师该懂的几乎所有基础模块:
| 领域 | 涉及内容 |
|---|---|
| 操作系统 | 进程、/proc 文件系统、cgroup、namespace |
| Linux 系统编程 | 读系统文件、解析内核数据结构 |
| 网络基础 | 网络接口、流量统计、netlink |
| 并发与调度 | 定时采集、异步、worker |
| 数据结构 | 时序数据、增量计算(差分算法) |
| 容器原理 | Docker = namespace + cgroup + 镜像 |
| 工程素养 | 模块化、配置、日志、测试、打包 |
把这个项目吃透,基础就扎实了一大半。
虽然生产级 agent 通常用 Go 或 Rust 写(node_exporter、cAdvisor 都是 Go),但第一版用 Python 更合适:
- 延续已有经验,降低启动阻力
- Python 读
/proc、调 Docker API、做并发都非常顺手 - 重点是理解数据从哪来、怎么算,不是语言性能
psutil的源码本身就是最好的系统编程教材
等理解了原理,用 Go 重写采集核心 —— 这时候才会真正理解为什么生产级 agent 都用 Go。
准备工作
- 准备一台 Linux 环境(WSL2、Docker Desktop 里的 Linux、或云上小机器都行;macOS 也可但
/proc体验不同) - 装好 Docker,跑几个容器(nginx、redis)作为后续观察对象
- 建 GitHub 仓库
local-resource-agent,写第一版 README(就写想做什么)
心态设定
这个项目不是"做完就结束",是"每个模块先理解再写"。
Linux 下,进程的一切信息都在 /proc/<pid>/ 下,只要会读文件就能做监控。这一步不要碰任何库,纯手读。
学习内容
- 读《The Linux Programming Interface》第 12 章"系统与进程信息" —— 或者直接读
man proc - 在终端里手动执行:
把每个字段都搞明白
cat /proc/self/status cat /proc/1/stat cat /proc/meminfo cat /proc/net/dev
动手任务
- 写
proc_reader.py:给一个 PID,返回它的名字、状态、父进程、内存占用 - 写
cpu_usage.py:不准用 psutil,自己计算一个进程的 CPU 使用率- 关键理解:
CPU 使用率 = (两次采样间该进程用的 jiffies) / (两次采样间系统总 jiffies) × 100% - 这个"差分"的概念搞懂了,就理解了所有速率类指标(网络 bps、磁盘 IOPS 都是这个套路)
- 关键理解:
验收标准
能向别人解释清楚"为什么 CPU 使用率必须采样两次才能算"。
学习内容
- 内存的几个概念:RSS、VSZ、PSS、swap ——
/proc/<pid>/status和/proc/<pid>/smaps - 磁盘 I/O:
/proc/<pid>/io(读写字节数),系统级/proc/diskstats
动手任务
- 扩展上周的脚本,加入 memory 和 block I/O
- 特别注意 I/O 也是差分指标(总字节数 → 速率)
容易踩的坑
RSS 和 "真实使用内存" 不是一回事(共享库会被多次计入)。理解了这点就超过 80% 的"会写监控"的人了。
学习内容
/proc/net/dev:接口级总流量/proc/<pid>/net/dev:但它不是进程级的!(会被 namespace 骗)—— 理解这点需要知道 namespace- 进程级网络流量其实在 Linux 上是个难题,生产方案要用 eBPF 或 cgroup v2
动手任务
- 先做接口级网络速率采集(简单)
- 进程级可以先标记为 "v2 功能",避免陷进去
这里的收获
第一次遇到"这个需求看起来简单但其实很难"的现实 —— 这是工程师成长的必经之路。
这是整个项目最有"开眼"感的部分。
学习内容(关键概念,慢慢啃)
- Namespace:让进程看到的世界不同(pid、net、mnt、uts、ipc、user)
- Cgroup:限制进程的资源(cpu、memory、io)
- Docker = namespace(隔离)+ cgroup(限制)+ 镜像(文件系统)
动手任务(三个递进练习)
练习 A:观察容器进程
- 在宿主机
ps aux看到容器里的进程 - 理解"容器进程就是宿主机进程,只是被隔离了视图"
练习 B:手动读 cgroup
- 找到某个容器的 cgroup 路径
- 手动
cat它的指标文件:- cgroup v2:
cpu.stat、memory.current - cgroup v1:
cpuacct.usage、memory.usage_in_bytes
- cgroup v2:
练习 C:调用 Docker API
- 用 Python 的
dockerSDK 列出所有容器、拿到元数据(名字、镜像、标签)
集成到 agent
- 从 Docker API 拿容器列表和元数据
- 从 cgroup 文件拿 CPU/内存/IO
- 把这些数据和"进程级"数据关联起来(一个容器对应一组进程)
这一步完成后
会真正"看懂" Docker,而不是只会
docker run。
到现在有一堆采集函数,接下来做工程化。
要加的东西
- 配置系统:用 YAML 或 TOML,让用户能配置采集间隔、要监控哪些容器
- 调度循环:每 N 秒采集一次,用
asyncio或APScheduler - 数据输出:先支持两种 —— JSON 打到 stdout、写入 SQLite 本地存储
- 日志:用
logging模块,分级输出 - 优雅退出:捕获 SIGTERM/SIGINT,保证数据不丢
项目结构参考
local-resource-agent/
├── agent/
│ ├── collectors/ # 各类采集器
│ │ ├── cpu.py
│ │ ├── memory.py
│ │ ├── network.py
│ │ ├── io.py
│ │ └── container.py
│ ├── sinks/ # 数据输出
│ │ ├── stdout.py
│ │ └── sqlite.py
│ ├── scheduler.py # 调度核心
│ ├── config.py
│ └── main.py
├── tests/
├── pyproject.toml
└── README.md
这两周是"巩固与视野"阶段。
对比学习
- 读 psutil 源码 里的
_pslinux.py—— 会发现手写过的东西它都做过,但更健壮 - 读 node_exporter 的几个 collector(Go 写的,但可读) —— 看看生产级怎么做
可选扩展(挑 1-2 个做)
- 加一个 HTTP 接口:
/metrics返回 Prometheus 格式,能被 Prometheus 抓取 - 加一个 Web UI:用 FastAPI + 简单前端展示实时数据
- 性能测试:agent 自己耗多少 CPU?很多新手没意识到要考虑这个
如果这时候还想深入:
- Go 版:用 Go 重写采集核心,体会静态语言 + 单二进制部署的爽感
- eBPF 版:用 Python 的
bcc或 Go 的cilium/ebpf,做真正的内核级可观测性(当前最前沿方向) - 贡献开源:去 node_exporter、cAdvisor 提个小 PR
这部分是整个 roadmap 最重要的部分 —— "AI 写过代码但基础不扎实"的问题通常不在"不会写",而在对写出的东西没有掌控感。
不允许"库一调、数字一出、收工"。
不要问:"帮我写一个 CPU 采集器"
要问:
- "解释一下
/proc/<pid>/stat第 14、15 个字段的含义和单位" - "我这样算 CPU 使用率对吗?为什么结果有时候超过 100%?"
- "这段代码有 bug 吗?"(贴上自己写的)
AI 当老师,不当代写。
哪怕只有 300 字,主题是"这周我搞懂了 X"。发到自己博客、GitHub README 附录、或 Notion 都行。
表达过的知识才真正是你的。
比如看到 ss -tnp,就 man ss。这个反射建立了,"基础扎实度"会飞速上涨。
如果第 1 周的 /proc 还没完全搞明白就冲第 5 周的 cgroup,只会又一次得到"能跑但不懂"的代码。
完成这条路线后,应该能做到:
- 不看教程手写一个进程的 CPU/内存/IO/网络采集器
- 解释清楚"差分算法"和为什么速率指标都需要两次采样
- 讲清楚 Docker = namespace + cgroup,并能手动找到某容器的 cgroup 文件
- RSS、VSZ、PSS 的区别能说清楚
- 有一个结构良好、可配置、能持续运行的 agent 在 GitHub 上
- 读得懂 psutil 和 node_exporter 的源码
- 面试时能侃侃而谈这个项目每一个设计决策的原因
- 《The Linux Programming Interface》 by Michael Kerrisk —— Linux 系统编程圣经,查第 12 章、第 36 章、第 13 章
- 《Systems Performance》 by Brendan Gregg —— 可观测性经典,了解宏观视角
- 《Linux/UNIX System Programming Handbook》 —— 上一本的简化版
- man proc ——
/proc每个文件的含义 - cgroup v2 文档 —— 内核官方文档
- Missing Semester - MIT —— Shell、Git、调试工具
- Linux Inside —— 深入内核
- psutil —— Python 实现,和你的项目同语言
- node_exporter —— Go 生产级实现
- cAdvisor —— Google 的容器监控,架构参考
- Prometheus Python Client —— 如果要加 Prometheus 输出
- Brendan Gregg 的博客 —— 性能分析领域的权威
- Julia Evans 的博客和 zine —— 用可爱的画风讲 Linux,极适合入门
最后一句话:这个项目的意义不在于做出多酷的东西,而在于走完之后,每次别人提到"监控""容器""Linux",你都能说——"这个我真的懂"。