Frammentazione della memoria Linux


20

C'è un modo per rilevare la frammentazione della memoria su Linux? Questo perché su alcuni server di lunga durata ho notato un peggioramento delle prestazioni e solo dopo il riavvio del processo vedo prestazioni migliori. L'ho notato di più quando si utilizzava il supporto di pagine enormi per Linux - le pagine enormi in Linux sono più inclini alla frammentazione?

Ho guardato in particolare / proc / buddyinfo. Voglio sapere se ci sono modi migliori (non solo i comandi CLI in sé, qualsiasi programma o background teorico farebbero) per esaminarlo.


Non sto guardando solo soluzioni rapide da riga di comando, lo farà anche qualsiasi programma / teoria semplice. Quindi, non ho chiesto a serverfault.
Raghu,

1
Non capisco qui un punto. Per quanto ho capito, la frammentazione della memoria deve portare alla mancanza di memoria e di conseguenza a errori di allocazione della memoria. Comunque stai chiedendo del degrado delle prestazioni. È perché hai un sacco di memoria scambiata su disco? E se sì, cosa dia vmstatnel campo so?

@skwllsp - Modificata la mia risposta per essere più specifico.
Tim Post

@Raghu - Non mi aspetto che la maggior parte degli amministratori di sistema modifichi il codice del kernel per far sì che la gestione della memoria si comporti in modo diverso, tuttavia gli amministratori Linux esperti dovrebbero conoscere almeno una panoramica di come Linux gestisce la memoria. Questa domanda è davvero in linea. Ho votato per migrarlo semplicemente perché non posso suggerire (nella mia risposta) il codice che risponde alla tua domanda. Leggere da / proc o usare vmstatè un'esperienza utente comune. Se stavi scrivendo un programma per fare lo stesso, sarebbe diverso. Se intendi utilizzare bash per raccogliere queste informazioni, modifica la tua domanda, non verrà chiusa :)
Tim Post

@Tim - Come ho suggerito non sono solo i comandi bash / cli che volevo sapere, avevo bisogno delle informazioni per aiutarmi nella mia procedura di benchmarking (per analizzare i risultati, non per eseguirli).
Raghu,

Risposte:


12

Sto rispondendo al tag . La mia risposta è specifica solo per Linux .

Sì, le pagine enormi sono più soggette alla frammentazione. Ci sono due viste della memoria, quella che il tuo processo ottiene (virtuale) e quella che il kernel gestisce (reale). Più una pagina è grande, più sarà difficile raggruppare (e mantenerlo con) i suoi vicini, specialmente quando il tuo servizio è in esecuzione su un sistema che deve supportare anche altri che, per impostazione predefinita, allocano e scrivono su molta più memoria di loro finiscono per usare.

La mappatura del kernel degli indirizzi (reali) concessi è privata. C'è un ottimo motivo per cui userspace li vede mentre il kernel li presenta, perché il kernel deve essere in grado di sovraccaricare senza confondere lo spazio utente. Il tuo processo ottiene uno spazio di indirizzi "Disneyfied" piacevole e contiguo in cui lavorare, ignaro di ciò che il kernel sta effettivamente facendo con quel ricordo dietro le quinte.

Il motivo per cui si notano prestazioni degradate su server a esecuzione prolungata è molto probabilmente dovuto al fatto che i blocchi allocati che non sono stati esplicitamente bloccati (ad es. mlock()/ mlockall()O posix_madvise()) e che non sono stati modificati da un po 'di tempo sono stati pagati , il che significa che il servizio scivola su disco quando deve leggere loro. La modifica di questo comportamento rende il tuo processo un cattivo vicinato , motivo per cui molte persone collocano il loro RDBMS su un server completamente diverso da web / php / python / ruby ​​/ qualunque cosa. L'unico modo per risolverlo, in modo sano, è ridurre la concorrenza per blocchi contigui.

La frammentazione è davvero evidente (nella maggior parte dei casi) quando la pagina A è in memoria e la pagina B è passata allo scambio. Naturalmente, riavviare il servizio sembrerebbe "curare" questo, ma solo perché il kernel non ha ancora avuto l'opportunità di eliminare il processo "(ora) blocchi appena allocati entro i limiti del suo rapporto di sovraccarico.

