最近做了一次网络抖动排障,庆幸定位到了原因,记录一下。

网络抖动的表现

业务方是 DB 团队,他们对慢查询有监控,发现了一些慢查询;而且,确认是接入虚拟网络后才出现的慢查询。

所以,他们确信是我这边的问题,于是联系到了我这边。如下,是我同事做的 ping 记录:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# cat ping_log | grep -v "time=0"
PING x.x.x.x (x.x.x.x) 56(84) bytes of data.
64 bytes from x.x.x.x: icmp_seq=3415 ttl=62 time=197 ms
64 bytes from x.x.x.x: icmp_seq=3416 ttl=62 time=173ms
64 bytes from x.x.x.x: icmp_seq=3417 ttl=62 time=149ms
64 bytes from x.x.x.x: icmp_seq=3418 ttl=62 time=125 ms
64 bytes from x.x.x.x: icmp_seq=3419 ttl=62 time=101 ms
64 bytes from x.x.x.x: icmp_seq=3420 ttl=62 time=77.3 ms
64 bytes from x.x.x.x: icmp_seq=3421 ttl=62 time=53.3 ms
64 bytes from x.x.x.x: icmp_seq=3422 ttl=62 time=29.3 ms
64 bytes from x.x.x.x: icmp_seq=3423 ttl=62 time=5.27 ms

我也用 ping -i 0.02 x.x.x.x 确认了一下,的确是这样,几千个 ping 包中,有几个包的延迟很高。

排查过程

首先,我确认了一下虚拟网络网关的环境设置,发现有点问题;于是,我修改了一下,但是问题依旧。

然后,我怀疑是 CPU 抢占的问题;于是,用 htop -d 0.2 看了一下,发现 CPU 使用率并不高;不过,恰巧注意到 ethtool -m XXX 会定期执行一下;接着,用 bpftrace execsnoop.bt 确认了一下,的确是这样:

1
2
3
4
5
6
7
# bpftrace /usr/sbin/execsnoop.bt
Attaching 2 probes...
TIME (ms)   PID ARGS
1361        1844976 ethtool -m XXX0
2117        1844977 ethtool -m XXX1
6774        1844978 ethtool -m XXX0
7118        1844979 ethtool -m XXX1

不过,execsnoop.bt 没提供 PPID,不知道是哪个进程在执行 ethtool -m XXX;于是,我用 for i in {1..100}; do ps -ef | grep ethtool; sleep 0.1; done 确认了一下 PPID,居然是某个 exporter 在执行 ethtool -m XXX

经同事一起确认,ethtool -m XXX 会影响 Intel 网卡收发包,从而导致网络抖动。

随后,让负责 exporter 的同事,修改了一下代码,不再执行 ethtool -m XXX;问题解决。

ixgbe 网卡驱动

ethtool -i XXX 确认网卡驱动是 ixgbe,于是,我看了一下 ixgbe 网卡驱动的源代码。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// ${KERNEL}/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c

static int ixgbe_get_module_info(struct net_device *dev,
                       struct ethtool_modinfo *modinfo)
{
    // ...

    /* Check whether we support SFF-8472 or not */
    status = hw->phy.ops.read_i2c_eeprom(hw,
                                         IXGBE_SFF_SFF_8472_COMP,
                                         &sff8472_rev);
    // ...

    /* addressing mode is not supported */
    status = hw->phy.ops.read_i2c_eeprom(hw,
                                         IXGBE_SFF_SFF_8472_SWAP,
                                         &addr_mode);
    // ...

    return 0;
}

static int ixgbe_get_module_eeprom(struct net_device *dev,
                     struct ethtool_eeprom *ee,
                     u8 *data)
{
    // ...

    for (i = ee->offset; i < ee->offset + ee->len; i++) {
        /* I2C reads can take long time */
        if (test_bit(__IXGBE_IN_SFP_INIT, &adapter->state))
            return -EBUSY;

        if (i < ETH_MODULE_SFF_8079_LEN)
            status = hw->phy.ops.read_i2c_eeprom(hw, i, &databyte);
        else
            status = hw->phy.ops.read_i2c_sff8472(hw, i, &databyte);

        if (status)
            return -EIO;

        data[i - ee->offset] = databyte;
    }

    return 0;
}

static const struct ethtool_ops ixgbe_ethtool_ops = {
    .get_module_info    = ixgbe_get_module_info,
    .get_module_eeprom  = ixgbe_get_module_eeprom,
};

发现,ethtool -m XXX 会读取网卡的硬件信息,估计是这些操作影响了网卡的收发包。

总结

庆幸的是,那个 exporter 用的是 ethtool -m XXX 命令行来获取信息,而不是用 ioctl() 系统调用;否则,我可能就找不到原因了。

所以,有没有办法对 ethtool 使用的 ioctl() 系统调用进行监控呢?kprobe dev_ethtool() 即可。