我正在寻找“sar -n SOCK”输出的 totsck 列的解释
09:44:06 PM totsck tcpsck udpsck rawsck ip-frag tcp-tw
09:44:09 PM 580 18 5 0 0 1
09:44:10 PM 580 18 5 0 0 0
09:44:11 PM 580 18 5 0 0 0
Average: 580 18 5 0 0 1
显然它不是 tcp/udp/raw 套接字的总和。我能想到的唯一其他解释是它是套接字加上
sysctl fs.file-nr
但在我的测试盒里
fs.file-nr = 5632 0 803168
非常感谢准确的解释。
谢谢
编辑 2:显然 totsck 相当于
cat /proc/net/sockstat
这引出了一个问题,那里算的是什么。我发现这但最后它只建议询问编写该特定内核代码的人。
编辑(针对域套接字会计):
[root@fedora16 fs]# netstat --protocol unix| wc -l
413
[root@fedora16 fs]# sar -n SOCK 1 1
Linux 3.3.1-5.fc16.x86_64 (fedora16) 06/21/2012 _x86_64_ (4 CPU)
10:03:25 PM totsck tcpsck udpsck rawsck ip-frag tcp-tw
10:03:26 PM 598 6 5 0 0 3
Average: 598 6 5 0 0 3
答案1
看起来,系统使用的套接字总数中还包括 UNIX 域套接字(STREAM 和 DGRAM)。进程将 UNIX 域套接字引用为文件系统中的 inode。有很多东西仍将 UNIX 域套接字用于各种目的,因此sar
将其记录下来。检查该输出以netstat -a
查看系统上打开了多少个 UNIX 域套接字。
fs.file-nr
是最大文件句柄的数量,虽然很重要,但与您在输出中看到的内容无关sar
。
编辑:请考虑sar
基本上读取/proc/net/sockstat
并计算该计数的平均值或报告历史值。似乎/proc/net/sockstat
从两个地方(2.6.27 的内核源代码)获取数据,位置是net/socket.c
行:2324 和net/ipv4/proc.c
行 54 及以下,总数来自第一个位置,其余来自第二个位置。通过结构net
还可以揭示哪些套接字被计数/记录并打印到 proc 文件系统中。
79 * @SOCK_STREAM: stream (connection) socket
80 * @SOCK_DGRAM: datagram (conn.less) socket>
81 * @SOCK_RAW: raw socket
82 * @SOCK_RDM: reliably-delivered message>
83 * @SOCK_SEQPACKET: sequential packet socket
84 * @SOCK_DCCP: Datagram Congestion Control Protocol socket
答案2
好吧,我也遇到了这个问题,结论是所有内核都有这个明显的缺陷/错误。我在 3.10、4.2、5.1 和 6.2 内核上测试过这个问题,从 2.6 到 4.16 之前的代码没有变化。
看来我们的插座有漏电!
考虑以下命令:
ss -Han |wc -l ;\
awk 'NR==1 { print $NF }' /proc/net/sockstat
每个命令的输出应该大致相同(第一个命令至少会创建 1 个套接字)。但对于我的许多服务器,每个命令的输出都大不相同。
sar
从 中获取信息/proc/net/sockstat
,正如我们在第二个命令中看到的那样。此信息由内核套接字驱动程序中的代码提供,如下所述。
可能两者都ss
没有netstat
提供详尽的套接字列表。这可能是他们的一个错误或缺乏文档。
可能是错误在 的代码中net/socket.c
。但是,我找不到它。该代码处理系统中所有套接字的分配和释放。当它创建一个新的套接字时,它会增加一个计数器。当它销毁一个套接字时,它减少一个计数器。非常简单,不应该有出错的余地。
但是,对于多 CPU 系统,代码确实存在一些隐藏的复杂性。我发现我的单 CPU VM 总体上比其他系统差异较小。但这些系统只分配了 1 个 CPU,因为它们是测试系统,使用率不高。我的单 CPU 系统上的差异小于 10%。但对于多 CPU VM,差异很大,从小于 1% 到 10 倍!
报告时每个 CPU 的代码net/socket.c
如下所示:
for_each_possible_cpu(cpu)
counter += per_cpu(sockets_in_use, cpu);
增量器和减量器如下所示:
percpu_add(sockets_in_use,1);
...
percpu_sub(sockets_in_use,1);
从 2005 年之前到 2017 年,这段代码没有发生根本性变化,在 4.16 版中使用了 net-namespaces。但我仍然在 6.2 版之前遇到这种差异,所以也许底层是相同的代码。
这些 per-cpu 宏隐藏了大量细节。我并不完全理解,但也许在我学习之后我会理解的这一页. 最终,它应该就像一个 cpu 编号索引数组。我认为需要这种构造,以便每个 CPU 上运行的内核可以更新自己的计数器,以避免昂贵的自旋锁定和可能的缓存刷新。宏确保这些添加/减操作是原子的。每个计数器都是一个int
。不执行边界检查。即使跨多个 CPU 出现上溢/下溢,整数数学也能正常工作。而且它是到处使用的非常著名的代码。
另一种可能性是套接字计数器使用的一个或多个内存区域被破坏其他系统中的代码。