sql >> Databáze >  >> NoSQL >> HBase

Ladění Java Garbage Collection pro HBase

Tento příspěvek hosta od architekta výkonu Intel Java Erica Kaczmareka (původně zveřejněný zde) se zabývá tím, jak vyladit sběr odpadu Java (GC) pro Apache HBase se zaměřením na 100% čtení YCSB.

Apache HBase je open source projekt Apache nabízející úložiště dat NoSQL. HBase se často používá společně s HDFS a je široce používán po celém světě. Mezi známé uživatele patří Facebook, Twitter, Yahoo a další. Z pohledu vývojáře je HBase „distribuovaná, verzovaná, nerelační databáze modelovaná podle Bigtable společnosti Google, distribuovaného úložného systému pro strukturovaná data“. HBase si snadno poradí s velmi vysokou propustností buď škálováním (tj. nasazením na větším serveru) nebo škálováním (tj. nasazením na více serverech).

Z pohledu uživatele velmi záleží na latenci každého jednotlivého dotazu. Když pracujeme s uživateli na testování, ladění a optimalizaci pracovních zátěží HBase, setkáváme se nyní se značným počtem lidí, kteří skutečně chtějí 99. percentil operační latence. To znamená zpáteční cestu, od požadavku klienta po odpověď zpět klientovi, to vše během 100 milisekund.

Ke kolísání latence přispívá několik faktorů. Jedním z nejničivějších a nejnepředvídatelnějších narušitelů latence jsou pauzy Java Virtual Machine (JVM) „zastavte svět“ kvůli sběru odpadu (vyčištění paměti).

Abychom to vyřešili, vyzkoušeli jsme několik experimentů pomocí kolektoru Oracle jdk7u21 a jdk7u60 G1 (Garbage 1st). Serverový systém, který jsme použili, byl založen na procesorech Intel Xeon Ivy-bridge EP s Hyper-threading (40 logických procesorů). Měl 256 GB DDR3-1600 RAM a tři 400GB SSD jako místní úložiště. Tato malá sestava obsahovala jeden master a jeden slave, konfigurované na jednom uzlu s odpovídajícím přizpůsobením zátěže. Použili jsme HBase verze 0.98.1 a lokální souborový systém pro úložiště HFile. Testovací tabulka HBase byla nakonfigurována jako 400 milionů řádků a měla velikost 580 GB. Použili jsme výchozí strategii haldy HBase:40 % pro blockcache, 40 % pro memstore. YCSB byl použit k řízení 600 pracovních vláken odesílajících požadavky na server HBase.

Následující grafy ukazují, že jdk7u21 běží na 100 % čtení po dobu jedné hodiny pomocí -XX:+UseG1GC -Xms100g -Xmx100g -XX:MaxGCPauseMillis=100 . Zadali jsme sběrač odpadu, který se má použít, velikost haldy a požadovaný čas pauzy pro sběr odpadu (GC) „zastavte svět“.

Obrázek 1:Divoké výkyvy v GC Pause time

V tomto případě jsme dostali divoce houpající se GC pauzy. Pauza GC měla rozsah od 7 milisekund do 5 celých sekund po počáteční špičce, která dosáhla až 17,5 sekundy.

Následující graf ukazuje další podrobnosti během ustáleného stavu:

Obrázek 2:Podrobnosti o pauze GC v ustáleném stavu

Obrázek 2 nám říká, že GC pauzy ve skutečnosti přicházejí ve třech různých skupinách:(1) mezi 1 až 1,5 sekundy; (2) mezi 0,007 sekundy až 0,5 sekundy; (3) špičky mezi 1,5 sekundy až 5 sekundami. Bylo to velmi zvláštní, takže jsme otestovali poslední vydanou verzi jdk7u60, abychom zjistili, zda se data budou lišit:

Provedli jsme stejné testy 100% čtení s přesně stejnými parametry JVM:-XX:+UseG1GC -Xms100g -Xmx100g -XX:MaxGCPauseMillis=100 .

Obrázek 3:Výrazně lepší zpracování časových špiček pauzy

Jdk7u60 výrazně zlepšil schopnost G1 zvládat časové špičky pauzy po počátečním špičce během fáze usazování. Jdk7u60 vytvořil 1029 mladých a smíšených GC během jedné hodiny. GC probíhalo přibližně každé 3,5 sekundy. Jdk7u21 vytvořil 286 GC, přičemž každý GC se odehrál přibližně každých 12,6 sekund. Jdk7u60 dokázal zvládnout dobu pauzy mezi 0,302 až 1 sekundou bez větších výkyvů.

Obrázek 4 níže nám poskytuje bližší pohled na 150 GC pauz během ustáleného stavu:

Obrázek 4:Lepší, ale ne dost dobré

Během ustáleného stavu dokázal jdk7u60 udržet průměrnou dobu pauzy kolem 369 milisekund. Bylo to mnohem lepší než jdk7u21, ale stále nesplňovalo náš požadavek na 100 milisekund daný –Xx:MaxGCPauseMillis=100 .

