cgroups memória 16GB teto

4

Estou tentando usar o cgroups para limitar o uso de memória de processos do usuário em servidores com uma grande quantidade de memória ram (128 GB ou mais). O que queremos alcançar é reservar cerca de 6 GB de memória RAM para o sistema operacional e os processos de raiz e deixar o resto para os usuários. Queremos ter certeza de que temos memória livre em todos os momentos e não queremos que os servidores troquem de forma agressiva.

Isso funciona bem se o limite estiver baixo o suficiente (< 16GB). Os processos do usuário são atribuídos corretamente ao cgroup correto pelo cgred e, assim que o limite for atingido, o oom finalizará os processos com fome de memória.

A questão aumenta quando nós aumentamos o limite. Em seguida, o servidor iniciará a troca se um processo estiver usando mais de 16 G de RAM, mesmo que o uso de memória ainda esteja bem abaixo do limite e haja bastante memória RAM disponível.

Existe alguma configuração ou algum tipo de máximo que limitaria a quantidade de memória que podemos conceder acesso aos cgroups?

Aqui tem mais informações:

Eu uso o seguinte código para simular processos do usuário comendo memória. O código monitora a memória alocada em uma lista encadeada para que a memória seja usada e acessível de dentro do programa, em vez de apenas ser reservada com malloc (e sobrescrever o ponteiro de cada vez).

/ * Conteúdo do 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;   

}

Até agora eu tentei configurar os seguintes tuneables:

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

Nenhuma dessas configurações de sysctl parece ter algum efeito. O servidor vai começar a trocar depois que meu código acima for acima da barreira de 16GB, mesmo que o swappiness esteja configurado para 0, o overcommit esteja desativado, etc. Eu até tentei desativar o swap sem sucesso. Mesmo sem swap, o kswapd ainda é acionado e o desempenho diminui.

Finalmente, o conteúdo relevante do arquivo 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";
    }
}

Finalmente, usamos o Centos 6, kernel 2.6.32.

Obrigado

    
por Marc-andré Labonté 24.02.2014 / 20:58

1 resposta

5

** Nota: Recuperação para a posteridade **

Seu problema está aqui

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

Você está sempre usando o um nó da memória. Você precisa definir isso para usar todos nós da memória.

Eu também acho que o abaixo também se aplica, e você verá o problema ainda a menos que você saiba sobre o abaixo. Então, deixando a posteridade.

Esse problema basicamente se resume ao hardware que está sendo usado. O kernel tem uma heurística para determinar o valor desse switch. Isso altera como o kernel determina a pressão da memória em um sistema 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.

Para lhe dar uma idéia do que está acontecendo, a memória é dividida em zonas, isso é especificamente útil em sistemas NUMA, nos quais a RAM está ligada a CPUs específicas. Nesses hosts, a localidade de memória pode ser um fator importante no desempenho. Se, por exemplo, os bancos de memória 1 e 2 são atribuídos à CPU física 0, a CPU 1 pode acessar isso, mas com o custo de bloquear essa RAM da CPU 0, o que causa uma degradação de desempenho.

No linux, o zoneamento reflete o layout NUMA da máquina física. Cada zona tem 16 GB de tamanho.

O que está acontecendo no momento com a recuperação de zona é que o kernel está optando por recuperar (gravar páginas sujas em disco, remover cache de arquivos, trocar memória) em uma zona completa (16 GB) em vez de permitir que o processo aloque memória em outra zona (o que afetará o desempenho nessa CPU. É por isso que você percebe a troca após 16 GB.

Se você desativar este valor, isso deve alterar o comportamento do kernel não recuperar agressivamente os dados da zona e, em vez disso, alocar de outro nó.

Tente desativar zone_reclaim_mode executando sysctl -w vm.zone_reclaim_mode=0 no seu sistema e, em seguida, executando novamente o teste.

Observe que os processos de alta memória de longa execução executados em uma configuração como essa com zone_reclaim_mode off se tornarão cada vez mais caros com o tempo.

Se você permitir que vários processos diferentes sejam executados em várias CPUs diferentes, todos usando muita memória para usar qualquer nó com páginas livres, você poderá renderizar efetivamente o desempenho do host a algo parecido com apenas 1 CPU física.

    
por 24.02.2014 / 22:13

Tags