Назад | Перейти на главную страницу

cgroups память 16GB потолок

Я пытаюсь использовать cgroups, чтобы ограничить использование памяти пользовательскими процессами на серверах с большим объемом оперативной памяти (128 ГБ и более). Мы хотим зарезервировать около 6 ГБ оперативной памяти для ОС и корневых процессов, а остальное оставить пользователям. Мы хотим быть уверены, что у нас всегда есть свободная память, и мы не хотим, чтобы серверы активно менялись местами.

Это нормально работает, если установлен достаточно низкий лимит (<16 ГБ). Пользовательские процессы правильно назначены cgred для правильной контрольной группы, и как только предел будет достигнут, oom завершит процессы, требующие большого количества памяти.

Проблема возникает, когда мы устанавливаем лимит выше. Затем сервер начнет подкачку, если процесс использует более 16 ГБ оперативной памяти, даже если использование памяти все еще значительно ниже предела и доступно много оперативной памяти.

Есть ли какой-либо параметр или какой-то максимум, который ограничивал бы объем памяти, к которому мы можем предоставить доступ в cgroups?

Вот дополнительная информация:

Я использую следующий код для имитации пользовательских процессов, потребляющих память. Код отслеживает выделенную память в связанном списке, поэтому память используется и доступна изнутри программы, а не просто зарезервирована с помощью malloc (и каждый раз перезаписывает указатель).

/ * Содержимое grabram.c * /

#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>



struct testlink {
  void *ram;
  struct testlink *next;
};

int main (int argc, char *argv[]) {

    int block=8192;
    char buf[block];
    void *ram=NULL;
    FILE *frandom;
    int nbproc,i;
    pid_t pID;
  struct testlink *pstart, *pcurr, *pnew;

    if (argc < 2) {
        //nbproc = 1 by default
        nbproc=1;
    } else {
        if (sscanf(argv[1], "%d", &nbproc) != 1) {
                /* it is an error */
            printf("Failed to set number of child processes\n");
            return -1;
            } 
    }

    // open /dev/urandom for reading
    frandom = fopen("/dev/urandom", "r");
    if ( frandom == NULL ) {
        printf("I can't open /dev/urandom, giving up\n");
        return -1;
    }

    fread(&buf, block, 1, frandom); 
    if ( ferror(frandom) ) {
        // we read less than 1 byte, get out of the loop
        printf("Error reading from urandom\n");
        return -1;
    } 
    fclose (frandom);

    // pID=0 => child pID <0 => error, pID > 0 => parent
    for (i=1; i<nbproc; i++){ 
            pID = fork();
        // break out of the loop  if a child
        if (pID == 0)
            break;
        // exit if fork fails
        if (pID < 0) {
            printf("fork() failed, dying \n");
            return -1;
        }

    }
  pstart = (struct testlink*)malloc(sizeof(struct testlink));
  pstart->ram=NULL;
  pstart->next=NULL;
  pcurr = pstart;

    while ( 1==1 ) {
        ram = (void *)malloc(block);
        if (ram == NULL) {
                    printf("can't allocate memory\n");
                    return -1;
        }

        memcpy(ram, &buf, block);

    // store allocated blocks of ram in a linked list
    // so no one think we are not using them
    pcurr->ram = ram;
    pnew = (struct testlink*)malloc(sizeof(struct testlink));
    pnew->ram=NULL;
    pnew->next=NULL;
    pcurr->next=pnew;
    pcurr=pnew;

    }

    return 0;   

}

До сих пор я пытался установить следующие настраиваемые параметры:

vm.overcommit_memory
vm.overcommit_ratio
vm.swappiness
vm.dirty_ratio
vm.dirty_background_ratio
vm.vfs_cache_pressure

Ни одна из этих настроек sysctl не оказала никакого влияния. Сервер начнет подкачку после того, как мой код выше превысит барьер в 16 ГБ, даже если подкачка установлена ​​на 0, переопределение отключено и т. Д. Я даже попытался отключить подкачку, но безрезультатно. Даже без свопа kswapd все равно запускается, и производительность снижается.

Наконец, соответствующее содержимое файла cgconfig.conf

mount {
  cpuset  = /cgroup/computenodes;
  cpu = /cgroup/computenodes;
  memory  = /cgroup/computenodes;
}


