Përparësitë dhe disavantazhet e HugePages

Përparësitë dhe disavantazhet e HugePages

Përkthimi i artikullit është përgatitur për studentët e kursit «Administrator Linux».

Më parë kam folur për mënyrën se si të kontrolloni dhe aktivizoni përdorimin e HugePages në Linux.
Ky artikull do të jetë i dobishëm vetëm nëse keni realisht ndonjë vend për të përdorur HugePages. Kam takuar shumë njerëz që mashtrohen nga perspektiva se HugePages do të rrisin magjepshëm performancën. Megjithatë, hugepaging është një temë komplekse, dhe nëse përdoret keq, mund të ulet performanca.

Pjesa 1: kontrolloni nëse hugepages janë aktivizuar në Linux (originali këtu)

Problemi:
Duhet të kontrolloni nëse HugePages janë aktivizuar në sistemin tuaj.

Zgjidhja:
Është mjaft e thjeshtë:

cat /sys/kernel/mm/transparent_hugepage/enabled

Do të merrni diçka të tillë:

always [madvise] never

Do të shihni një listë opsionesh të disponueshme (always, madvise, never), ndërsa opsioni aktual aktiv është i zbuluar në kllapa (në parazgjedhje madvise).

madvise do të thotë se transparent hugepages janë aktivizuar vetëm për rajonet e memories që kërkojnë qartë hugepages me madvise(2).

always do të thotë se transparent hugepages janë gjithmonë të përfshira dhe për të gjitha proceset. Zakonisht, kjo e rrit performancën, por nëse keni një rast përdorimi ku shumë procese konsumojnë pak memorie, ngarkesa totale e memories mund të rritet ndjeshëm.

asnjëherë do të thotë se transparent hugepages nuk do të aktivizohen as edhe me një kërkesë përmes madvise. Për të mësuar më shumë, ju lutemi referojuni dokumentacion bërthamave Linux.

Si të ndryshoni vlerën e paracaktuar

Mundësia 1: Ndryshoni drejtpërdrejt sysfs (pas rinisjes, parameteri do të kthehet në vlerën e paracaktuar):

echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled

Variant 2: Ndryshoni vlerën e sistemit të paracaktuar duke rindërtuar bërthamën me një konfigurim të ndryshuar (kjo mundësi rekomandohet vetëm nëse po përdorni një bërthamë të personalizuar):

  • Për të vendosur always si parazgjedhje, përdorni:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Komentoni CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Për të vendosur madvise si parazgjedhje, përdorni:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Komentoni CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Pjesa 2: Avantazhet dhe disavantazhet e HugePages

Do të përpiqemi të shpjegojmë përfitimet, disavantazhet dhe gabimet e mundshme të përdorimit të Hugepages. Duke qenë se artikulli është teknologjikisht kompleks dhe pedant, ndoshta do të jetë i vështirë për t'u kuptuar nga ata që mashtrohen duke e konsideruar Hugepages si një panacee, do të sakrifikoj saktësinë për shkak të thjeshtësisë. Është e rëndësishme të kihet parasysh se shumë tema janë me të vërtetë të komplikuara dhe prandaj janë shumë të thjeshtuara.

Merrni parasysh se po flasim për sisteme x86 64-bit që punojnë në Linux, dhe se supozon që sistemi mbështet transparent hugepages (sepse nuk është një disavantazh që hugepages nuk zëvendësohen), ashtu siç ndodh në pothuajse çdo mjedis modern Linux.

Në lidhjet më poshtë do të bashkangjit më shumë përshkrim teknik.

Memoria virtuale

Nëse jeni një programues C++, e dini se objektet në kujtesë kanë adresa specifike (vlera e treguesit).

Megjithatë, këto adresa nuk përfaqësojnë domosdoshmërisht adresat fizike në memorie (adresat në RAM). Ato përfaqësojnë adresat në memorien virtuale. Procesori ka njësi të veçantë MMU (njësia e menaxhimit të memories), e cila ndihmon bërthamën të mapojë memorien virtuale me vendndodhjen fizike.

Ky qasje ka shumë përfitime, por më të rëndësishmit janë:

  • Performanca (për arsye të ndryshme);
  • Izolimi i programeve, domethënë asnjë program nuk mund të lexojë nga memoria e një programi tjetër.

Çfarë janë faqet?

