Метрика cpuPercent из статистики докеров по сравнению с контрольными группами

Я новичок в cgroups и пытаюсь получить статистику контейнера с помощью cgroups. Раньше я использовал docker stats, но пытался собрать аналогичные метрики и с cgroups.

В статистике докера раздел статистики процессора выглядит следующим образом:

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

И метрика % процессора рассчитывается с использованием приведенного ниже уравнения:

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

Я ищу контрольные группы для сбора systemUsage и totalUsage, но, похоже, у них нет похожих показателей:

cgroups имеет псевдофайл cpuacct.stats, в котором есть галочки user и system, но они совпадают только с usage_in_user_mode и usage_in_kernel_mode из вывода docker stats.

и псевдофайл cpuacct.usage_per_cpu имеет использование на процессор, что соответствует total_usage из выходных данных статистики докера выше.

$cat cpuacct.stat 
user 1914
system 455

$cat cpuacct.usage_percpu 
27120642519 

Но я не мог найти способа выяснить, как собрать «systemUsage» из cgroups.

Любые наводки будут очень полезны!

Спасибо!


person Venkat Teki    schedule 19.07.2017    source источник


Ответы (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. «system_cpu_usage» API статистики Docker относится к использованию ЦП хоста.
  2. «Cpu_usage» > «total_usage» API статистики Docker относится к использованию контейнера на каждый ЦП.
  3. Следовательно, после расчета (cpuDelta/systemDelta) мы получаем использование процессора для каждого системного процессора.
  4. Теперь нам нужно умножить результат шага 3 и общее количество ЦП, выделенных для контейнера докеров, чтобы получить общее использование ЦП на системный ЦП.
  5. Результат шага 4 при умножении на 100 дает нам загрузку процессора в процентах.

Вернемся к вопросу: как докер рассчитывает системный процессор?

Для расчета использования системного ЦП докер использует «/proc/stat», определенный POSIX. Он ищет строку статистики ЦП, а затем суммирует первые семь предоставленных полей. Ниже приведен код 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
}

Для подтверждения сопоставьте «system_cpu_usage» API статистики докеров с выводом приведенной ниже команды:

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