Gestione delle risorse mediante i gruppi di controllo

Spiega come i gruppi di controllo organizzano i processi, come systemd applica i criteri delle risorse e quando gestire i gruppi di controllo manualmente.

I gruppi di controllo, definiti cgroups, sono una funzione kernel Oracle Linux che organizza i servizi systemd e, se necessario, i singoli processi (PIDs) in gruppi gerarchici per l'allocazione delle risorse di sistema, ad esempio CPU, memoria e I/O.

Ad esempio, se sono stati identificati tre processi ai quali è necessario allocare il tempo della CPU in un rapporto di 150:100:50, è possibile creare tre processi cgroups, ciascuno con un peso della CPU corrispondente a uno dei tre valori del rapporto e assegnare il processo appropriato a ciascun cgroup.

Importante

Utilizzare systemd per configurare cgroups.

La creazione manuale delle directory cgroup nel file system virtuale /sys/fs/cgroup (come descritto in questo argomento) può essere utile per illustrare i concetti sottostanti. Tuttavia, utilizzare questo approccio per scenari specifici, ad esempio debug o test temporanei. Per la maggior parte dei casi d'uso, utilizzare systemd per configurare cgroups per garantire una gestione delle risorse corretta e persistente.

Per impostazione predefinita, systemd crea un cgroup per i seguenti elementi:

  • Ogni servizio systemd impostato sull'host.

    Ad esempio, un server potrebbe avere il gruppo di controllo NetworkManager.service per raggruppare i processi di proprietà del servizio NetworkManager e il gruppo di controllo firewalld.service per raggruppare i processi di proprietà del servizio firewalld e così via.

  • Ogni utente (UID) sull'host.

La funzionalità cgroup viene attivata come file system virtuale in /sys/fs/cgroup. Ogni cgroup ha una directory corrispondente all'interno del file system /sys/fs/cgroup. Ad esempio, il comando cgroups creato da systemd per i servizi che gestisce può essere visualizzato eseguendo il comando ls -l /sys/fs/cgroup/system.slice | grep ".service" come mostrato nel seguente blocco di codice di esempio:

ls -l /sys/fs/cgroup/system.slice | grep ".service"
            ...root root 0 Mar 22 10:47 atd.service
            ...root root 0 Mar 22 10:47 auditd.service
            ...root root 0 Mar 22 10:47 chronyd.service
            ...root root 0 Mar 22 10:47 crond.service
            ...root root 0 Mar 22 10:47 dbus-broker.service
            ...root root 0 Mar 22 10:47 dtprobed.service
            ...root root 0 Mar 22 10:47 firewalld.service
            ...root root 0 Mar 22 10:47 httpd.service
            ...

È anche possibile creare cgroups personalizzate creando directory nel file system virtuale /sys/fs/cgroup e assegnando ID di processo (PIDs) a cgroups diversi in base ai requisiti di sistema. Tuttavia, si consiglia di utilizzare systemd per configurare cgroups invece di creare manualmente cgroups in /sys/fs/cgroup.

Per il metodo consigliato di gestione di cgroups tramite systemd, vedere Utilizzo di Systemd per gestire i gruppi di controllo.

Nel kernel Linux sono disponibili due versioni di gruppi di controllo.

Gruppi di controllo versione 1 (cgroups v1)

Fornisce una gerarchia di controller per risorsa. Ogni risorsa (CPU, memoria, I/O e così via) ha la propria struttura di gruppi di controllo. Ciò può rendere difficile il coordinamento tra le risorse. Utilizza un'API legacy. Ora considerato deprecato ma disponibile per la compatibilità sui sistemi supportati.

Gruppi di controllo versione 2 (cgroups v2)

Utilizza un'unica gerarchia unificata per tutti i controller, consentendo un migliore coordinamento tra le risorse e una gestione più semplice. Utilizza un'API moderna e semplificata. Questa è l'implementazione preferita e attivamente sviluppata.

La tabella seguente riassume la disponibilità per ogni release di Oracle Linux:

