我正在编写一个脚本,该脚本解析 的输出lsof
以显示哪些进程打开了套接字的列表(类似于netstat
显示的内容)。lsof
还给了我一个文件描述符。我现在想做的是让我的脚本也告诉通过该套接字发送/接收了多少数据(以KB/秒为单位)。
到目前为止我已经看过:
nethogs
:告诉我一个进程的网络 I/O,但仅限于每个进程,而不是每个套接字。iotop
:告诉我每个进程的磁盘 I/O;似乎无法区分网络 I/O 或每个套接字的 I/O。/proc/pid/fd/
: 看起来这并不能告诉我太多。fatrace
:告诉我进程访问哪些文件(不是套接字)。iostat
:告诉我每个磁盘的平均 I/O 统计信息。tcpdump
:为我提供每个 IP 的所有流量的转储;似乎无法判断流量属于哪个套接字。strace -p pid -e trace=network -s 0
:告诉我每次给定进程调用某些套接字函数,这看起来很有用,但实际上只给了我很多recvfrom(13, 0x7feed8fb3074, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
strace -p pid -e trace=read,write -s
read
:告诉我每个/调用的结果write
。
strace
看起来很有希望,但我不确定我是否正确工作(read,write
足够了吗?),而且似乎会有很多开销。 (对于每个具有打开套接字的进程,我必须运行一个实例strace
并解析输出。)
Linux 内核是否提供了更好的方法来测量每个 fd/socket 进行了多少 I/O?可能可以设置iptables
或破解某些东西nethogs
?
答案1
考虑使用系统点击。它是 DTrace 克隆,但针对 Linux - 它编译动态修补内核的内核模块,并具有对其数据的完全访问权限(因此lsof
在这种情况下可能不需要)。
然而,您询问的信息越多,脚本就会变得越棘手并且特定于内核版本。
例如,用于套接字的简单的类似于统计的实用程序将如下所示:
global stats;
probe begin {
printf("%14s %6s %12s %5s %5s %8s\n", "NAME", "PID", "EXECNAME",
"INO", "OPS/S", "BYTES");
}
function file_ino:long (file:long)
{
if(file == 0) return -1;
d_inode = @cast(file, "file", "kernel")->f_inode;
if (d_inode == 0) return -1;
return @cast(d_inode, "inode", "kernel")->i_ino;
}
probe socket.send, socket.receive {
if(success == 0) next;
/* Get inode number for a socket. Depending on
operation, struct file is contained in different fields.
Determine that field and get inode number */
ino = -1;
if(@defined($sock)) {
ino = file_ino($sock->file);
}
else if(@defined($iocb)) {
ino = file_ino($iocb->ki_filp);
}
stats[pid(), execname(), ino, name] <<< size;
}
probe timer.s(1) {
/* Every 1 second print statistics */
foreach([pid+, ename, ino, name] in stats) {
printf("%14s %6d %12s %5d %5d %8d\n", name, pid, ename, ino,
@count(stats[pid, ename, ino, name]),
@sum(stats[pid, ename, ino, name]));
}
delete stats;
}
我在 vanilla Linux 3.12 上测试了它,但是正如你所看到的,获取 inode 编号的逻辑依赖于内部内核结构。
正如您所看到的,大多数时候,它会跟踪自己写入 SSH 会话:
NAME PID EXECNAME INO OPS/S BYTES
socket.send 2655 sshd 7480 1 96
socket.send 2655 sshd 7480 1 96
socket.send 2655 sshd 7480 1 96
...
示例中有更复杂的脚本:https://sourceware.org/systemtap/examples/network/socktop
警告
SystemTap 是正在开发的内核级软件,因此存在内核崩溃或冻结的可能性。不过,这种情况很少见,但要小心。
参考
- https://sourceware.org/systemtap/- 项目主页
- https://sourceware.org/systemtap/wiki- 维基百科
- https://sourceware.org/systemtap/tapsets/socket.stp.html- 演示脚本中使用的套接字 Tapset
- https://sourceware.org/systemtap/langref/- SystemTap 语言参考