简单聊聊国庆吃的屎吧

首先明确下需求,我们要监控哪几个指标

1. RTO:TCP 连接的 RTO ,TCP 的超时重传的阈值,具体可以参见[RFC 0793](https://tools.ietf.org/html/rfc793) 和 [RFC 6298](https://tools.ietf.org/html/rfc6298)
2. 发送队列和接收队列长度
3. TCP 慢启动等指标

而且一个很核心的需求还是在于说,我们需要以 进程 为粒度去做 Metric 的 Group By,细化下来的可以有这样的效果

1. 单个进程的所有连接平均的 RTO 等指标
2. 单个进程Source-Target连接的 RTO 等指标

这个需求看起来可能会很无从下手,但是内核实际上是已经暴露出 metric 来供 Agent 采集了的

1. 对于 IPv4 连接,内核将 Metric 输出到 /proc/net/tcp
2. 对于 IPv6 连接,内核将 Metric 输出到 /proc/net/tcp6

不过这里要注意的是,官方已经不推荐利用 /proc/net/tcp 来获取连接级别的 metrics ,建议使用 [netlink](https://man7.org/linux/man-pages/man7/netlink.7.html) 来获取对应连接的 metrics

在目前输出的 metrics 中,已经包含了一些关键的指标

1. 连接状态
2. 本地端口,地址
3. 远程端口,地址
4. 接收队列长度
5. 发送队列长度
6. 慢启动阈值
7. RTO 值
8. 连接所属的 socket 的 inode id
9. uid
10. delay ack 软时钟

具体可以参见 [proc_net_tcp.txt](https://github.com/torvalds/linux/blob/v4.10/Documentation/networking/proc_net_tcp.txt)

所以根据目前的一些指标,我们通过 inode→process 这一样一个路径便可以实现根据进程为粒度来对内核输出的 metric 进行二次聚合

但是这样做的弊端也很明显

1. 内核直接提供的 metric 信息还是太少,一些关于 RTT,SRTT 这样的指标还是没法获取,也没法获取 SACK 等一些特定事件(虽然走 netlink+tcp_diag) 能获取到一些信息,但是还是相对有限
2. 根据内核输出的 metric 无论是读文件,还是 netlink 轮询,都存在的问题是实时性和精度的问题,换句话说,我们在不考虑精度的情况下可以去做这方面的尝试
3. 如果是读文件,因为全局同一个 network namespaces 下都会写同一个文件,如果我们要强行去通过 [inotify](https://man7.org/linux/man-pages/man7/inotify.7.html) 来监听文件变化来做实时处理得话,首先能否实时处理还是一个问题,其次 inotify 给整个系统带来的开销还是不小的(在频繁变动的情况下)

所以如果有高精度的监控需求,可能还是优先考虑需要在协议层做一些手脚,在有包传输/连接变动的时候,触发特定的事件回调来做

目前一些能监控进程级别连接状态的工具,如 [nethogs](https://github.com/raboof/nethogs) 是依赖 [libpcap](https://github.com/the-tcpdump-group/libpcap)(这货也是 tcpdump 的核心)来根据包传输,连接建立等事件发生地时候触发特定的处理逻辑。而 libpcap 是基于 BPF (应该是没扩展之前的 cBPF)来在内核中打点做协议栈监控

所以考虑后续其余的一些自定义的监控的话,估计还是会考虑基于 eBPF 来做。不过估计不会像 Cilium 那种直接做一套全家桶。可能更类似于头条落地的 Sysprobe 那种专注于系统监控的东西。 RFC 6298: Computing TCP's Retransmission Timer
 
 
Back to Top