使用 eBPF 追踪 VPS 流量使用情况

没错,现在是 2015 年 1 月 2 日。就在新年的第二天,我的 VPS 流量用完了。

我的 VPS 是每个月 1 日重置,也就是说才一天 VPS 就跑了整整 1TB 的流量。很奇怪到底是哪个进程在作妖,于是决定找一个方法来追踪 VPS 的流量使用情况。

追踪流量使用情况的软件有很多,比如 nthlogsvnstat。eBPF 是最近才出现的新技术,因为能够在内核空间运行,所以性能非常好。Linux 内核的计数器也能满足我的需求,因此我选择使用 eBPF 来追踪 VPS 的流量使用情况。

Linux 内核有几个计数器,能够按照进程统计流量的使用情况,包括:

  • netif_receive_skb
  • net_dev_queue
  • napi_gro_receive_entry
  • net_dev_xmit

只要在这几个地方插入 eBPF tracepoint,再定期打印出来即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/bpftrace

tracepoint:net:netif_receive_skb {
@recv[pid, comm] = sum(args->len);
}

tracepoint:net:net_dev_queue {
@send[pid, comm] = sum(args->len);
}

tracepoint:net:napi_gro_receive_entry
{
@nic_recv[pid, comm] = sum(args->len);
}

tracepoint:net:net_dev_xmit
{
@nic_send[pid, comm] = sum(args->len);
}

interval:s:15 {
$ts = nsecs;
printf("Time: %s\n", strftime("%Y-%m-%d %H:%M:%S %Z", $ts));
print(@recv);
print(@send);
print(@nic_recv);
print(@nic_send);
printf("-------------------------------------\n");
}

赋予执行权限,然后运行,即可每 15 秒输出一次流量使用情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sudo chmod +x netstat.bt
sudo ./netstat.bt
# Attaching 5 probes...
# Time: 2025-01-02 10:07:10 PST
# @recv[513, qemu-ga]: 1280
# @recv[1291, kworker/0:1]: 2616
# @recv[30, khugepaged]: 2620
# @recv[0, swapper/0]: 989360
# @send[1290, kworker/0:0]: 74
# @send[1291, kworker/0:1]: 1180
# @send[30, khugepaged]: 1234
# @send[0, swapper/0]: 427898
# @nic_recv[513, qemu-ga]: 1280
# @nic_recv[1291, kworker/0:1]: 2616
# @nic_recv[30, khugepaged]: 2620
# @nic_recv[0, swapper/0]: 989360
# @nic_send[1290, kworker/0:0]: 74
# @nic_send[1291, kworker/0:1]: 1180
# @nic_send[30, khugepaged]: 1234
# @nic_send[0, swapper/0]: 427898
# -------------------------------------

如果需要后台运行,可以用 Systemd 管理。

1
2
mkdir /srv/ebpf/netstat
mv netstat.bt /srv/ebpf/netstat

然后在 /etc/systemd/system/ebpftrace@.service 中写入:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
Description=eBPFTrace Daemon
After=network.target

[Service]
Type=simple
ExecStart=/srv/ebpf/%i/%i.bt
StandardOutput=append:/srv/ebpf/%i/%i.log
StandardError=append:/srv/ebpf/%i/%i_err.log
Restart=always

[Install]
WantedBy=multi-user.target

最后启动服务:

1
systemctl enable --now ebpftrace@netstat