prometheus / procfs

procfs provides functions to retrieve system, kernel and process metrics from the pseudo-filesystem proc.
Apache License 2.0
754 stars 311 forks source link

procfs has data consistency issues when reading /proc/net/tcp #576

Closed shaohk closed 2 months ago

shaohk commented 9 months ago

https://github.com/prometheus/procfs/blob/ff0ad85f7e8bcd5c677d99143f14a2a3aab533aa/net_tcp.go#L28

I read tcp connections by procfs like this

package main

import (
    "fmt"

    "github.com/prometheus/procfs"
)

func main() {
    fs, _ := procfs.NewDefaultFS()

    tcps, _ := fs.NetTCP()
    for _, tcp := range tcps {
        fmt.Println(tcp.LocalAddr, tcp.LocalPort, tcp.RemAddr, tcp.RemPort, tcp.Inode)
    }
}

When I execute multiple times, I find that the same TCP connection appears twice. eg:

Tue Sep 26 18:48 [root@host ~]# ./nettcp | sort | uniq -c | grep '2 '
      ......
      1 192.168.0.2 22815 127.0.0.1 8181 4157386808
      2 192.168.0.2 24219 127.0.0.1 8300 4192187746
      1 192.168.0.2 29727 127.0.0.1 5002 4185948034
      ......

But, When I execute multiple netstat command, there won't be the phenomenon mentioned above. eg:

Tue Sep 26 18:50 [root@host ~]# netstat -npta | awk '{print $1, $4, $5, $7}' | sort | uniq -c
      ......
      1 tcp 192.168.0.2:11609 127.0.0.1:8300 138167/python
      1 tcp 192.168.0.2:12385 127.0.0.1:8300 138188/python
      1 tcp 192.168.0.2:12465 127.0.0.1:8035 266462/agent
      ......

And I find netstat source code, find the code that

FILE *proc_fopen(const char *name)
{
    static char *buffer;
    static size_t pagesz;
    FILE *fd = fopen(name, "r");

    if (fd == NULL)
      return NULL;

    if (!buffer) {
      pagesz = getpagesize();
      buffer = malloc(pagesz);
    }

    setvbuf(fd, buffer, _IOFBF, pagesz);

    return fd;
}

netstat sets the setvbuf to _IOFBF mode when opening the net/tcp file. But golang procfs doesn't set this.

How can we ensure consistency when reading net/tcp in Golang?

discordianfish commented 8 months ago

We essentially just parse net/tcp, can you provide the relevant /proc/net/tcp content in this situation?

dswarbrick commented 8 months ago

@shaohk Are you implying that you suspect the contents of /proc/netstat are changing mid-flight when procfs reads that file? I would be skeptical of that, since it is read with io.ReadAll (limited to 1 MiB) via the internal/util.ReadFileNoStat function.

rexagod commented 3 months ago

I couldn't reproduce this with the aforementioned snippet running for a thousand times. @shaohk Are you still able to reproduce this with the latest release?