proc/net/snmp
Simple Network Management Protocol (SNMP) is a networking protocol used for the management and monitoring of network-connected devices in Internet Protocol networks
像 promethues, openfalcon 这类开源监控软件,通过 /proc/net/snmp 和 /proc/net/netstat 获取连接和流量信息。
/proc/net/snmp文件只是提供了主机各层的IP、ICMP、ICMPMsg、TCP、UDP详细数据/proc/net/netstat文件提供了主机的收发包数、收包字节数据。
这两个文件只能看到主机级别的信息,没法实现进程级别的流量采集。
但是我们可以从其他路子来实现细粒度的进程级别的流量监控。
通过 /proc/net/tcp ,/proc/net/udp 文件,我们可以拿到 tcp及udp 的四元组和 inode 信息。通过 /proc/{pid}/fd/ 可以拿到 pid 及 socket inode文件描述符的映射关系。
http://hengyunabc.github.io/netstat-difference-proc-fd-socket-stat/
最近,线上一个应用,发现socket数缓慢增长,并且不回收,超过警告线之后,被运维监控自动重启了。
首先到zabbix上观察JVM历史记录,发现JVM-Perm space最近两周没有数据,猜测是程序从JDK7切换到JDK8了。问过开发人员之后,程序已经很久没有重启了,最近才重新发布的。而在这期间,线上的Java运行环境已经从JDK7升级到JDK8了。
因为jdk8里没有Perm space了,换成了Metaspace。
netstat
到线上服务器上,用netstat来统计进程的connection数量。
1
|
netstat -antp | grep pid | wc -l
|
发现比zabbix上的统计socket数量要少100多,netstat统计只有100多,而zabbix上监控数据有300多。
于是到/proc/$pid/fd下统计socket类型的fd数量:
1
|
cd /proc/$pid/fd
|
发现数据和zabbix上的数据一致。
netstat是怎么统计的
下载netstat的源代码
http://unix.stackexchange.com/questions/21503/source-code-of-netstat
1
|
apt-get source net-tools
|
从netstat的代码里,大概可以看到是读取/proc/net/tcp里面的数据来获取统计信息的。
java和c版的简单netstat的实现
java版的
http://www.cs.earlham.edu/~jeremiah/LinuxSocket.java
C版的:
http://www.netmite.com/android/mydroid/system/core/toolbox/netstat.c
用starce跟踪netstat
1
|
strace netstat -antp
|
可以发现netstat把/proc 下的很多数据都读取出来了。于是大致可以知道netstat是把/proc/pid/fd 下面的数据和/proc/net/下面的数据汇总,对照得到统计结果的。
哪些socket会没有被netstat统计到?
又在网上找了下,发现这里有说到socket如果创建了,没有bind或者connect,就不会被netstat统计到。
http://serverfault.com/questions/153983/sockets-found-by-lsof-but-not-by-netstat
实际上,也就是如果socket创建了,没有被使用,那么就只会在/proc/pid/fd下面有,而不会在/proc/net/下面有相关数据。
简单测试了下,的确是这样:
1
|
int socket = socket(PF_INET,SOCK_STREAM,0); //不使用
|
另外,即使socket是使用过的,如果执行shutdown后,刚开始里,用netstat可以统计到socket的状态是FIN_WAIT1。过一段时间,netstat统计不到socket的信息的,但是在/proc/pid/fd下,还是可以找到。
中间的时候,自己写了个程序,把/proc/pid/fd 下的inode和/proc/net/下面的数据比较,发现的确有些socket的inode不会出现在/proc/net/下。
用lsof查看
用lsof查看socket inode:
触发GC,回收socket
于是尝试触发GC,看下socket会不会被回收:
1
|
jmap -histo:live <pid>
|
结果,发现socket都被回收了。
再看下AbstractPlainSocketImpl的finalize方法:
1
|
/**
|
可以看到socket是会在GC时,被close掉的。
写个程序来测试下:
1
|
public class TestServer {
|
先执行,查看/proc/pid/fd,可以发现有相关的socket fd,再触发GC,可以发现socket被回收掉了。
其它的东东
anon_inode:[eventpoll]
1
|
ls -al /proc/pid/fd
|
可以看到有像这样的输出:
1
|
661 -> anon_inode:[eventpoll]
|
这种类型的inode,是epoll创建的。
再扯远一点,linux下java里的selector实现是epoll结合一个pipe来实现事件通知功能的。所以在NIO程序里,会有anon_inode:[eventpoll]和pipe类型的fd。
为什么tail -f /proc/$pid/fd/1 不能读取到stdout的数据
http://unix.stackexchange.com/questions/152773/why-cant-i-tail-f-proc-pid-fd-1
https://github.com/moooofly/MarkSomethingDown/blob/master/Linux/TCP%20%E7%9B%B8%E5%85%B3%E7%BB%9F%E8%AE%A1%E4%BF%A1%E6%81%AF%E8%AF%A6%E8%A7%A3.md
我们知道 TCP 相关统计信息包含在如下文件中
/proc/net/netstat/proc/net/snmp
可以通过 netstat -s 的输出信息进行确认;
$ strace -e open netstat -s
浙公网安备 33010602011771号