Supporto della versione di cgroups per Oracle Linux Release
Release di Oracle Linux cgroups v1 cgroups v2
Oracle Linux 8 Disponibile (predefinito) Disponibile (abilita manualmente)
Oracle Linux 9 Disponibile (compatibilità) Disponibile (predefinito)
Oracle Linux 10 Non disponibile (obsoleto) Disponibile (predefinito)

Per ulteriori informazioni sui gruppi di controllo, consultare le pagine del manuale cgroups(7) e sysfs(5).

Abilita cgroups v2 su Oracle Linux 8

  1. Controllare le attivazioni correnti.
    sudo mount -l | grep cgroup

    Se l'output mostra già cgroup2 su /sys/fs/cgroup, non sono necessarie ulteriori azioni.

  2. Aggiungere il parametro di avvio della gerarchia unificata.
    sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"

    Il comando aggiunge systemd.unified_cgroup_hierarchy=1 a ogni voce del kernel in modo che la versione 2 sia attiva al boot.

  3. Riavviare per applicare la modifica.
  4. Verificare che cgroups v2 sia attivato.
    sudo mount -l | grep cgroup

    Cercare cgroup2 on /sys/fs/cgroup nell'output.

Verifica cgroups v2 su Oracle Linux 9 e Oracle Linux 10

Confermare il punto di attivazione.
sudo mount -l | grep cgroup
cgroup2 on /sys/fs/cgroup type cgroup2 (rw,nosuid,nodev,noexec,relatime,seclabel,nsdelegate,memory_recursiveprot)

Informazioni sui controller delle risorse kernel

I gruppi di controllo gestiscono l'uso delle risorse tramite i controller delle risorse kernel. Un controller di risorse kernel rappresenta una singola risorsa, ad esempio tempo CPU, memoria, larghezza di banda di rete o I/O su disco.

Per identificare i controller di risorse attivati nel sistema, controllare il contenuto del file /procs/cgroups, ad esempio eseguire:

less /proc/cgroups
#subsys_name    hierarchy       num_cgroups     enabled
cpuset  0       103     1
cpu     0       103     1
cpuacct 0       103     1
blkio   0       103     1
memory  0       103     1
devices 0       103     1
freezer 0       103     1
net_cls 0       103     1
perf_event      0       103     1
net_prio        0       103     1
hugetlb 0       103     1
pids    0       103     1
rdma    0       103     1
misc    0       103     1

Per una spiegazione dettagliata dei controller delle risorse del kernel di cgroups, vedere la pagina del manuale cgroups(7).

Informazioni sul file system del gruppo di controllo

La funzionalità cgroup viene attivata come file system gerarchico in /sys/fs/cgroup.

La directory /sys/fs/cgroup è anche denominata gruppo di controllo root.

Il contenuto della directory del gruppo di controllo root varia leggermente a seconda della versione attivata, ma sui sistemi che utilizzano cgroups v2 in genere vengono visualizzate voci simili alle seguenti:

ls /sys/fs/cgroup
cgroup.controllers      cpuset.mems.effective  memory.stat
cgroup.max.depth        cpu.stat               misc.capacity
cgroup.max.descendants  dev-hugepages.mount    sys-fs-fuse-connections.mount
cgroup.procs            dev-mqueue.mount       sys-kernel-config.mount
cgroup.stat             init.scope             sys-kernel-debug.mount
cgroup.subtree_control  io.pressure            sys-kernel-tracing.mount
cgroup.threads          io.stat                system.slice
cpu.pressure            memory.numa_stat       user.slice
cpuset.cpus.effective   memory.pressure
È possibile utilizzare il comando mkdir per creare sottodirectory di cgroup all'interno del gruppo di controllo root. Ad esempio, è possibile creare le seguenti sottodirectory di cgroup:
  • /sys/fs/cgroup/MyGroups/

  • /sys/fs/cgroup/MyGroups/cgroup1

  • /sys/fs/cgroup/MyGroups/cgroup2

Nota

La migliore procedura di progettazione prevede che l'elemento figlio cgroups sia di almeno 2 livelli nella profondità dell'elemento /sys/fs/cgroup. Gli esempi riportati nell'elenco precedente seguono questa procedura utilizzando il primo gruppo figlio, MyGroups, come elemento padre contenente il diverso cgroups necessario per il sistema.