Abychom zjistili, co dalšího bychom mohli udělat, abychom získali 100 milionů sekund pauzy, potřebovali jsme porozumět více o chování správy paměti JVM a G1 (Garbage First) garbage collector. Následující obrázky ukazují, jak G1 funguje na kolekci Young Gen.

Obrázek 5:Snímek z prezentace JavaOne z roku 2012 od Charlieho Hunta a Monicy Beckwith:„G1 Garbage Collector Performance Tuning“

Když se JVM spustí, na základě spouštěcích parametrů JVM požádá operační systém, aby alokoval velký kontinuální blok paměti pro hostování haldy JVM. Tento blok paměti je rozdělen JVM do oblastí.

Obrázek 6:Snímek z prezentace JavaOne z roku 2012 od Charlie Hunta a Monicy Beckwith:„G1 Garbage Collector Performance Tuning“

Jak ukazuje obrázek 6, každý objekt, který program Java alokuje pomocí Java API, se nejprve dostane do prostoru Eden v mladé generaci vlevo. Po chvíli se Eden zaplní a spustí se GC mladé generace. Objekty, na které se stále odkazuje (tj. „živé“), jsou zkopírovány do prostoru Survivor. Když předměty přežijí několik GC v mladé generaci, povýší se do prostoru staré generace.

Když dojde k Young GC, vlákna aplikace Java se zastaví, aby bylo možné bezpečně označit a zkopírovat živé objekty. Tyto zastávky jsou notoricky známé pauzy GC „stop-the-world“, díky nimž aplikace nereagují, dokud pauzy neskončí.

Obrázek 7:Snímek z prezentace JavaOne z roku 2012 od Charlie Hunta a Monicy Beckwith:„G1 Garbage Collector Performance Tuning“

Stará generace také může být přeplněná. Na určité úrovni – kontrolované -XX:InitiatingHeapOccupancyPercent=? kde výchozí hodnota je 45 % celkové haldy – spustí se smíšená GC. Sbírá jak Young gen, tak Old gen. Smíšené pauzy GC jsou řízeny tím, jak dlouho trvá vyčištění Young genu, když dojde ke smíšené GC.

V G1 tedy vidíme, že pauzám GC „zastavte svět“ dominuje, jak rychle dokáže G1 označit a zkopírovat živé objekty z prostoru Eden. S ohledem na to budeme analyzovat, jak nám vzor alokace paměti HBase pomůže vyladit G1 GC, abychom dosáhli požadované pauzy 100 milisekund.

V HBase existují dvě struktury v paměti, které spotřebují většinu jeho hromady:BlockCache , ukládání bloků souborů HBase do mezipaměti pro operace čtení a ukládání nejnovějších aktualizací do mezipaměti Memstore.

Obrázek 8:V HBase spotřebují dvě struktury v paměti většinu jeho hromady.

Výchozí implementace BlockCache HBase je LruBlockCache , který jednoduše používá velké bajtové pole k hostování všech bloků HBase. Když jsou bloky „vyklizeny“, je odstraněn odkaz na objekt Java daného bloku, což umožňuje GC přemístit paměť.

Nové objekty tvořící LruBlockCache a Memstore jděte nejprve do prostoru Eden mladé generace. Pokud žijí dostatečně dlouho (tj. pokud nejsou vystěhováni z LruBlockCache nebo spláchnuty z Memstore), pak po několika mladých generacích GC pronikají do staré generace Java haldy. Když je volné místo staré generace menší než daný threshOld (InitiatingHeapOccupancyPercent pro začátek), smíšené GC nakopne a odstraní některé mrtvé předměty ve staré generaci, zkopíruje živé objekty z mladé generace a přepočítá Eden mladé generace a HeapOccupancyPercent u mladé generace . Nakonec, když HeapOccupancyPercent dosáhne určité úrovně, FULL GC se stane, což způsobí obrovské pauzy GC „zastavte svět“, aby vyčistily všechny mrtvé předměty uvnitř staré generace.

Po prostudování protokolu GC vytvořeného „-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy “, všimli jsme si HeapOccupancyPercent nikdy nenarostly natolik, aby vyvolaly úplnou GC během 100% čtení HBase. V GC pauzách, které jsme viděli, dominovaly pauzy Young gen „stop the world“ a postupem času narůstající referenční zpracování.