Memoria virtuale është e ndarë në faqe. Secila faqe e veçantë tregon një memorie fizike të caktuar, mund të tregojë një zonë në memorien operative, ose mund të tregojë një adresë të caktuar për pajisje fizike, si për shembull kartën grafike.

Shumica e faqeve me të cilat keni të bëni tregojnë ose RAM-in, ose të zëvendësohen (swap), që do të thotë se ruhen në një hard disk ose SSD. Nukleusi menaxhon pozitat fizike të çdo faqeje. Nëse ka akses në një faqe të zëvendësuar, nukleusi ndalon rrjedhën që përpiqet të qaset në memorie, e lexon faqen nga hard disku/SSD në RAM dhe pastaj vazhdon ekzekutimin e rrjedhës.

Ky proces është i dukshëm për rrjedhën, do të thotë se ajo nuk domosdoshmërisht lexon drejtpërdrejt nga hard disku/SSD. Madhësia e faqeve normale është 4096 byte. Madhësia e Hugepages është 2 megabajt.

Blerja e asociativës së transfereve (TLB)

Kur një program i qaset një faqe memorjeje, procesori qendror duhet të dijë se nga cila faqe fizike të lexojë të dhënat (pra, të ketë një hartë virtuale adresash).

Në bërthamë ekziston një strukturë të dhënash (tabela e faqeve), e cila përmban të gjitha informatat për faqet që përdoren. Me këtë strukturë të dhënash, mund të përputhen adresat virtuale me adresat fizike.

Megjithatë, tabela e faqeve është mjaft e ndërlikuar dhe funksionon ngadalë, prandaj ne thjesht nuk mund të analizojmë çdo herë të gjithë strukturën e të dhënave kur ndonjë proces iu qaset memories.

Sidoqoftë, procesori ynë ka një TLB, i cili ruan përputhjen ndërmjet adresave virtuale dhe fizike. Kjo do të thotë se, ndonëse na nevojitet të analizojmë tabelën e faqeve gjatë përpjekjes së parë për qasje, të gjitha kërkesat e mëpasshme për faqe mund të përpunohen në TLB, duke siguruar një funksionim të shpejtë.

Duke qenë se është e implementuar si një pajisje fizike (e cila e bën atë fillimisht të shpejtë), kapaciteti i saj është i kufizuar. Prandaj, nëse dëshironi të qasni më shumë faqe, TLB nuk do të mund të ruajë përputhjen për të gjithë ato, duke bërë që programi juaj të funksionojë shumë më ngadalë.

Hugepages vijnë në ndihmë

Pra, çfarë mund të bëjmë për të shmangur mbushjen e TLB-së? (Ne supozojmë se programi ka ende nevojë për të njëjtin volum memorjeje).

Këtu shfaqen Hugepages. Në vend që 4096 bytes të kërkojnë vetëm një regjistrim në TLB, tani një regjistrim në TLB mund të tregojë për 2 megabajt kolosale. Le të supozojmë se TLB ka 512 regjistrime, këtu pa Hugepages mund të përputhim:

4096 b⋅512=2 MB

Ndërsa me to mund të përputhim:

2 MB⋅512=1 GB

Pikërisht për këtë arsye Hugepages janë të shkëlqyera. Ato mund të rrisin performancën pa u kërkuar shumë përpjekje. Por këtu ka disa sqarime të rëndësishme.

Ndërrimi i Hugepages

Bashkëpunimi automatik ndjek frekuencën e përdorimit të çdo faqeje të memories. Nëse ka mungesë fiziologjike të memories (RAM), bërthama do të transferojë faqet më pak të rëndësishme (më rrallë të përdorura) në hard disk, për të liruar një pjesë të RAM për faqet më të rëndësishme.
Në parim, e njëjta gjë vlen për Hugepages. Sidoqoftë, bërthama mund të ndërronte vetëm faqe të tëra, jo byte të veçanta.

Supozoni se kemi një program të tillë:

char* mymemory = malloc(2*1024*1024); // Ta marrim këtë si një Hugepage!
// Ta mbushim mymemory me të dhëna
// Të bëjmë shumë gjëra të tjera,
// që do të çojnë në ndërrimin e faqes mymemory
// ...
// Të kërkojmë qasje vetëm në byte-n e parë
putchar(mymemory[0]); 

Në këtë rast, bërthama do të duhet të lexojë plot 2 megabajt të informacionit nga disku i fortë/SSD vetëm në mënyrë që ju të lexoni një bajt. Sa për faqet standarde, nga disku i fortë/SSD duhet të lexoni vetëm 4096 bajt.

