该模块通过包装net.Conn实现TCP流量统计,按五元组维护并发安全计数器,支持滑动窗口与累计模式,提供HTTP指标导出及防OOM机制。

要开发一个自定义的 TCP 流量统计与监控模块,核心在于捕获网络数据包、识别 TCP 流(五元组)、实时累加字节数与连接状态,并提供轻量级的观测接口。它不依赖 NetFlow 或 eBPF(降低门槛),适合嵌入到中间件、代理或运维工具中。
一、明确监控维度与数据结构
先定义你要统计什么,避免后期频繁重构:
- 连接粒度:按源IP:端口 → 目标IP:端口(即五元组)单独计数,区分方向(上行/下行)
- 关键指标:已建立连接数、当前活跃流数、每秒收发字节数(bps)、总收发字节数、重传包数(可选)
- 时间窗口:支持滑动窗口(如最近10秒)和累计总量两种模式
- 存储结构:用并发安全的 map(如 Go 的 sync.Map)存活跃流,key 为字符串化的五元组(如 "192.168.1.10:54321-10.0.0.5:80"),value 是含计数器的结构体
二、在应用层拦截 TCP 流量(以 Go 为例)
不抓包、不改内核,而是从你控制的网络入口/出口切入。例如:
- 若你在写反向代理(如基于 net/http 或 fasthttp),所有请求经过 listener.Accept() 和 conn.Read(),此时可包装 *net.Conn
- 定义一个 TrafficConn 结构,嵌入原始 conn,并重写 Read/Write 方法,在读写时原子更新对应方向的字节数
- 连接建立时注册五元组(conn.RemoteAddr() + conn.LocalAddr()),断开时清理或标记过期
- 示例伪代码:
func (tc *TrafficConn) Read(b []byte) (n int, err error) {
n, err = tc.conn.Read(b)
if n > 0 { atomic.AddUint64(&tc.stats.TxBytes, uint64(n)) }
return
}
三、构建低开销的聚合与导出机制
避免每次请求都查 map 或打日志。推荐分层设计:
- 内存热区:每个活跃连接维护独立计数器(uint64),读写无锁(atomic)
- 周期采样:启动 goroutine 每 2 秒扫描一次活跃流,将增量合并到“窗口统计器”(如环形缓冲区存最近 60 个 2 秒的 bps)
- 对外接口:提供 HTTP handler(如 /metrics)返回 Prometheus 格式文本,或 /api/flows 返回 JSON 列表(含 top 20 高流量流)
- 防爆策略:设置最大流数阈值(如 10 万),超限时启用 LRU 清理或只保留 top-N,避免 OOM
四、验证与轻量调试技巧
不用等上线,本地就能闭环验证:
- 用 nc 或 curl 发起多个短连接和长连接,观察 /api/flows 是否实时出现、消失
- 用 iftop -P tcp 或 ss -i 对比你的模块输出与系统视图是否趋势一致
- 注入异常:手动 close 连接后检查你的 map 是否及时删除;模拟大量新建连接压测内存增长是否可控
- 加一行 debug 日志:“active flows: %d, total rx: %s”,每 5 秒打一次,肉眼判断稳定性
这个模块本质是“带状态的连接包装器 + 时间感知聚合器”。它小而确定,能嵌进任何 Go 网络服务,后续可平滑升级为支持 TLS 解密统计或对接 Grafana。不复杂但容易忽略。

