In effetti, il riavvio (diciamo) di 'apache' con un carico elevato probabilmente invierà blocchi di proprietà di altri servizi direttamente sul disco. Quindi sì, 'apache' migliorerebbe per un breve periodo, ma 'mysql' potrebbe soffrire .. almeno fino a quando il kernel non li farà soffrire ugualmente quando c'è semplicemente una mancanza di memoria fisica ampia.

Aggiungi più memoria o dividi i malloc()consumatori esigenti :) Non è solo la frammentazione che devi guardare.

Prova vmstata ottenere una panoramica di ciò che viene effettivamente archiviato dove.


Grazie per la risposta. Stavo usando enormi pagine (dimensioni = 2048 KB ciascuna) per mysql - pool di buffer innodb - per vedere quanto costa (usando sysbench). Inizialmente quando il tempo di attività del processo (e persino il tempo di attività del sistema) era basso, stava dando ottimi risultati. Tuttavia, le sue prestazioni hanno iniziato a peggiorare su diverse corse. Per quanto riguarda la pagina che hai citato, ho sicuramente notato un'alta attività di VM, ma ho presunto che potrebbe essere stato a causa del benchmark e del flushing dei log innodb (attività vm più alta con pagine enormi che senza). Ho anche impostato vm.swappiness su 1. Non ho potuto notare alcun cambiamento drastico.
Raghu,

Secondo il fine manuale , "Le pagine enormi non possono essere scambiate sotto pressione della memoria". Penso che questa sia una buona risposta nella memoria standard w / r / t ma non per hugepages.
Dan Pritts,

5

nocciolo

Per ottenere l'indice di frammentazione corrente utilizzare:

sudo cat /sys/kernel/debug/extfrag/extfrag_index

Per deframmentare la memoria del kernel prova a eseguire:

sysctl vm.compact_memory=1  

Inoltre, prova a disattivare le pagine trasparenti enormi (ovvero THP) e / o disabilita lo scambio (o la riduzione swappiness).

Spazio utente

Per ridurre la frammentazione dello spazio utente potresti voler provare diversi allocatori, ad es. jemalloc(Ha grandi capacità di introspezione , che ti daranno una visione interna della frammentazione interna degli allocatori).

È possibile passare a malloc personalizzato ricompilando il programma con esso o semplicemente eseguendo il programma con LD_PRELOAD: LD_PRELOAD=${JEMALLOC_PATH}/lib/libjemalloc.so.1 app (attenzione alle interazioni tra THP e allocatori di memoria )

Sebbene, leggermente non correlato alla frammentazione della memoria (ma connesso alla compattazione / migrazione della memoria), probabilmente si desidera eseguire più istanze del servizio, una per ciascun nodo NUMA e collegarle utilizzando numactl.


1
Perché pensi che disabilitare lo swap potrebbe aiutare? A me sembra più probabile che la disabilitazione dello swap danneggi ancora di più.
Kasperd,

1
Poiché non ci sono abbastanza informazioni nel post originale, forse il processo sta perdendo e inizia a scambiare. Inoltre, non vedo motivi legittimi per l'utilizzo dello swap praticamente su qualsiasi sistema di produzione (mb solo per workstation condivise per studenti).
SaveTheRbtz il

2
Avere abbastanza spazio di swap migliorerà le prestazioni. I problemi di prestazioni che potresti avere se lo spazio di swap è insufficiente è un motivo sufficiente per abilitare lo swap.
Kasperd,

1
@SaveTheRbtz Un buon motivo per utilizzare lo swap su un sistema di produzione è che offre al sistema più opzioni che utilizzerà solo se ritiene che siano utili. Inoltre, consente di espellere le pagine modificate che non sono state accedute per ore (e che potrebbero non essere mai accessibili) dalla preziosa memoria fisica. Infine, consente al sistema di gestire in modo sicuro i casi in cui è riservata molta più memoria di quella utilizzata.
David Schwartz,