Ogni cgroup nella gerarchia contiene i file indicati di seguito.

cgroup.controllers

In questo file di sola lettura sono elencati i controller disponibili nel file cgroup corrente. Il contenuto di questo file corrisponde al contenuto del file cgroup.subtree_control nell'elemento padre cgroup.

cgroup.subtree_control

Questo file contiene i controller nel file cgroup.controllers abilitati per l'elemento figlio immediato di cgroup cgroups corrente.

Quando un controller (ad esempio, pids) è presente nel file cgroup.subtree_control, i corrispondenti file di interfaccia del controller (ad esempio, pids.max) vengono creati automaticamente negli elementi figlio immediati del file cgroup corrente.

Per una procedura di esempio che crea gruppi figlio in cui è possibile implementare la gestione delle risorse per un'applicazione, vedere Impostazione del peso della CPU per regolare la distribuzione del tempo della CPU.

Per rimuovere un cgroup, assicurarsi che il file cgroup non contenga altri gruppi figlio, quindi rimuovere la directory. Ad esempio, per rimuovere il gruppo figlio /sys/fs/cgroup/MyGroups/cgroup1 è possibile eseguire il comando seguente:

sudo rmdir /sys/fs/cgroup/MyGroups/cgroup1

Informazioni sui modelli di distribuzione delle risorse

I seguenti modelli di distribuzione consentono di implementare il controllo o la regolamentazione nella distribuzione delle risorse destinate all'uso da parte di cgroups v2:

Fattori ponderali

In questo modello viene calcolato il totale dei pesi di tutti i gruppi di controllo. Ogni gruppo riceve una frazione della risorsa in base al rapporto tra il peso del gruppo e il peso totale.

Considerare 10 gruppi di controllo, ciascuno con un peso di 100 per un totale combinato di 1000. In questo caso, ogni gruppo può utilizzare un decimo di una risorsa specificata.

Il peso viene in genere utilizzato per distribuire risorse senza conservazione dello stato. Per applicare questa risorsa, viene utilizzata l'opzione CPUWeight.

Limiti

In questo modello, un gruppo può utilizzare fino alla quantità configurata di una risorsa. Se una risorsa come l'uso della memoria per un processo supera il limite, il kernel potrebbe interrompere il processo con un messaggio out-of-memory (oom).

È inoltre possibile eseguire l'overcommit delle risorse in modo che la somma dei limiti dei sottogruppi possa superare il limite del gruppo padre. Il sovraimpegno presuppone che le risorse in tutti i sottogruppi non raggiungano tutti i loro limiti contemporaneamente.

Per implementare questo modello di distribuzione, viene spesso utilizzata l'opzione MemoryMax.

Protezioni

In questo modello, a un gruppo viene assegnato un limite protetto. Se l'uso delle risorse del gruppo rimane all'interno dell'importo protetto, il kernel non può privare il gruppo dell'uso della risorsa a favore di altri gruppi che competono per la stessa risorsa. In questo modello è consentito un sovraccarico di risorse.

Per implementare questo modello, viene spesso utilizzata l'opzione MemoryLow.

Allocazioni

In questo modello viene allocato un importo assoluto specifico per l'uso di risorse di tipo finito, ad esempio il budget in tempo reale.

Gestione di cgroups v2 Utilizzo di sysfs

Mostra come creare e ottimizzare le gerarchie cgroups v2 direttamente in /sys/fs/cgroup per la risoluzione dei problemi o i test temporanei.

Importante

Utilizzare systemd per gestire tutta la gestione delle risorse, ove possibile. Per ulteriori informazioni, vedere Utilizzo di Systemd per la gestione dei gruppi di controllo.

Gli esempi forniti qui forniscono il contesto per le azioni eseguite da systemd su un sistema e mostrano le funzionalità al di fuori di systemd. Le informazioni fornite possono essere utili durante il debug dei problemi con cgroups.

