gopack

如何分析某服务器上哪个进程的流量多 ? 猜不少人都有类似的需求, 社区里已经有 c 写的 nethogs 工具, 该工具很方便的获取流量较高的 TOP N 进程列表。
既然有 nethogs 工具,为什么还需要用 goalng 来实现一遍 ?主要是 nethogs 不够灵活,没有开放接口供其他程序调用。对的,我们现在就需要这类接口。当然,不是每个公司都有这类需求,大家通常都是当流量异常时,登上去分析下异常流量。



https://github.com/rfyiamcool/go-netflow




像 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文件描述符的映射关系。



那么怎么流量从哪里获取?抓包,类似 tcpdump 这类使用 pcap 来抓包。



这里详细的说下,基于 pcap 的进程流量统计的实现.



启动阶段扫描 /proc/net/tcp和 /proc/{pid}/fd/{socket inode}。构建三个缓存hashmap
connInodesMap, 定义了 tcp 连接和 inode 号 的对应关系。
inodePidMap, 定义了 inode 和 进程 pid 号 的对应关系。
processMap,存放了进程的基本信息, 最近15秒的流量缓存及流量统计结果。
使用 google 提高的 gopacket 库包进行抓包, 拿到的数据往一个 channel 里面怼,如果队列满,则直接抛弃,可以理解为采样。这个 channel 可以多协程消费,建议就一个消费者。
从 channel 里拿到 packet 结构对象,抽取解析为 ipLayer 和 tcpLayer 两个层,从 ipLayer 获取源和目标的ip地址,从 tcpLayer 获取源和目的端口号。
通过 地址:源端口_目标地址:目标端口从 connInodeMap 里获取 inode 索引号, 再通过 inode 到 inodePidMap 获取 pid 进程号,再用 pid 到 processMap 里获取进程对象,然后进行进出流量的累加计算。
上面说的正常的流程,如果在 pcap 捕获流量时期,有新的连接和新的进程创建了,那么就会拿不到对应的 inode 或者 pid 信息。所以,需要定时重新扫描那几个元数据文件,然后对这几个缓存 map 进行增减处理。把暂未找到进程的 packet ,放到一个 ringbuffer 缓存里,每次定时扫描完 /proc 元数据后,再尝试计算 ringbuffer 里的缓存。



注意的几个点:



/proc 的那个几个元数据不能使用 inotify 来监听,只能是定时扫描或者利用你通知来被动更新。udp也是同理,这里就不复述了。



如何判断是进出流量?



如果 src.ip 是本地的ip地址,那么就是出流量,src.ip 不是本地ip地址,那么肯定就是进流量了。go-netflow 在启动阶段就需要获取本地的ip地址列表。



如何监听多个网卡



google golang gopacket 库默认只能 openlive 一个网卡,没找到可以 openlive 多个设备网卡的相关方法。平时我们用 tcpdump 抓包时,可以通过 -i any 匹配多个网卡。那么在 gopacket 如何实现多个设备网卡监听?实例化多个 openlive 实例不就行了,我居然还还提了 issue 询问该问题,当然没人回复我了。



如何限定 cpu/mem 占用资源



tcpdump 在大流量网关下是相当消耗 cpu 资源的,netflow 里做了一些简单的限制,不是同步处理全量的包,而是扔到队列中异步处理,如果队列满了,则直接丢弃。通过简单的 atomic 计数器来进行限制处理的包数。



但难免还是有意外造成 cpu 资源大量占用,如何限定 cpu 资源?



这里直接使用 linux cgroups 来限定cpu及mem资源,new netflow 对象时可以传入 cgroups 的参数。cpu为核数,可以为 0.5 ,也就是仅占用一个 cpu core 的 50% 资源。mem 是限定的内存量,单位是 MB,默认为0,及为不限制。



WithLimitCgroup(cpu float64, mem int)
写入pcap文件



netflow支持pcap文件的写入,后面可通过 tcpdump 或 wireshark 来读取 netflow 写入的pcap文件。



超时机制



netflow 限定了默认超时时间为 5 分钟,当超过 5 分钟后会关闭所有设备的监听。这么做主要为了避免长时间运行忘了关闭,尤其是通过 netflow 接口来进行抓包的。



https://mp.weixin.qq.com/s/ibVM2ruofb397JMT1pts5w


Category golang