#limit = 120G
group computenodes {
# set memory.memsw the same so users can't use swap
  memory {
    memory.limit_in_bytes = 120G;
    memory.memsw.limit_in_bytes = 120G;
    memory.swappiness = 0;
#    memory.use_hierarchy = 1;
  }

# No alternate memory nodes if the system is not NUMA
# On computenodes use all available cores
    cpuset {
        cpuset.mems="0";
        cpuset.cpus="0-47";
    }
}

Наконец, мы используем Centos 6, ядро ​​2.6.32.

Спасибо

** Примечание: восстановление для потомков **

Ваша проблема здесь

# No alternate memory nodes if the system is not NUMA
# On computenodes use all available cores
    cpuset {
        cpuset.mems="0";
        cpuset.cpus="0-47";
    }
}

Вы только когда-либо используете один узел памяти. Вам нужно установить это, чтобы использовать все узлы памяти.

Я также думаю, что приведенное ниже тоже применимо, и вы все еще увидите проблему, если не знаете о нижеследующем. Так что оставим потомкам.

Эта проблема в основном сводится к используемому оборудованию. В ядре есть эвристика для определения значения этого переключателя. Это меняет способ определения ядром нагрузки на память в системе NUMA.

zone_reclaim_mode:

Zone_reclaim_mode allows someone to set more or less aggressive approaches to
reclaim memory when a zone runs out of memory. If it is set to zero then no
zone reclaim occurs. Allocations will be satisfied from other zones / nodes
in the system.

This is value ORed together of

1   = Zone reclaim on
2   = Zone reclaim writes dirty pages out
4   = Zone reclaim swaps pages

zone_reclaim_mode is set during bootup to 1 if it is determined that pages
from remote zones will cause a measurable performance reduction. The
page allocator will then reclaim easily reusable pages (those page
cache pages that are currently not used) before allocating off node pages.

It may be beneficial to switch off zone reclaim if the system is
used for a file server and all of memory should be used for caching files
from disk. In that case the caching effect is more important than
data locality.

Allowing zone reclaim to write out pages stops processes that are
writing large amounts of data from dirtying pages on other nodes. Zone
reclaim will write out dirty pages if a zone fills up and so effectively
throttle the process. This may decrease the performance of a single process
since it cannot use all of system memory to buffer the outgoing writes
anymore but it preserve the memory on other nodes so that the performance
of other processes running on other nodes will not be affected.

Allowing regular swap effectively restricts allocations to the local
node unless explicitly overridden by memory policies or cpuset
configurations.

Чтобы дать вам некоторое представление о том, что происходит, память разбита на зоны, это особенно полезно в системах NUMA, оперативная память которых привязана к конкретным процессорам. В этих хостах расположение памяти может быть важным фактором производительности. Если, например, банки памяти 1 и 2 назначены физическому ЦП 0, ЦП 1 может получить к нему доступ, но за счет блокировки этой ОЗУ от ЦП 0, что приведет к снижению производительности.

В Linux зонирование отражает структуру NUMA физической машины. Каждая зона имеет размер 16 ГБ.

Что происходит в настоящий момент с включенной регенерацией зоны, так это то, что ядро ​​решает восстановить (записать грязные страницы на диск, удалить файловый кеш, подкачать память) в полной зоне (16 ГБ), а не разрешить процессу выделить память в другой zone (что повлияет на производительность этого процессора. Вот почему вы заметили подкачку после 16 ГБ.

Если вы отключите это значение, это должен изменить поведение ядра, не требуя агрессивного восстановления данных зоны, а вместо этого выделять их из другого узла.

Попробуйте выключить zone_reclaim_mode бегом sysctl -w vm.zone_reclaim_mode=0 в вашей системе, а затем повторно запустите тест.

Обратите внимание: длительные процессы с высокой памятью, выполняемые в такой конфигурации с zone_reclaim_mode off будет становиться все дороже со временем.

Если вы разрешаете запуску множества разрозненных процессов на разных процессорах, использующих много памяти, для использования любого узла со свободными страницами, вы можете эффективно рендерить производительность хоста на что-то похожее на то, что имеет только 1 физический процессор.