La procedura di esempio prevede l'allocazione del tempo CPU tra cgroups a cui sono assegnati diversi PID applicazione. Il tempo CPU e i valori PID dell'applicazione vengono impostati nei file cpu.weight e cgroup.procs di ciascun gruppo.

L'esempio include anche i passaggi necessari per garantire che il controller cpu e i file associati, incluso il file cpu.weight, siano disponibili in cgroups che è necessario creare in /sys/fs/cgroup.

Preparazione del gruppo di controllo per la distribuzione del tempo CPU

Questa procedura descrive come preparare manualmente un gruppo di controllo per gestire la distribuzione del tempo CPU. Si noti che l'approccio consigliato per configurare i gruppi di controllo è l'utilizzo di systemd.

  1. Verificare che il controller cpu sia disponibile nella parte superiore della gerarchia nel gruppo di controllo root.

    Stampa del contenuto del file /sys/fs/cgroup/cgroup.controllers sullo schermo:

    sudo cat /sys/fs/cgroup/cgroup.controllers
    cpuset cpu io memory hugetlb pids rdma misc

    È possibile aggiungere qualsiasi controller elencato nel file cgroup.controllers al file cgroup.subtree_control nella stessa directory per renderli disponibili per l'immediato figlio cgroups del gruppo.

  2. Aggiungere il controller cpu al file cgroup.subtree_control per renderlo disponibile per l'immediato cgroups figlio della radice.

    Per impostazione predefinita, nel file sono presenti solo i controller memory e pids. Per aggiungere il controller cpu, digitare:

    echo "+cpu" | sudo tee /sys/fs/cgroup/cgroup.subtree_control
    
  3. Se necessario, verificare che il controller cpu sia stato aggiunto come previsto.
    sudo cat /sys/fs/cgroup/cgroup.subtree_control
    cpu memory pids
  4. Creare un gruppo figlio sotto il gruppo di controllo radice per diventare il nuovo gruppo di controllo per la gestione delle risorse CPU nelle applicazioni.
    sudo mkdir /sys/fs/cgroup/MyGroups
  5. Facoltativamente, elencare il contenuto della nuova sottodirectory o gruppo figlio e confermare la presenza del controller cpu come previsto.
    ls -l /sys/fs/cgroup/MyGroups
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 cgroup.controllers
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 cgroup.events
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.freeze
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.max.depth
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.max.descendants
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.procs
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 cgroup.stat
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cgroup.subtree_control
    …​
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 cpu.stat
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cpu.weight
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 cpu.weight.nice
    …​
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 memory.events.local
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 memory.high
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 memory.low
    …​
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 pids.current
    -r—​r—​r--. 1 root root 0 Jun  1 10:33 pids.events
    -rw-r—​r--. 1 root root 0 Jun  1 10:33 pids.max
  6. Abilitare il controller cpu nel file cgroup.subtree_control nella directory MyGroups per renderlo disponibile al relativo cgroups figlio immediato.
    echo "+cpu" | sudo tee /sys/fs/cgroup/MyGroups/cgroup.subtree_control
  7. Se necessario, verificare che il controller cpu sia abilitato per i gruppi figlio in MyGroups.
    sudo cat /sys/fs/cgroup/MyGroups/cgroup.subtree_control
    cpu

Impostazione del peso della CPU per regolare la distribuzione del tempo della CPU

Questa procedura descrive come impostare il peso della CPU per tre processi diversi utilizzando un gruppo di controllo per gestire la distribuzione del tempo della CPU. Si noti che l'approccio consigliato per configurare i gruppi di controllo è l'utilizzo di systemd.

Questa procedura si basa sulle seguenti ipotesi:

  • L'applicazione che utilizza eccessivamente risorse CPU è sha1sum, come mostrato nell'output di esempio seguente del comando top:

    sudo top
    ...
    PID   USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
    33301 root      20   0   18720   1756   1468 R  99.0   0.0   0:31.09 sha1sum
    33302 root      20   0   18720   1772   1480 R  99.0   0.0   0:30.54 sha1sum
    33303 root      20   0   18720   1772   1480 R  99.0   0.0   0:30.54 sha1sum
    1 root      20   0  109724  17196  11032 S   0.0   0.1   0:03.28 systemd                     
    2 root      20   0       0      0      0 S   0.0   0.0   0:00.00 kthreadd                    
    3 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_gp                      
    4 root       0 -20       0      0      0 I   0.0   0.0   0:00.00 rcu_par_gp                  
              ...
  • I processi sha1sum hanno PID 33301, 33302 e 33303, come indicato nell'output del campione precedente.