Prandaj, nëse hugepage zëvendësohet, leximi i saj ndodh më shpejt, vetëm nëse ju nevojitet qasja në të gjithë faqen. Kjo do të thotë që nëse po përpiqeni të qaseni rastësisht në pjesë të ndryshme të memories dhe thjesht lexoni disa kilobajtë, duhet të përdorni faqet standarde dhe të mos shqetësoheni për asgjë tjetër.

Nga ana tjetër, nëse ju nevojitet të aksesoni një pjesë të madhe të memories njëpasnjërisht, hugepages do të rrisin performancën tuaj. Megjithatë, duhet ta verifikoni këtë vetë (nuk në shembuj abstraktë) dhe të shihni se çfarë do të punojë më shpejt.

Alokimi në memorie

Nëse po shkruani në C, e dini që mund të kërkoni për sasi shumë të vogla (apo pothuajse aq të mëdha) të memories nga kupa duke përdorur malloc(). Supozoni se ju duhen 30 bajt memorie:

char* mymemory = malloc(30);

Një programues mund të mendojë se ju “po kërkoni” 30 byte memorje nga sistemi operativ dhe keni një tregues për ndonjë memorje virtuale. Por në të vërtetë malloc () — është thjesht një funksion C që thërret brenda funksioneve brk dhe sbrk për të kërkuar ose çliruar memorje nga sistemi operativ.

Megjithatë, kërkesa për më shumë dhe më shumë memorje për çdo alokim nuk është efikase; ka gjasa që ndonjë segment memorjeje të jetë çliruar tashmë (free()), dhe ne mund ta rishfrytëzojmë atë. malloc() implementon algoritme mjaft të komplikuara për rishfrytëzimin e memorjes së çliruar.

Dhe për ju, gjithçka ndodh pa u vënë re, kështu që pse duhet të shqetësoheni? Sepse thirrja free() nuk do të thotë se memorja kthehet domosdoshmërisht menjëherë në sistemin operativ.

Ekziston një koncept i tillë si fraktura e memorjes. Në raste ekstreme, ka segmente heaps ku përdoren vetëm disa byte, ndërsa gjithçka që ndodhet midis tyre është çliruar. (free()).

Vini rehatni se se shikoni se fragmetimi i memories është një temë jashtëzakonisht e ndërlikuar dhe madje ndryshimet e vogla në program mund të kenë një ndikim të konsiderueshëm mbi të. Në shumicën e rasteve, programet nuk shkaktojnë fragmentim të dukshëm të memories, por duhet të keni parasysh se nëse ka një problem me fragmentimin në ndonjë zonë të heap-it, hugepages mund ta përkeqësojnë situatën.

Përdorimi selektiv i hugepages

Pas leximit të artikullit, krijuat një ide se cilat pjesë të programit tuaj mund të përfitojnë nga përdorimi i hugepages dhe cilat jo. Pra, a duhet ta përfshini në tërësi hugepages?

Fatmirësisht, mund të përdorni madvise(), për të aktivizuar hugepaging vetëm për ato zona të memories ku do të jetë e dobishme.

Për të filluar, kontrolloni që hugepages të punojnë në modalitetin madvise(), duke përdorur udhëzues në fillim të artikullit.

Pastaj, përdorni madvise(), për të treguar bërthamës se ku saktësisht të përdorë hugepages.

#include <sys/mman.h>
// Аллоцируйте большое количество памяти, которую будете использовать
size_t size = 256*1024*1024;
char* mymemory = malloc(size);
// Просто включите hugepages…
madvise(mymemory, size, MADV_HUGEPAGE);
// … и задайте следующее
madvise(mymemory, size, MADV_HUGEPAGE | MADV_SEQUENTIAL)

Vini re se kjo metodë është thjesht një rekomandim për bërthamën për menaxhimin e memories. Kjo nuk do të thotë se bërthama automatikisht do të përdorë hugepages për memorjen e caktuar.

Konsultohuni me dokumentacionin (manpage) madvise, për të mësuar më shumë rreth menaxhimit të memories dhe madvise(), ky kjo temë ka një kurbë të mrekullueshme të të mësuarit. Prandaj, nëse keni ndërmend të kuptoni vërtet mirë këtë, përgatituni për të lexuar dhe testuar për disa javë, para se të prisni ndonjë rezultat pozitiv.

Çfarë të lexoni?

Keni një pyetje? Shkruani në komentet!

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster