SSD Nodes Learn Hosting plans →
Guide Matt ConnorDi Matt Connor

Limitare memoria e CPU di un servizio systemd

Un processo limitato può bloccare il VPS: configura MemoryHigh, MemoryMax, CPUQuota e TasksMax e interpreta l'errore OOM dopo l'uccisione.

Limitare memoria e CPU dei processi con un drop-in di systemd

È possibile limitare la memoria e la CPU usate da un processo su un VPS Linux aggiungendo alcune righe all'unità che esegue il processo. MemoryMax= è il limite massimo rigido della memoria. CPUQuota= è il limite massimo del tempo di CPU. Entrambi vengono applicati tramite cgroup v2 (control groups, versione 2), la funzionalità del kernel che systemd usa già per contabilizzare ogni servizio presente sul sistema.

sudo systemctl edit myapp.service

Il comando apre un file drop-in che contiene istruzioni sotto forma di commenti. Aggiungere queste righe prima delle istruzioni:

[Service]
MemoryHigh=512M
MemoryMax=768M
MemorySwapMax=0
CPUQuota=80%
TasksMax=128
sudo systemctl daemon-reload
sudo systemctl restart myapp.service
systemctl show myapp.service -p MemoryHigh -p MemoryMax -p CPUQuotaPerSecUSec -p TasksMax

systemctl show deve riportare gli stessi valori usando le unità del kernel: MemoryMax=805306368 e CPUQuotaPerSecUSec=800ms. Se restituisce MemoryMax=infinity, il drop-in non è stato caricato. Verificare che il file sia stato creato in /etc/systemd/system/myapp.service.d/override.conf e che inizi con l'intestazione [Service], perché una riga di configurazione senza una sezione precedente fa registrare a systemd Assignment outside of section. Ignoring. e avvia il servizio senza applicare alcun limite.

Il resto della guida spiega come scegliere questi valori e quali problemi possono verificarsi anche dopo averli impostati.

Perché un processo fuori controllo blocca una VPS senza riempirla

Un processo che raggiunge un limite rigido di memoria viene terminato in circa un secondo e il servizio viene riavviato. Questo è il caso favorevole. Il caso peggiore è quello in cui non viene terminato nulla: il server risponde al ping, SSH accetta la connessione, ma il prompt della shell non compare mai. La macchina è attiva e occupata, ma nessuna di queste attività produce risultati utili.

Il meccanismo è il seguente, anche se non è immediato. Quando la memoria libera si esaurisce, il kernel recupera pagine invece di assegnarne di nuove. Le pagine più semplici da recuperare sono quelle associate ai file, mentre la page cache contiene il codice eseguibile di tutto ciò che è in esecuzione. Il kernel espelle quindi le pagine di testo di sshd, e la prima istruzione eseguita da sshd provoca un page fault che deve rileggere quei byte dallo storage. Alla fine, ogni processo resta in attesa del disco invece di eseguire il proprio lavoro. Le stesse pagine vengono espulse e ricaricate continuamente in un ciclo chiamato thrashing.

Su una VPS questo fenomeno è più grave che su un laptop per due motivi. Lo storage è spesso collegato tramite rete o condiviso, quindi ogni page fault richiede più millisecondi rispetto a un dispositivo NVMe locale. Inoltre, il kernel non misura il tempo: misura i fallimenti. Finché il reclaim riesce a restituire una pagina, anche molto lentamente, il kernel ritiene di stare facendo progressi e non attiva l'out of memory (OOM) killer. Un server può restare in questo stato per molti minuti prima che venga terminato un processo.

È possibile osservare il fenomeno mentre si verifica. Su Linux 4.20 e versioni successive, il kernel espone le pressure stall information (PSI):

cat /proc/pressure/memory
cat /proc/pressure/io
some avg10=63.72 avg60=41.02 avg300=12.33 total=13729481
full avg10=48.15 avg60=30.44 avg300=8.90 total=9114233

La riga full è quella rilevante. full avg10=48.15 significa che, durante il 48% degli ultimi dieci secondi, tutte le attività non inattive del server erano contemporaneamente in attesa a causa della memoria; di conseguenza, nessuna attività stava avanzando. Su un server in condizioni normali, il valore di full è vicino a zero. Oltre 10 il rallentamento è percepibile, mentre valori pari o superiori a 40 corrispondono allo stato che viene descritto come blocco completo.

Questo spiega anche perché un limite, da solo, non costituisce una garanzia. Un'unità soggetta a MemoryHigh= viene limitata invece di essere terminata: resta attiva, ma continua a essere lenta, e non viene riavviata perché, dal punto di vista di systemd, non ha mai avuto esito negativo. Un'unità con un limite che può ancora usare lo swap genera operazioni di lettura e scrittura addebitate a quell'unità, ma servite da un unico dispositivo condiviso. Di conseguenza, può aumentare /proc/pressure/io per tutti gli altri servizi del server. I limiti stabiliscono chi sostiene il costo della carenza di risorse, ma non possono creare capacità.

Verificare che il VPS utilizzi cgroup v2

stat -fc %T /sys/fs/cgroup

cgroup2fs è la gerarchia unificata, richiesta dalle impostazioni di memoria riportate di seguito. tmpfs indica che il sistema ha avviato il layout v1 precedente, nel quale MemoryHigh= e MemorySwapMax= non sono supportati e il comportamento OOM per unità è diverso, anche se CPUQuota= continua a funzionare tramite il file legacy cpu.cfs_quota_us. Ubuntu 22.04 e versioni successive, così come Debian 11 e versioni successive, utilizzano v2 per impostazione predefinita. Un'immagine meno recente non lo fa; inoltre, con systemd 257 o versioni precedenti, lo stesso vale per un kernel avviato con systemd.unified_cgroup_hierarchy=0. systemd 258 ha rimosso il supporto per cgroup v1 e monta sempre la gerarchia unificata all'avvio; quindi, nelle release che lo includono, quell'argomento non consente più di riattivare v1.

Su cgroup v2, systemd abilita per impostazione predefinita la contabilizzazione della memoria per ogni unità, quindi i valori sono già disponibili:

systemd-cgtop -m

Il comando elenca i cgroup ordinati in base all'utilizzo della memoria. È il modo più rapido per capire "che cosa sta consumando le risorse di questo server" mentre il sistema è ancora operativo. Se il server è nuovo, le attività relative all'account e al firewall descritte in i primi dieci minuti su un nuovo VPS vengono prima di questa verifica.

MemoryHigh applica il throttling. MemoryMax termina i processi.

La differenza tra le due impostazioni della memoria determina il comportamento in caso di errore.

  • MemoryHigh= è un limite morbido. Quando viene superato, il kernel recupera memoria in modo aggressivo da quel cgroup e rallenta intenzionalmente le nuove allocazioni. L'utilizzo può comunque superare il valore e nessun processo viene terminato.
  • MemoryMax= è un limite rigido. Quando un'allocazione non può essere soddisfatta entro questo limite, entra in funzione l'OOM killer all'interno di quel cgroup e termina uno dei processi appartenenti a quella unità.

Questa seconda caratteristica è il motivo principale per impostare MemoryMax= su tutto ciò di cui non hai il pieno controllo. Senza un limite, l'esaurimento della memoria diventa un problema dell'intero sistema e l'OOM killer globale sceglie il processo da terminare in base a oom_score, che nella maggior parte dei casi significa il processo più grande. Di solito il processo più grande è il database, non lo script che ha causato la perdita di memoria. Con un limite, la terminazione avviene all'interno dell'unità che ha causato il problema.

Imposta entrambi i limiti, mantenendo MemoryHigh= circa dal 20 al 30 percento al di sotto di MemoryMax=. La differenza costituisce una zona di avviso: una perdita lenta supera High e si manifesta come un servizio che rallenta, mentre un picco improvviso supera direttamente Max e causa la terminazione del processo.

I valori percentuali vengono calcolati in base alla memoria fisica installata. Di conseguenza, MemoryMax=25% su un piano da 4 GB equivale a 1 GB e resta pari a un quarto della memoria del sistema anche dopo l'aumento delle risorse del piano. MemorySwapMax=0 impedisce completamente a quell'unità di usare lo swap. Quando raggiunge MemoryMax=, la terminazione avviene rapidamente invece di arrivare dopo un lungo rallentamento causato dallo swap. Al di sotto di quel limite, MemoryHigh= può comunque applicare il throttling. Il superamento del limite alto non attiva mai l'OOM killer, quindi un'unità che oscilla tra i due limiti rimane lenta invece di terminare.

Alcuni servizi permettono di definire in anticipo il consumo previsto invece di misurarlo. Un'unità Ollama dimensiona la propria cache KV in base alla finestra di contesto configurata. Prima di scegliere un limite, consulta quanto costa in RAM aumentare num_ctx.

Un limite deve essere accompagnato da una policy di riavvio. In caso contrario, la terminazione lascia semplicemente il servizio arrestato.

[Unit]
StartLimitIntervalSec=300
StartLimitBurst=5

[Service]
Restart=on-failure
RestartSec=5s

StartLimit* deve trovarsi in [Unit] e Restart= in [Service]. Se inserisci uno dei due nella sezione errata, systemd lo ignora. Cinque riavvii in cinque minuti indicano una perdita, non un evento temporaneo. Dopo questo numero, systemd rinuncia e lascia l'unità nello stato failed. È lo stato che vuoi trovare in seguito, invece di un ciclo di crash che nasconde il problema.

Limita la CPU con CPUQuota o condividila con CPUWeight

CPUQuota= utilizza una percentuale del tempo disponibile su una CPU. CPUQuota=50% corrisponde a metà di un core. CPUQuota=200% equivale a due core, che l'unità può distribuire su tutti i thread necessari. In un piano con 2 vCPU, CPUQuota=200% corrisponde all'intera macchina.

CPUWeight= è l'impostazione predefinita più adatta per la maggior parte dei servizi. È una quota relativa da 1 a 10000 e il valore predefinito del kernel è 100. Ha effetto solo quando più processi competono per la CPU: sotto carico, un processo di backup con CPUWeight=20 cede la precedenza a un web server con valore 100, mentre quando la macchina è inattiva può comunque utilizzare tutta la CPU disponibile. Una quota rigida spreca questa capacità inutilizzata.

È importante valutare correttamente il vantaggio offerto da un limite CPU. Un processo che satura la CPU raramente blocca Linux, perché lo scheduler continua ad assegnare tempo di esecuzione agli altri processi. È la memoria che può rendere indisponibile la macchina. Usa CPUQuota= quando ti serve un limite massimo prevedibile, ad esempio per una compilazione o un agent che altrimenti funzionerebbe a pieno carico per un'ora. Il dimensionamento di questo tipo di carico è un problema distinto, trattato in quanta RAM e CPU servono a un VPS per un coding agent.

Se la CPU risulta occupata mentre nessuno dei tuoi processi sembra utilizzarla in misura significativa, la causa potrebbe trovarsi dall'altra parte dell'hypervisor. Si tratta dello steal time della CPU causato da un vicino rumoroso e nessuna quota impostata da te può modificarlo.

TasksMax arresta un ciclo di fork

TasksMax= indica il numero massimo di processi e thread che un'unità può contenere. I thread vengono conteggiati, quindi un servizio Java o Go richiede un margine maggiore di quanto suggerisca l'elenco dei processi. È la protezione meno costosa contro uno script che esegue fork in un ciclo, perché il fork fallisce all'interno dell'unità invece di esaurire gli ID di processo del sistema.

TasksMax=128

Quando un'unità raggiunge il limite, il kernel registra una riga con il nome del cgroup:

cgroup: fork rejected by pids controller in /system.slice/myapp.service

Il programma segnala in genere fork: retry: Resource temporarily unavailable. Verifica quale valore applica il gestore per impostazione predefinita con systemctl show -p DefaultTasksMax.

Limitare un job occasionale con systemd-run

Non serve un unit file per usare queste funzionalità. systemd-run crea un'unità temporanea attorno a un singolo comando.

sudo systemd-run --scope -p MemoryMax=1G -p MemorySwapMax=0 -p CPUQuota=50% -p TasksMax=64 ./import-data.sh

--scope esegue il comando nel terminale dopo aver visualizzato Running scope as unit: run-r7c1a....scope. L'output resta sullo schermo e i limiti scompaiono quando il comando termina. Qualsiasi proprietà di systemd.resource-control funziona dopo -p.

Per un job di lunga durata, ometti --scope e assegnagli un nome. Il job viene quindi eseguito in background come servizio temporaneo e i log vengono scritti nel journal:

sudo systemd-run --unit=nightly-import -p MemoryMax=1G -p CPUWeight=20 ./import-data.sh
journalctl -u nightly-import -f

Le stesse opzioni funzionano con --user anche senza essere root. Tuttavia, il user manager dispone soltanto dei controller che gli sono stati delegati, quindi una proprietà può essere rifiutata. In tal caso, eseguilo con sudo. Quando un job diventa permanente, le impostazioni vengono trasferite senza modifiche in un'unità reale: consulta eseguire uno script come servizio e timer systemd.

La questione dello swap, con una risposta onesta

Lo swap modifica la modalità del guasto, ma non lo impedisce.

Senza swap, una perdita di memoria raggiunge il limite massimo e un processo termina entro pochi secondi. L’interruzione è evidente, breve e facile da analizzare successivamente nel journal. Con lo swap, il kernel scrive su disco le pagine anonime non utilizzate e guadagna tempo. Se il processo stava per stabilizzarsi, lo swap è utile. Se invece è fuori controllo, lo swap trasforma un’interruzione di cinque secondi in un blocco di venti minuti. Il blocco è peggiore, perché un processo terminato lascia comunque disponibile una shell funzionante, mentre un sistema in thrashing no.

swapon --show
free -h

Una soluzione pratica per un VPS di piccole dimensioni consiste nel mantenere un file di swap moderato per le pagine allocate una sola volta e mai più utilizzate, e impostare MemorySwapMax=0 sulle unità che si è disposti a perdere. I servizi importanti conservano l’accesso allo swap. Quelli imprevedibili raggiungono rapidamente il limite e la policy di riavvio accanto al relativo limite li riporta in esecuzione.

Ridurre vm.swappiness è un intervento poco efficace, ed è utile capire perché. Modifica soltanto l’equilibrio tra l’espulsione della page cache e lo swap delle pagine anonime; in entrambi i casi, in seguito sarà necessaria una lettura dal disco. Cambia quali pagine entrano in thrashing, non il fatto che il sistema ci entri.

Un demone OOM preventivo termina i processi prima del blocco

Il kernel attende che il reclaim fallisca completamente. Su una VPS di piccole dimensioni, questa attesa coincide esattamente con l'intervallo in cui si perde l'accesso alla macchina. Due demoni in userspace riducono questo intervallo monitorando direttamente la memoria e terminando prima i processi.

earlyoom controlla la memoria disponibile e lo swap libero fino a dieci volte al secondo. Termina il processo con il valore oom_score più alto solo quando entrambi scendono sotto le rispettive soglie. Su una macchina senza swap, decide soltanto la soglia della memoria.

sudo apt install earlyoom
systemctl status earlyoom

Il pacchetto Debian e Ubuntu avvia il servizio durante l'installazione. Le relative opzioni si trovano in /etc/default/earlyoom:

EARLYOOM_ARGS="-m 5,2 -s 5,2 --avoid ^(sshd|systemd)$ --prefer ^(node|python3)$"

-m PERCENT imposta il minimo di memoria disponibile e -s PERCENT il minimo di swap libero, entrambi al 10 percento per impostazione predefinita. Il secondo numero di ogni coppia indica la soglia per SIGKILL: earlyoom invia SIGTERM quando memoria e swap scendono entrambi sotto i primi valori, quindi invia SIGKILL quando entrambi scendono sotto i secondi valori, che per impostazione predefinita sono la metà dei primi. Lascia i pattern --avoid e --prefer senza virgolette e senza spazi, perché systemd passa letteralmente i caratteri delle virgolette e un pattern tra virgolette non trova mai corrispondenze. Applica una modifica con sudo systemctl restart earlyoom e leggi journalctl -u earlyoom per vedere quale processo è stato terminato e quanta memoria stava utilizzando.

systemd-oomd è l'altra opzione. La relativa pagina del manuale lo descrive come "un servizio di sistema che usa cgroups-v2 e le pressure stall information (PSI) per monitorare il sistema e adottare misure correttive prima che si verifichi un OOM nello spazio del kernel". Agisce su interi cgroup anziché su singoli processi. Termina quindi una unità, non un processo figlio isolato. Le unità devono abilitare esplicitamente questa funzione con ManagedOOMMemoryPressure=kill o ManagedOOMSwap=kill. Le soglie si trovano in /etc/systemd/oomd.conf.

systemctl status systemd-oomd
oomctl

oomctl mostra ciò che sta monitorando in quel momento. Su un'immagine server spesso non mostra nulla, perché l'impostazione deve essere abilitata per ogni unità. Scegli un solo demone e usa quello. Eseguire entrambi significa lasciare che due componenti competano nella scelta della vittima. Diventa quindi più difficile ricostruire il motivo di ogni terminazione.

Quale unit era responsabile?

Inizia dal kernel, perché registra ogni kill che esegue.

journalctl -k --grep "Killed process" --since "2 hours ago"

Un kill eseguito dall’OOM killer globale ha questo aspetto:

Out of memory: Killed process 4127 (node) total-vm:2731084kB, anon-rss:1874232kB, file-rss:0kB, shmem-rss:0kB, UID:1000 pgtables:4212kB oom_score_adj:0

anon-rss è la memoria anonima, ad esempio l’heap, che il processo teneva in RAM quando è terminato: qui circa 1.8 GB. Le mappature di file residenti e la memoria condivisa vengono conteggiate separatamente, rispettivamente come file-rss e shmem-rss. Leggi con cautela il nome tra parentesi. È il processo che il kernel ha scelto come vittima. Il kernel sceglie il processo più grande, che non è sempre quello che ha causato l’esaurimento della memoria.

Un kill causato da un limite cgroup ha un prefisso diverso. Il report stampato sopra indica il cgroup che ha raggiunto il proprio limite:

Memory cgroup out of memory: Killed process 8811 (python3) total-vm:1044320kB, anon-rss:769112kB, file-rss:0kB, shmem-rss:0kB, UID:998 pgtables:1720kB oom_score_adj:0

Quel prefisso fornisce già gran parte della diagnosi. Memory cgroup out of memory significa che una unit ha raggiunto il MemoryMax= che le hai assegnato e che il resto del sistema funzionava normalmente. Un semplice Out of memory significa che la memoria della macchina era esaurita. In questo caso i limiti mancavano oppure erano troppo elevati nel loro insieme.

Poi chiedi a systemd che cosa ha rilevato:

systemctl status myapp.service
journalctl -u myapp.service -n 50
myapp.service: A process of this unit has been killed by the OOM killer.
myapp.service: Main process exited, code=killed, status=9/KILL
myapp.service: Failed with result 'oom-kill'.

systemctl status indica la stessa cosa in una sola riga, come Active: failed (Result: oom-kill).

I contatori del cgroup sono la terza fonte di informazioni e l’unica che registra il throttling, che non produce mai una riga di log:

cat /sys/fs/cgroup/system.slice/myapp.service/memory.events
cat /sys/fs/cgroup/system.slice/myapp.service/memory.peak
low 0
high 4213
max 118
oom 12
oom_kill 12

high conta quante volte la unit ha superato MemoryHigh= ed è stata sottoposta a throttling. max conta quante volte ha raggiunto il limite rigido e oom_kill conta i processi terminati. Un valore elevato di high insieme a oom_kill 0 indica il caso silenzioso descritto prima: dalla creazione del cgroup, la unit è stata sottoposta ripetutamente a throttling senza che si verificasse alcun kill, quindi systemd non ha registrato errori. Il contatore cresce soltanto. Leggilo due volte a distanza di un minuto: un high ancora in aumento indica che il throttling è in corso. memory.peak (Linux 5.19 e versioni successive) contiene il valore massimo raggiunto dal consumo del cgroup. È il numero da usare per dimensionare MemoryMax=. Entrambi i file vengono azzerati quando la unit viene riavviata, perché systemd ricrea il cgroup.

Alla base di tutto c’è un prerequisito. Se /var/log/journal non esiste, il journal risiede in RAM e ogni riga viene persa dopo il riavvio necessario per recuperare il sistema.

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
journalctl --list-boots

Se journalctl --list-boots mostra più di un solo boot corrente, la cronologia viene conservata. In questo caso journalctl -k -b -1 può mostrare i messaggi del kernel relativi al boot che si è interrotto.

Un punto di partenza per un piccolo VPS

Su un piano da 2 GB, lascia da 300 a 400 MB al kernel e alla page cache. Non impostare limiti la cui somma raggiunge tutti i 2 GB, perché ogni unità può raggiungere il picco nello stesso momento. Assegna la quota maggiore al servizio più importante, quindi limita tutto ciò che è secondario attorno a esso.

[Service]
MemoryHigh=256M
MemoryMax=384M
MemorySwapMax=0
CPUWeight=20
TasksMax=64
Restart=on-failure
RestartSec=5s

Mantenere una modalità di accesso disponibile richiede un'impostazione aggiuntiva. OOMScoreAdjust=-500 in un drop-in per ssh.service rende molto meno probabile che l'OOM killer globale scelga il demone SSH come processo da terminare. Questa può essere la differenza tra correggere il server e riavviarlo dal pannello di controllo. Modifica soltanto il processo scelto dal kernel come vittima. Non riduce la durata del blocco.

I container vengono eseguiti in cgroup propri, creati dal runtime dei container anziché dai file delle unità. Per questo, un limite su docker.service non diventa un limite per un singolo container. Gli equivalenti per container di MemoryMax= e CPUQuota= sono descritti in impostare i limiti di memoria e CPU in Docker Compose.

FAQ

Perché il mio VPS si è bloccato invece di terminare il processo fuori controllo?

Perché il kernel valuta l'avanzamento in base al fatto che il reclaim restituisca pagine, non al tempo necessario. Quando la memoria è insufficiente, espelle la page cache, comprese le pagine eseguibili dei programmi in esecuzione, quindi le rilegge alla successiva istruzione. Tutto resta in attesa dello storage e nessuna allocazione risulta tecnicamente fallita, quindi l'OOM killer non viene mai chiamato. Controllare /proc/pressure/memory mentre il problema è in corso: un valore full avg10 superiore a 40 indica che, per oltre il 40% degli ultimi dieci secondi, ogni attività non inattiva è rimasta bloccata contemporaneamente in attesa della memoria. Un demone in userspace come earlyoom termina il processo prima che il sistema raggiunga questo stato.

Qual è la differenza tra MemoryHigh e MemoryMax?

MemoryHigh= è un limite morbido che applica il throttling. Il kernel esegue il reclaim in modo aggressivo sull'unità e rallenta le allocazioni, ma l'utilizzo può superare il valore e nessun processo viene terminato. MemoryMax= è un limite rigido: un'allocazione che non può essere soddisfatta entro questo limite richiama l'OOM killer all'interno del cgroup dell'unità, quindi viene terminato il processo che ha causato il problema, invece del processo più grande dell'intero sistema. Impostare MemoryHigh= al di sotto di MemoryMax= e considerare la differenza tra i due valori come una zona di avviso.

Come posso individuare il servizio colpito dall'OOM killer?

Eseguire journalctl -k --grep "Killed process" --since "2 hours ago". Una riga che inizia con Memory cgroup out of memory indica che un'unità ha raggiunto il proprio MemoryMax=, mentre un semplice Out of memory indica che la memoria dell'intero sistema è terminata. Eseguire quindi journalctl -u <unit> -n 50 e cercare Failed with result 'oom-kill'. Se /var/log/journal non esiste sul server, il journal era mantenuto in RAM e le informazioni sono andate perse con il riavvio; creare quindi quella directory prima del prossimo incidente.

Devo aggiungere la swap a un VPS di piccole dimensioni?

Un file di swap di piccole dimensioni è utile per le pagine fredde, allocate una sola volta e mai più utilizzate. Non aiuta con un processo fuori controllo: ritarda la terminazione e sostituisce una breve interruzione con un blocco prolungato, durante il quale non è possibile accedere al sistema per risolvere il problema. Mantenere la swap su dimensioni moderate e impostare MemorySwapMax=0 sulle unità che si è disposti a perdere, in modo che raggiungano rapidamente il limite e, con Restart=on-failure impostato, si riavviino autonomamente mentre i servizi importanti conservano la propria swap.

Posso limitare un comando senza scrivere un file di unità?

Sì. sudo systemd-run --scope -p MemoryMax=1G -p CPUQuota=50% ./script.sh esegue il comando nel terminale all'interno di uno scope temporaneo con questi limiti, che scompaiono quando il comando termina. Tutte le proprietà di systemd.resource-control sono disponibili dopo -p, quindi anche MemorySwapMax=, TasksMax= e CPUWeight= funzionano in questo contesto. Rimuovere --scope e aggiungere --unit=name per eseguire il processo in background registrandone l'output nel journal.