【问题标题】:cpuPercent metric from docker stats vs cgroups来自 docker stats 与 cgroups 的 cpuPercent 指标
【发布时间】:2017-07-19 16:45:05
【问题描述】:

我是 cgroups 的新手,正在尝试使用 cgroups 获取容器统计信息。以前我使用的是docker stats,但也尝试使用cgroups 收集类似的指标。

在 docker stats 中,cpu stats 部分如下所示:

"cpu_usage": {
        "total_usage": 27120642519,
        "percpu_usage": [27120642519],
        "usage_in_kernelmode": 4550000000,
        "usage_in_usermode": 19140000000
    },
    "system_cpu_usage": 42803030000000,

并且,cpu % 指标是使用以下公式计算的:

cpuDelta = float64(v.CpuStats.CpuUsage.TotalUsage - previousCPU)
systemDelta = float64(v.CpuStats.SystemUsage - previousSystem)
cpuPct = cpuDelta/systemDelta

我正在查看 cgroups 以收集 systemUsagetotalUsage,但它似乎没有类似的指标:

cgroups 有一个伪文件 cpuacct.stats,其中有 usersystem 刻度,但这些仅与来自 docker stats 输出的 usage_in_user_modeusage_in_kernel_mode 匹配。

并且 cpuacct.usage_per_cpu 伪文件具有每个 cpu 的使用情况,这与上面 docker stats 输出中的 total_usage 匹配。

$cat cpuacct.stat 
user 1914
system 455

$cat cpuacct.usage_percpu 
27120642519 

但是,我找不到任何方法来弄清楚如何从 cgroups 中收集“systemUsage”。

任何线索都会有很大帮助!

谢谢!

【问题讨论】:

    标签: docker cgroups


    【解决方案1】:

    您的问题的答案不在于 cgroups。请参考以下几点:

    func calculateCPUPercentUnix(previousCPU, previousSystem uint64, v *types.StatsJSON) float64 {
        var (
            cpuPercent = 0.0
            // calculate the change for the cpu usage of the container in between readings
            cpuDelta = float64(v.CPUStats.CPUUsage.TotalUsage) - float64(previousCPU)
            // calculate the change for the entire system between readings
            systemDelta = float64(v.CPUStats.SystemUsage) - float64(previousSystem)
        )
        if systemDelta > 0.0 && cpuDelta > 0.0 {
            cpuPercent = (cpuDelta / systemDelta) * float64(len(v.CPUStats.CPUUsage.PercpuUsage)) * 100.0
        }
        return cpuPercent
    }
    
    1. Docker stats API 的“system_cpu_usage”是指主机的 CPU 使用率。
    2. Docker stats API 的“cpu_usage”>“total_usage”指的是容器的每个 CPU 的使用情况。
    3. 因此,在计算 (cpuDelta/systemDelta) 之后,我们得到每个系统 CPU 的每个 CPU 使用率。
    4. 现在我们需要将第 3 步的结果与分配给 docker 容器的 CPU 总数相乘,得到每个系统 CPU 的总 CPU 使用率。
    5. 第 4 步的结果乘以 100 后得出的 CPU 利用率百分比。

    回到问题: docker是如何计算系统CPU的?

    要计算系统 CPU 使用率,docker 使用 POSIX 定义的“/proc/stat”。它查找 CPU 统计信息行,然后总结提供的前七个字段。下面提到了为执行所需步骤而编写的 golang 代码。

    https://github.com/rancher/docker/blob/3f1b16e236ad4626e02f3da4643023454d7dbb3f/daemon/stats_collector_unix.go#L137

    // getSystemCPUUsage returns the host system's cpu usage in
    // nanoseconds. An error is returned if the format of the underlying
    // file does not match.
    //
    // Uses /proc/stat defined by POSIX. Looks for the cpu
    // statistics line and then sums up the first seven fields
    // provided. See `man 5 proc` for details on specific field
    // information.
    func (s *statsCollector) getSystemCPUUsage() (uint64, error) {
        var line string
        f, err := os.Open("/proc/stat")
        if err != nil {
            return 0, err
        }
        defer func() {
            s.bufReader.Reset(nil)
            f.Close()
        }()
        s.bufReader.Reset(f)
        err = nil
        for err == nil {
            line, err = s.bufReader.ReadString('\n')
            if err != nil {
                break
            }
            parts := strings.Fields(line)
            switch parts[0] {
            case "cpu":
                if len(parts) < 8 {
                    return 0, derr.ErrorCodeBadCPUFields
                }
                var totalClockTicks uint64
                for _, i := range parts[1:8] {
                    v, err := strconv.ParseUint(i, 10, 64)
                    if err != nil {
                        return 0, derr.ErrorCodeBadCPUInt.WithArgs(i, err)
                    }
                    totalClockTicks += v
                }
                return (totalClockTicks * nanoSecondsPerSecond) /
                    s.clockTicksPerSecond, nil
            }
        }
        return 0, derr.ErrorCodeBadStatFormat
    }
    

    请将 docker stats API 的“system_cpu_usage”与以下命令的输出相匹配以确认:

    cat /proc/stat|grep -w cpu|awk '{split($0,a,\" \"); sum=0; for(i=2;i<8;i++)(sum+=a[i])} END{print sum }'
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-01-16
      • 2020-05-19
      • 1970-01-01
      • 1970-01-01
      • 2011-05-28
      • 1970-01-01
      • 2021-08-17
      • 2020-08-16
      相关资源
      最近更新 更多