Importante

Come prerequisito per la procedura seguente, è necessario completare i preparativi di cgroup-v2 come descritto in Preparazione del gruppo di controllo per la distribuzione del tempo CPU. Se questi preparati sono stati saltati, non è possibile completare questa procedura.

  1. Creare 3 gruppi figlio nella sottodirectory MyGroups.
    sudo mkdir /sys/fs/cgroup/MyGroups/g1
    sudo mkdir /sys/fs/cgroup/MyGroups/g2
    sudo mkdir /sys/fs/cgroup/MyGroups/g3
  2. Configurare il peso della CPU per ogni gruppo figlio.
    echo "150" | sudo tee /sys/fs/cgroup/MyGroups/g1/cpu.weight
    echo "100" | sudo tee /sys/fs/cgroup/MyGroups/g2/cpu.weight
    echo "50" | sudo tee /sys/fs/cgroup/MyGroups/g3/cpu.weight
  3. Applicare i PID dell'applicazione ai gruppi figlio corrispondenti.
    echo "33301" | sudo tee /sys/fs/cgroup/MyGroups/g1/cgroup.procs
    echo "33302" | sudo tee /sys/fs/cgroup/MyGroups/g2/cgroup.procs
    echo "33303" | sudo /sys/fs/cgroup/MyGroups/g3/cgroup.procs

    Questi comandi impostano le applicazioni selezionate in modo che diventino membri dei gruppi di controllo MyGroups/g*/. Il tempo CPU per ogni processo sha1sum dipende dalla distribuzione del tempo CPU configurata per ogni gruppo.

    I pesi dei gruppi g1, g2 e g3 con processi in esecuzione vengono sommati al livello di MyGroups, ovvero il gruppo di controllo padre.

    Con questa configurazione, quando tutti i processi vengono eseguiti contemporaneamente, il kernel alloca a ciascuno dei processi sha1sum il tempo CPU proporzionato in base al rispettivo file cpu.weight di cgroup, come segue:

    Gruppo figlio Impostazione cpu.weight Percentuale di allocazione tempo CPU
    g1 150 ~50% (150/300)
    g2 100 ~33% (100/300)
    g3 50 ~16% (50/300)

    Se un gruppo figlio non dispone di processi in esecuzione, l'allocazione del tempo CPU per i processi in esecuzione viene ricalcolata in base al peso totale dei gruppi figlio rimanenti con processi in esecuzione. Ad esempio, se il gruppo figlio g2 non dispone di processi in esecuzione, il peso totale diventa 200, ovvero il peso di g1+g3. In questo caso, il tempo CPU per g1 diventa 150/200 (~75%) e per g3, 50/200 (~25%)

  4. Verificare che le applicazioni siano in esecuzione nei gruppi di controllo specificati.
    sudo cat /proc/33301/cgroup /proc/33302/cgroup /proc/33303/cgroup
    0::/MyGroups/g1
    0::/MyGroups/g2
    0::/MyGroups/g3
  5. Controllare il consumo corrente della CPU dopo aver impostato i pesi della CPU.
    top
    ...
    PID   USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
    33301 root      20   0   18720   1748   1460 R  49.5   0.0 415:05.87 sha1sum
    33302 root      20   0   18720   1756   1464 R  32.9   0.0 412:58.33 sha1sum
    33303 root      20   0   18720   1860   1568 R  16.3   0.0 411:03.12 sha1sum
    760 root      20   0  416620  28540  15296 S   0.3   0.7   0:10.23 tuned
    1 root      20   0  186328  14108   9484 S   0.0   0.4   0:02.00 systemd
    2 root      20   0       0      0      0 S   0.0   0.0   0:00.01 kthread
    ...