2
"solo se ritiene che siano vantaggiosi" - ciò aggiunge ulteriore euristica e rende il sistema meno prevedibile. Anche gli algoritmi di sostituzione delle pagine (usati in swap e anonimi mmap) sono implementati in modo diverso su kernel diversi (es. Linux vs FreeBSD), o anche versioni diverse dello stesso sistema operativo (2.6.32 vs 3.2 vs 3.10) .. "consente pagine modificate [. ..] da espellere dalla [...] memoria fisica "- che nasconderà le perdite di memoria. "gestisci i casi in cui è riservata molta più memoria di quella usata" - il sistema lento è molto peggio del sistema inattivo, quindi "sano" è discutibile.
SaveTheRbtz il

4

L'uso di pagine enormi non dovrebbe causare ulteriore frammentazione della memoria su Linux; Il supporto di Linux per pagine enormi è solo per la memoria condivisa (tramite shmget o mmap) e qualsiasi pagina enorme utilizzata deve essere specificatamente richiesta e preallocata da un amministratore di sistema. Una volta in memoria, vengono bloccati lì e non vengono scambiati. La sfida di scambiare pagine enormi di fronte alla frammentazione della memoria è esattamente il motivo per cui rimangono bloccate in memoria (quando alloca una pagina enorme da 2 MB, il kernel deve trovare 512 pagine 4KB contigue libere, che potrebbero anche non esistere).

Documentazione Linux su pagine enormi: http://lwn.net/Articles/375098/

Esiste una circostanza in cui la frammentazione della memoria potrebbe rallentare l'allocazione di pagine enormi (ma non dove pagine enormi causano la frammentazione della memoria), ed è se il sistema è configurato per aumentare il pool di pagine enormi se richiesto da un'applicazione. Se / proc / sys / vm / nr_overcommit_hugepages è maggiore di / proc / sys / vm / nr_hugepages, ciò potrebbe accadere.


In effetti, e dovrebbe generalmente aiutare le prestazioni perché eviterà i mancati TLB (vedere l'articolo collegato per una spiegazione).
Dan Pritts,

0

C'è /proc/buddyinfoche è molto utile. È più utile con un bel formato di output, come può fare questo script Python:

https://gist.github.com/labeneator/9574294

Per pagine enormi vuoi frammenti gratuiti nella dimensione 2097152 (2 MiB) o più grande. Per pagine enormi trasparenti si compatterà automaticamente quando viene richiesto un kernel, ma se vuoi vedere quante ne puoi ottenere, allora come root esegui:

echo 1 | sudo tee /proc/sys/vm/compact_memory

Inoltre sì, pagine enormi causano grossi problemi alla frammentazione. O non puoi ottenere pagine enormi, o la loro presenza fa sì che il kernel passi molto tempo extra nel tentativo di ottenerne alcune.

Ho una soluzione che funziona per me. Lo uso su un paio di server e sul mio laptop. Funziona alla grande per macchine virtuali.

Aggiungi l' kernelcore=4Gopzione alla tua riga di comando del kernel Linux. Sul mio server uso 8G. Fai attenzione al numero, perché impedirà al tuo kernel di allocare qualsiasi cosa al di fuori di quella memoria. I server che necessitano di molti buffer socket o che scrivono su disco stream su centinaia di unità non gradiranno essere limitati in questo modo. Qualsiasi allocazione di memoria che deve essere "bloccata" per slab o DMA appartiene a questa categoria.

Tutta la tua altra memoria diventa quindi "mobile", il che significa che può essere compattata in bei pezzi per un'enorme allocazione della pagina. Ora enormi pagine trasparenti possono davvero decollare e funzionare come dovrebbero. Ogni volta che il kernel ha bisogno di più pagine 2M, può semplicemente rimappare le pagine 4K da qualche altra parte.

E non sono del tutto sicuro di come interagisca con l'IO diretto a zero copie. La memoria nella "zona mobile" non dovrebbe essere bloccata, ma una richiesta IO diretta farebbe esattamente questo per DMA. Potrebbe copiarlo. Potrebbe comunque bloccarlo nella zona mobile. In entrambi i casi, probabilmente non è esattamente quello che volevi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.