Po dokončení této analýzy jsme provedli tři skupiny změn ve výchozím nastavení G1 GC:

  1. Použijte -XX:+ParallelRefProcEnabled Když je tento příznak zapnutý, GC používá více vláken ke zpracování vzrůstajících referencí během Young a Mix GC. S tímto příznakem pro HBase se doba pro poznámky GC zkrátí o 75 % a celková doba pauzy GC se zkrátí o 30 %.
  2. Set -XX:-ResizePLAB and -XX:ParallelGCThreads=8+(logical processors-8)(5/8) Během sběru Young se používají místní alokační vyrovnávací paměti (PLAB) propagace. Používá se více vláken. Každé vlákno může potřebovat přidělit prostor pro kopírované objekty buď v Survivor nebo Old space. PLAB jsou vyžadovány, aby se zabránilo konkurenci vláken pro sdílené datové struktury, které spravují volnou paměť. Každé vlákno GC má jeden PLAB pro prostor přežití a jeden pro starý prostor. Rádi bychom přestali měnit velikost PLAB, abychom se vyhnuli velkým komunikačním nákladům mezi vlákny GC a také odchylkám během každého GC. Chtěli bychom opravit počet GC vláken tak, aby odpovídal velikosti vypočítané 8+ (logické procesory-8)( 5/8). Tento vzorec byl nedávno doporučen společností Oracle. S oběma nastaveními jsme schopni vidět plynulejší GC pauzy během běhu.
  3. Změňte -XX:G1NewSizePercent výchozí od 5 do 1 pro 100GB halduNa základě výstupu z -XX:+PrintGCDetails and -XX:+PrintAdaptiveSizePolicy , všimli jsme si, že důvodem, proč G1 nesplnila požadovaný čas pauzy 100 GC, byla doba, kterou zabralo zpracování Edenu. Jinými slovy, G1 trvalo během našich testů v průměru 369 milisekund, než vyprázdnilo 5 GB Edenu. Poté jsme změnili velikost Eden pomocí -XX:G1NewSizePercent=
    příznak z 5 na 1. Díky této změně jsme zaznamenali zkrácení doby pauzy GC na 100 milisekund.

Z tohoto experimentu jsme zjistili, že rychlost G1 při čištění Edenu je asi 1 GB za 100 milisekund nebo 10 GB za sekundu pro nastavení HBase, které jsme použili.

Na základě této rychlosti můžeme nastavit -XX:G1NewSizePercent=
takže velikost Edenu lze udržet kolem 1 GB. Například:

  • 32GB halda, -XX:G1NewSizePercent=3
  • 64GB halda, –XX:G1NewSizePercent=2
  • 100 GB a více, -XX:G1NewSizePercent=1
  • Takže naše poslední možnosti příkazového řádku pro HRegionserver jsou:
    • -XX:+UseG1GC
    • -Xms100g -Xmx100g (Velikost haldy použitá v našich testech)
    • -XX:MaxGCPauseMillis=100 (Požadovaná doba pauzy GC v testech)
    • XX:+ParallelRefProcEnabled
    • -XX:-ResizePLAB
    • -XX:ParallelGCThreads= 8+(40-8)(5/8)=28
    • -XX:G1NewSizePercent=1

Zde je graf doby pauzy GC pro spuštění operace 100% čtení po dobu 1 hodiny:

Obrázek 9:Nejvyšší počáteční usazování se snížily o více než polovinu.

V tomto grafu byly i nejvyšší počáteční usazovací špičky sníženy z 3,792 sekund na 1,684 sekund. Nejvíce počátečních špiček bylo méně než 1 sekunda. Po vyrovnání byl GC schopen udržet čas pauzy kolem 100 milisekund.

Níže uvedená tabulka porovnává běhy jdk7u60 s laděním a bez ladění v ustáleném stavu:

Obrázek 10:jdk7u60 běží s laděním i bez ladění v ustáleném stavu.

Jednoduché ladění GC, které jsme popsali výše, poskytuje ideální doby pauzy GC, přibližně 100 milisekund, s průměrem 106 milisekund a standardní odchylkou 7 milisekund.

Shrnutí

HBase je aplikace kritická z hlediska doby odezvy, která vyžaduje dobu pauzy GC, aby byla předvídatelná a spravovatelná. S Oracle jdk7u60, na základě informací GC hlášených -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintAdaptiveSizePolicy , jsme schopni vyladit dobu pauzy GC až na požadovaných 100 milisekund.

Eric Kaczmarek je architektem výkonu Java ve skupině softwarových řešení společnosti Intel. Vede úsilí společnosti Intel o aktivaci a optimalizaci rámců pro velká data (Hadoop, HBase, Spark, Cassandra) pro platformy Intel.

Software a pracovní zátěže používané při testech výkonu mohly být optimalizovány pro výkon pouze na mikroprocesorech Intel. Výkonnostní testy, jako jsou SYSmark a MobileMark, se měří pomocí specifických počítačových systémů, komponent, softwaru, operací a funkcí. Jakákoli změna kteréhokoli z těchto faktorů může způsobit, že se výsledky budou lišit. Měli byste si prostudovat další informace a testy výkonu, které vám pomohou plně vyhodnotit zamýšlené nákupy, včetně výkonu daného produktu v kombinaci s jinými produkty.

Čísla procesorů Intel nejsou měřítkem výkonu. Čísla procesorů odlišují funkce v rámci každé rodiny procesorů. Ne napříč různými rodinami procesorů. Přejděte na:http://www.intel.com/products/processor_number.

Copyright 2014 Intel Corp. Intel, logo Intel a Xeon jsou ochranné známky společnosti Intel Corporation v USA a/nebo dalších zemích.


  1. Problém s instalací ovladače PHP MongoDb na wamp

  2. Jak provést addToSet pomocí oficiálního ovladače Go?

  3. Jak agregovat podle data, když je v agregačním rámci uvedeno úplné časové razítko?

  4. Další vlastnosti ověření MongoDB jsonSchema