Úvod
Některé konfigurační vlastnosti nalezené v Apache Hadoop mají přímý vliv na klienty, jako je Apache HBase. Jedna z těchto vlastností se nazývá „dfs.datanode.max.xcievers“ a patří do podprojektu HDFS. Definuje počet vláken na straně serveru a – do určité míry – soketů používaných pro datová připojení. Nastavení příliš nízkého čísla může způsobit problémy s růstem nebo zvýšením využití vašeho clusteru. Tento příspěvek vám pomůže pochopit, co se děje mezi klientem a serverem, a jak určit přiměřený počet pro tuto vlastnost.
Problém
Vzhledem k tomu, že HBase ukládá vše, co potřebuje, uvnitř HDFS, tvrdá horní hranice stanovená konfigurační vlastností „dfs.datanode.max.xcievers“ může vést k tomu, že HBase bude mít k dispozici příliš málo zdrojů, což se projeví jako IOExceptions na obou stranách připojení. Zde je příklad z mailing listu HBase [1], kde byly na straně RegionServeru původně protokolovány následující zprávy:
2008-11-11 19:55:52,451 INFO org.apache.hadoop.dfs.DFSClient: Výjimka v createBlockOutputStream java.io.IOException:Nelze číst ze streamu
2008-11-11 19:55:52,451 INFO org.apache.hadoop.dfs.DFSClient: Opuštění bloku blk_-5467014108-325863<508/325863 11 19:55:58,455 WARN org.apache.hadoop.dfs.DFSClient: Výjimka DataStreamer:java.io.IOException:Nelze vytvořit nový blok.
2008-11-11 19:55:58,455 WARN org.apache .hadoop.dfs.DFSClient:Chyba Obnovení pro blok blk_-5467014108758633036_595771 špatný datový uzel[0]
2008-11-11 19:55:58,482 vyžadováno FATALoregion opplayhache.FATAL region org.applayhache. . Vynucení vypnutí serveru
Porovnání s protokoly Hadoop DataNode odhalilo následující záznam:
CHYBA org.apache.hadoop.dfs.DataNode: DatanodeRegistration(10.10.10.53:50010,storageID=DS-1570581820-10.10.10.53-50010-1224117842339,infoPort=50075, ipcPort=50020):DataXceiver:java.io.IOException:xcie thevers2556 conception:xciexceiverscurrent
V tomto příkladu způsobila nízká hodnota „dfs.datanode.max.xcievers“ pro DataNodes vypnutí celého RegionServeru. To je opravdu špatná situace. Bohužel neexistuje žádné pevné pravidlo, které by vysvětlovalo, jak požadovaný limit vypočítat. Obvykle se doporučuje zvýšit číslo z výchozích 256 na něco jako 4096 (viz [1], [2], [3], [4] a [5] pro referenci). Toho se dosáhne přidáním této vlastnosti do souboru hdfs-site.xml všech DataNodes (všimněte si, že je napsána chybně):
Poznámka:Po provedení této změny v konfiguračním souboru budete muset restartovat své DataNodes.
To by mělo pomoci s výše uvedeným problémem, ale přesto byste možná chtěli vědět více o tom, jak to všechno funguje dohromady, a co HBase s těmito prostředky dělá. Budeme o tom diskutovat ve zbytku tohoto příspěvku. Než to však uděláme, musíme si ujasnit, proč nemůžete jednoduše nastavit toto číslo velmi vysoko, řekněme 64 kB, a skončit s tím.
Horní hranice má svůj důvod, a to dvojí:za prvé, vlákna potřebují svůj vlastní zásobník, což znamená, že zabírají paměť. Pro současné servery to ve výchozím nastavení znamená 1 MB na vlákno[6]. Jinými slovy, pokud využijete všech 4096 vláken DataXceiver, potřebujete k jejich uložení přibližně 4 GB haldy. Tím se omezí prostor, který jste přidělili pro memstore a blokové mezipaměti, stejně jako všechny ostatní pohyblivé části JVM. V nejhorším případě můžete narazit na OutOfMemoryException a proces RegionServer je toast. Tuto vlastnost chcete nastavit na přiměřeně vysoké číslo, ale ne příliš vysoké.
Zadruhé, když je aktivních těchto mnoho vláken, uvidíte, že se váš procesor stále více zatěžuje. Dojde k mnoha přepnutím kontextu, aby zvládly veškerou souběžnou práci, což odebere zdroje pro skutečnou práci. Stejně jako v případě obav o paměť chcete, aby počet vláken nerostl neomezeně, ale poskytoval rozumnou horní hranici – a k tomu slouží „dfs.datanode.max.xcievers“.
Podrobnosti o souborovém systému Hadoop
Na straně klienta poskytuje knihovna HDFS abstrakci nazvanou Path. Tato třída představuje soubor v souborovém systému podporovaném Hadoopem, reprezentovaný třídou FileSystem. Existuje několik konkrétních implementací abstraktní třídy FileSystem, jednou z nich je DistributedFileSytem, představující HDFS. Tato třída zase obaluje skutečnou třídu DFSClient, která zpracovává všechny interakce se vzdálenými servery, tj. NameNode a mnoha DataNodes.
Když klient, jako je HBase, otevře soubor, udělá to tak, že například zavolá metody open() nebo create() třídy FileSystem, zde jsou nejjednodušší inkarnace
public DFSInputStream open(String src) vyvolá IOException
veřejné FSDataOutputStream create(Path f) vyvolá IOException
Vrácená instance streamu potřebuje soket a vlákno na straně serveru, které se používají ke čtení a zápisu bloků dat. Jsou součástí smlouvy o výměně dat mezi klientem a serverem. Všimněte si, že mezi různými počítači se používají jiné protokoly založené na RPC, ale pro účely této diskuse je lze ignorovat.
Vrácená instance streamu je specializovaná třída DFSOutputStream nebo DFSInputStream, která zpracovává veškerou interakci s NameNode, aby zjistila, kde jsou kopie bloků, a datovou komunikaci na blok na DataNode.
Na straně serveru DataNode zabalí instanci DataXceiverServer, což je skutečná třída, která čte výše uvedený konfigurační klíč a také vyvolá výše uvedenou výjimku, když je překročen limit.
Když se DataNode spustí, vytvoří skupinu vláken a spustí zmíněnou instanci DataXceiverServer takto:
this.threadGroup =new ThreadGroup(“dataXceiverServer”);
this.dataXceiverServer =new Daemon( threadGroup,
new DataXceiverServer(ss, conf, this));
this.threadGroup.setDaemon(true); // automatické zničení při prázdném
Všimněte si, že vlákno DataXceiverServer už zabírá jedno místo ve skupině vláken. DataNode má také tuto interní třídu pro načtení počtu aktuálně aktivních vláken v této skupině:
/** Počet souběžných xceiverů na uzel. */
int getXceiverCount() {
return threadGroup ==null ? 0 :threadGroup.activeCount();
}
Čtení a zápis bloků iniciovaných klientem způsobí navázání spojení, které je zabaleno vláknem DataXceiverServer do instance DataXceiver. Během tohoto předání se vytvoří vlákno a zaregistruje se do výše uvedené skupiny vláken. Takže pro každou aktivní operaci čtení a zápisu je na straně serveru sledováno nové vlákno. Pokud počet vláken ve skupině překročí nakonfigurované maximum, je vyvolána zmíněná výjimka a zaznamenána do protokolů DataNode:
if (curXceiverCount> dataXceiverServer.maxXceiverCount) {
hodit novou IOException(“xceiverCount ” + curXceiverCount
+ ” překračuje limit souběžných xcievers ”
+ dataXceiverServer.maxXceiverCount);
}
Důsledky pro klienty
Nyní je otázkou, jak souvisí čtení a zápis klienta s vlákny na straně serveru. Než se však pustíme do podrobností, použijme informace o ladění, které třída DataXceiver zaznamená, když je vytvořena a uzavřena
LOG.debug(“Počet aktivních připojení je:” + datanode.getXceiverCount());
…
LOG.debug(datanode.dnRegistration + “:Počet aktivních připojení je:” + datanode.getXceiverCount());
a během spuštění HBase sledovat, co je přihlášeno na DataNode. Pro jednoduchost se to děje na pseudo distribuovaném nastavení s jedinou instancí DataNode a RegionServer. Následující ukazuje horní část stavové stránky RegionServeru.
Důležitá část je v sekci „Metrics“, kde je napsáno „storefiles=22“. Takže za předpokladu, že HBase má alespoň tolik souborů ke zpracování, plus nějaké další soubory pro záznam napřed, měli bychom vidět výše uvedenou zprávu protokolů, že máme alespoň 22 „aktivních připojení“. Spusťte HBase a zkontrolujte soubory protokolu DataNode a RegionServer:
Příkazový řádek:
$ bin/start-hbase.sh
…
Protokol datového uzlu:
2012-03-05 13:01:35,309 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Počet aktivních připojení je:1
2012-03-05 13:01:35,315 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS 1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Počet aktivních připojení je:2
12/03/05 13:01:35 StemoremLimitlus3globalemserver6 globalMemStoreLimitLowMark=347,1m, maxHeap=991,7m
12/03/05 13:01:39 INFO http.HttpServer:Port vrácený webServer.getConnectors()[0].getLocalPort() před open() je -1 . Otevření posluchače na 60030
2012-03-05 13:01:40,003 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:1
12/03/05 13:01:40 INFO regionserver.HRegionServer:Přijatý požadavek na otevření regionu:-ROOT-,,0.70236052
2012-03-05 13:01:40,882 DEBUG org.apache.hadoop.hdfs.server.datadenode.Data :Počet aktivních připojení je:3
2012-03-05 13:01:40,884 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID36DS-10 -10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Počet aktivních připojení je:4
2012-03-05 13:01:40,888 DEBUG org.aphached.hado datanode.DataNode:Počet aktivních připojení je:3
…
12/03/05 13:01:40 INFO regionserver.HRegion:Onlined -ROOT-,,0,70236052; next sequenceid=63083
2012-03-05 13:01:40,982 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:3
2012-03-05 13 :01:40,983 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště=DS-1423642448-10.0.0.64-522355pc=0525225570pc=0252355pc=0077223225570 Počet aktivních připojení je:4
…
12/03/05 13:01:41 INFO regionserver.HRegionServer:Přijatý požadavek na otevření regionu:.META.,,1.1028785192
2012-03 -05 13:01:41,026 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:3
2012-03-05 13:01:41,027 DEBUG org.apache.hadoop. hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, info
12/03/05 13:01:41 INFO regionserver.HRregion:Onlined .META.,,1.1028785192; next sequenceid=63082
2012-03-05 13:01:41,109 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:3
2012-03-05 13 :01:41,114 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:4
2012-03-05 13:01:41,117 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:Počet aktivních připojení je:5
12/03/05 13:01:41 INFO regionserver.HRegionServer:Přijat požadavek na otevření 16 regionů
12/03/05 13 :01:41 INFO regionserver.HRegionServer:Přijatý požadavek na otevření regionu:usertable,,1330944810191.62a312d67981c86c42b6bc02e6ec7e3f.
Re1eg,12/03/05 11HRerserver,11eg 2.tabulka regionserver:1117ved regionserver:4 open region:1117ved regionserver:4 open 1330944810191.90d287473fe223f0ddc137020efda25d.
…
2012-03-05 13:01:41,246 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Počet aktivních připojení je:6
2012-03-05 13:01:41,248 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:7
…
2012-03-05 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště=DS-1423642413.23020236402443.202 , infoPort=50075, ipcPort=50020):Počet aktivních připojení je:10
2012-03-05 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration.0 0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Počet aktivních připojení je:9
/…
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable,,1330944810191.62a312d67981c86c42b6bc02e6ec7e3f.; další sekvenceid=62916
…
12/03/05 13:01:41 INFO regionserver.HRegion:Online uživatelská tabulka,uživatel1361265841,1330944811370.80663fcf291e3ce09064f6ba05; next sequenceid=62919
2012-03-05 13:01:41,474 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:6
2012-03-05 13 :01:41,491 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:7
2012-03-05 13:01:41,495 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipc22br aktivní připojení =220:00:0000 -05 13:01:41,508 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:7
…
12/03/05 13:01:41 INFO regionserver .HRegion:Online uživatelská tabulka,uživatel1964968041,1330944848231.dd89596e9129e1caa7e07f8a491c9734.; next sequenceid=62920
2012-03-05 13:01:41,618 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:6
2012-03-05 13 :01:41,621 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-525355pc=052522355pc=00772232550pc=0077 Počet aktivních připojení je:7
…
2012-03-05 13:01:41,829 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště =DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Počet aktivních připojení je:7
12/03/05 13:01:41 Online userserverd.HRegion region INFO ,uživatel515290649,1330944849739.d23924dc9e9d5891f332c337977af83d.; next sequenceid=62926
2012-03-05 13:01:41,832 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:6
2012-03-05 13 :01:41,838 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště=DS-1423642448-10.0.0.64-525355pc=052722355pc=0077223225570pc=00017) Počet aktivních připojení je:7
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable,user757669512,1330944850808.cd0d6f16d8ae9cf0c9277f5b9f.6; next sequenceid=62929
…
2012-03-05 14:01:39,711 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:4
2012 -03-05 22:48:41,945 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště=DS-1423642448-10.25230.60705752030.6705752030.605 ipcPort=50020):Počet aktivních připojení je:4
12/03/05 22:48:41 INFO regionserver.HRegion:Onlined usertable,user757669512,1330944850808.cd0d6f16006aef57c.c6 další sekvence id=62929
2012-03-05 22:48:41,963 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště 36048 DS-14. -50010-1321352233772, infoPort=50075, ipcPort=50020):Počet aktivních připojení je:4
Můžete vidět, jak se regiony otevírají jedna po druhé, ale také si můžete všimnout, že počet aktivních připojení nikdy nevyšplhá na 22 – sotva dosáhne 10. proč tomu tak je? Abychom tomu lépe porozuměli, musíme vidět, jak se soubory v HDFS mapují k instanci DataXceiveru na straně serveru – a skutečná vlákna, která představují.
Hluboký ponor Hadoop
Výše uvedené DFSInputStream a DFSOutputStream jsou skutečně fasádami kolem obvyklých konceptů streamů. Zabalí komunikaci klient-server do těchto standardních rozhraní Java a zároveň interně směrují provoz do vybraného DataNode – což je ten, který uchovává kopii aktuálního bloku. Má právo tato spojení otevírat a zavírat podle potřeby. Když klient čte soubor v HDFS, třídy klientských knihoven se transparentně přepínají z bloku do bloku, a tedy z DataNode na DataNode, takže musí podle potřeby otevírat a zavírat připojení.
DFSInputStream má instanci třídy DFSClient.BlockReader, která otevírá připojení k DataNode. Instance streamu volá blockSeekTo() pro každé volání funkce read() , která se postará o otevření připojení, pokud ještě žádné neexistuje. Jakmile je blok kompletně přečten, spojení je uzavřeno. Zavření streamu má samozřejmě stejný účinek.
DFSOutputStream má podobnou pomocnou třídu, DataStreamer. Sleduje připojení k serveru, které je zahájeno metodou nextBlockOutputStream(). Má další interní třídy, které pomáhají s vypisováním dat bloku, které zde pro stručnost vynecháváme.
Bloky zápisu i čtení vyžadují vlákno, které drží soket a mezilehlá data na straně serveru, zabalená do instance DataXceiver. V závislosti na tom, co váš klient dělá, uvidíte, že počet připojení kolísá kolem počtu aktuálně používaných souborů v HDFS.
Zpět k hádance HBase výše:důvod, proč nevidíte až 22 (a více) připojení během startu, je ten, že zatímco jsou regiony otevřené, jedinými požadovanými údaji je informační blok HFile. Tento blok se přečte, aby se získaly důležité podrobnosti o každém souboru, ale pak se znovu zavře. To znamená, že prostředek na straně serveru je uvolněn rychle za sebou. Zbývající čtyři spojení je těžší určit. JStack můžete použít k výpisu všech vláken na DataNode, což v tomto příkladu ukazuje tento záznam:
„DataXceiver pro klienta /127.0.0.1:64281 [blok pro odesílání blk_5532741233443227208_4201]“ 0dd70 prio=85 démon 0db06 nid=0x1178b4000 spustitelný [1178b3000]
java.lang.Thread.State:RUNNABLE
…
„DataXceiver pro klienta /127.0.0.1:64172 [blok příjmu blk_-2005512129579433420_4199_20bDFSC.lient_20bDFSC.0 ,60020,1330984111693_1330984118810]” démon prio=5 tid=7fb966109000 nid=0x1169cb000 spustitelný [1169ca000]
java.…NABLE.Tlang.
Toto jsou jediné položky DataXceiveru (v tomto příkladu), takže počet ve skupině vláken je trochu zavádějící. Připomeňme, že vlákno démona DataXceiverServer již představuje jednu položku navíc, která v kombinaci s výše uvedenými dvěma představuje tři aktivní připojení – což ve skutečnosti znamená tři aktivní vlákna. Důvod, proč místo toho protokol uvádí čtyři, je ten, že protokoluje počet z aktivního vlákna, které se blíží ke konci. Takže krátce poté, co se zaprotokoluje počet čtyř, je ve skutečnosti o jedno méně, tj. tři, a tudíž odpovídá našemu počtu aktivních vláken.
Všimněte si také, že interní pomocné třídy, jako je PacketResponder, zabírají jiné vlákno ve skupině, zatímco jsou aktivní. Výstup JStack tuto skutečnost naznačuje a uvádí vlákno jako takové:
„PacketResponder 0 pro blok blk_-2005512129579433420_4199“ démon prio=5 tid=7fb96300x in16 Object=000. () [116acd000]
java.lang.Thread.State:TIMED_WAITING (na objektovém monitoru)
na java.lang.Object.wait (Nativní metoda)
na org.apache.hadoop. hdfs.server.datanode.BlockReceiver$PacketResponder \
.lastDataNodeRun(BlockReceiver.java:779)
– uzamčeno (org.apache.hadoop.hdfs.server.datanode.BlockReceiver)$PacketRespond>na org.apache.hadoop.hdfs.server.datanode.BlockReceiver$PacketResponder.run(BlockReceiver.java:870)
na java.lang.Thread.run(Thread.java:680)
Toto vlákno je aktuálně ve stavu TIMED_WAITING a není považováno za aktivní. To je důvod, proč počet vydávaný příkazy protokolu DataXceiver nezahrnuje tento druh vláken. Pokud se stanou aktivními, protože klient odesílá data, počet aktivních vláken se opět zvýší. Další věc, kterou je třeba poznamenat, je, že toto vlákno nepotřebuje samostatné připojení nebo soket mezi klientem a serverem. PacketResponder je pouze vlákno na straně serveru, které přijímá bloková data a streamuje je do dalšího DataNode v kanálu zápisu.
Příkaz Hadoop fsck má také možnost hlásit, jaké soubory jsou aktuálně otevřené pro zápis:
$ hadoop fsck /hbase -openforwrite
FSCK spustil larsgeorge z /10.0.0.29 pro cestu / hbase v pondělí 5. března 22:59:47 CET 2012
……/hbase/.logs/10.0.0.29,60020,1330984111693/10.0.0.29%3A60020.13309240118% 3A60020.13309240118 TE 4, OPPP13092401188 ………………………………..Stav:ZDRAVÝ
Celková velikost: 2088783626 B
Celkový počet adresářů: 54
Celkový počet souborů: 45
…
To se bezprostředně netýká obsazeného vlákna na straně serveru, protože ty jsou přiděleny podle ID bloku. Ale dá se z toho poznat, že je tam jeden otevřený blok pro psaní. Příkaz Hadoop má další možnosti pro tisk skutečných souborů a ID bloku, ze kterých se skládají:
$ hadoop fsck /hbase -files -blocks
FSCK spustil larsgeorge z /10.0.0.29 pro cesta /hbase v úterý 6. března 10:39:50 CET 2012
…
/hbase/.META./1028785192/.tmp
/hbase/.META./1028785192/info
/hbase/.META./1028785192/info/4027596949915293355 36517 bajtů, 1 blok(y): OK
0. blk_5532741233443227208_4201 len=36517 repl=1
…
Stav:ZDRAVÝ
Celková velikost: 2088788703 B
Celkové dirs : 54
Celkový počet souborů: 45 (aktuálně zapisovaných souborů:1)
Celkový počet bloků (ověřeno): 64 (průměrná velikost bloku 32637323 B) (Celkový počet otevřených bloků souborů (neověřeno):1)
Minimálně replikované bloky: 64 (100,0 %)
…
To vám dává dvě věci. Za prvé, souhrn uvádí, že v době spuštění příkazu existuje jeden otevřený souborový blok – což odpovídá počtu uvedenému výše uvedenou volbou „-openforwrite“. Za druhé, seznam bloků vedle každého souboru vám umožňuje přiřadit název vlákna k souboru, který obsahuje blok, ke kterému se přistupuje. V tomto příkladu je blok s ID „blk_5532741233443227208_4201“ odeslán ze serveru klientovi, zde RegionServer. Tento blok patří do HBase .META. tabulka, jak ukazuje výstup příkazu Hadoop fsck. Kombinace JStack a fsck může sloužit jako slabá náhrada za lsof (nástroj na příkazovém řádku Linuxu pro „vypsání otevřených souborů“).
JStack také hlásí, že existuje vlákno DataXceiver s doprovodným PacketResponderem pro ID bloku „blk_-2005512129579433420_4199“, ale toto ID chybí v seznamu bloků hlášených fsck. Blok totiž ještě není dokončen, a tudíž není čtenářům dostupný. Jinými slovy, Hadoop fsck hlásí pouze dokončené (nebo synchronizované[7][8], pro verzi Hadoop, která tuto funkci podporuje) bloky.
Zpět na HBase
Otevření všech oblastí nevyžaduje tolik prostředků na serveru, jak byste očekávali. Pokud však naskenujete celou tabulku HBase, přinutíte HBase číst všechny bloky ve všech HFiles:
HBase Shell:
hbase(main):003:0> skenování 'usertable'
…
1000000 řádek(y) za 1460,3120 sekund
Protokol datového uzlu:
2012-03-05 14:42:20,580 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Počet aktivních připojení je:6
2012-03-05 14:43:23,293 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:7
2012 -03-05 14:43:23,299 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště=DS-1423642448-10.250.030.67077520313050570570505705050505 ipcPort=50020):Počet aktivních připojení je:8
…
2012-03-05 14:49:24,332 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0. 0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Počet aktivních připojení je:11
4org:2012-2012-00 .apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:10
2012-03-05 14:49:59,987 DEBUG org.apache.hadoop.hdfs.server.datanod e.DataNode:Počet aktivních připojení je:11
2012-03-05 14:51:12,603 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1, storageID=50010 DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Počet aktivních připojení je:12
2012-03-05 14:605DEBURGaph.2 .server.datanode.DataNode:Počet aktivních připojení je:11
2012-03-05 14:51:46,473 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:12
…
2012-03-05 14:56:59,420 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:15
2012-03-05 14:57:31,722 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:16
2012-03-05 14:58:24,909 DEBUG org.apache.hadoop.hdfs. server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, ID úložiště=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort ofNumber=500 počet připojení je:17
2012-03-05 14:58:24,910 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:16
…
2012-03-05 15:04:17,688 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:21
2012-03-05 15:04:17,689 DEBUG org.ap „ br />2012-03-05 15:04:54,545 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:21
2012-03-05 15:05:55,901 DEBUG nebo :22
2012-03-05 15:05:55,901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Počet aktivních připojení je:21
Počet aktivních připojení nyní dosahuje nepolapitelných 22. Všimněte si, že tento počet již zahrnuje vlákno serveru, takže stále máme trochu málo toho, co bychom mohli považovat za teoretické maximum – na základě počtu souborů, které musí HBase zpracovat.
Co to všechno znamená?
Takže, kolik „xcieverů (sic)“ potřebujete? Vzhledem k tomu, že používáte pouze HBase, můžete jednoduše sledovat výše uvedenou metriku „storefiles“ (kterou získáte také prostřednictvím Ganglia nebo JMX) a přidat několik procent pro přechodné a předem zapisované soubory protokolu. To by mělo fungovat pro systémy v pohybu. Pokud byste však toto číslo určili na nečinném, plně zkomprimovaném systému a předpokládali, že je to maximum, mohlo by se vám zdát toto číslo příliš nízké, jakmile začnete přidávat další soubory úložiště během pravidelných vyprázdnění paměti paměti, tj. jakmile začnete přidat data do tabulek HBase. Nebo pokud na stejném clusteru používáte také MapReduce, agregaci protokolu Flume a tak dále. Budete muset počítat s těmito extra soubory, a co je důležitější, otevřít bloky pro čtení a zápis.
Všimněte si znovu, že příklady v tomto příspěvku používají jeden DataNode, něco, co nebudete mít ve skutečném clusteru. Za tímto účelem budete muset vydělit celkový počet souborů úložiště (podle metriky HBase) počtem DataNodes, které máte. Pokud máte například počet uložených souborů 1000 a váš cluster má 10 DataNode, pak byste měli být v pořádku s výchozím nastavením 256 vláken xceiver na DataNode.
Nejhorším případem by byl počet všech aktivních čtenářů a zapisovatelů, tedy těch, kteří aktuálně odesílají nebo přijímají data. Ale protože je těžké to určit předem, možná budete chtít zvážit vybudování slušné rezervy. Také, protože proces zápisu potřebuje další – i když kratší – vlákno (pro PacketResponder), musíte s tím také počítat. Rozumný, ale poněkud zjednodušující vzorec by tedy mohl být:
Tento vzorec bere v úvahu, že potřebujete asi dvě vlákna pro aktivního zapisovatele a další pro aktivního čtenáře. To se pak sečte a vydělí počtem DataNode, protože musíte zadat „dfs.datanode.max.xcievers“ na DataNode.
Pokud se vrátíte zpět na snímek obrazovky HBase RegionServer výše, uvidíte, že existuje 22 souborů úložiště. These are immutable and will only be read, or in other words occupy one thread only. For all memstores that are flushed to disk you need two threads – but only until they are fully written. The files are finalized and closed for good, cleaning up any thread in the process. So these come and go based on your flush frequency. Same goes for compactions, they will read N files and write them into a single new one, then finalize the new file. As for the write-ahead logs, these will occupy a thread once you have started to add data to any table. There is a log file per server, meaning that you can only have twice as many active threads for these files as you have RegionServers.
For a pure HBase setup (HBase plus its own HDFS, with no other user), we can estimate the number of needed DataXceiver’s with the following formula:
Since you will be hard pressed to determine the active number of store files, flushes, and so on, it might be better to estimate the theoretical maximum instead. This maximum value takes into account that you can only have a single flush and compaction active per region at any time. The maximum number of logs you can have active matches the number of RegionServers, leading us to this formula:
Obviously, the number of store files will increase over time, and the number of regions typically as well. Same for the numbers of servers, so keep in mind to adjust this number over time. In practice, you can add a buffer of, for example, 20%, as shown in the formula below – in an attempt to not force you to change the value too often.
On the other hand, if you keep the number of regions fixed per server[9], and rather split them manually, while adding new servers as you grow, you should be able to keep this configuration property stable for each server.
Final Advice &TL;DR
Here is the final formula you want to use:
It computes the maximum number of threads needed, based on your current HBase vitals (no. of store files, regions, and region servers). It also adds a fudge factor of 20% to give you room for growth. Keep an eye on the numbers on a regular basis and adjust the value as needed. You might want to use Nagios with appropriate checks to warn you when any of the vitals goes over a certain percentage of change.
Note:Please make sure you also adjust the number of file handles your process is allowed to use accordingly[10]. This affects the number of sockets you can use, and if that number is too low (default is often 1024), you will get connection issues first.
Finally, the engineering devil on one of your shoulders should already have started to snicker about how horribly non-Erlang-y this is, and how you should use an event driven approach, possibly using Akka with Scala[11] – if you want to stay within the JVM world. Bear in mind though that the clever developers in the community share the same thoughts and have already started to discuss various approaches[12][13].
Links:
- [1] http://old.nabble.com/Re%3A-xceiverCount-257-exceeds-the-limit-of-concurrent-xcievers-256-p20469958.html
- [2] http://ccgtech.blogspot.com/2010/02/hadoop-hdfs-deceived-by-xciever.html
- [3] https://issues.apache.org/jira/browse/HDFS-1861 “Rename dfs.datanode.max.xcievers and bump its default value”
- [4] https://issues.apache.org/jira/browse/HDFS-1866 “Document dfs.datanode.max.transfer.threads in hdfs-default.xml”
- [5] http://hbase.apache.org/book.html#dfs.datanode.max.xcievers
- [6] http://www.oracle.com/technetwork/java/hotspotfaq-138619.html#threads_oom
- [7] https://issues.apache.org/jira/browse/HDFS-200 “In HDFS, sync() not yet guarantees data available to the new readers”
- [8] https://issues.apache.org/jira/browse/HDFS-265 “Revisit append”
- [9] http://search-hadoop.com/m/CBBoV3z24H1 “HBase, mail # user – region size/count per regionserver”
- [10] http://hbase.apache.org/book.html#ulimit “ulimit and nproc”
- [11] http://akka.io/ “Akka”
- [12] https://issues.apache.org/jira/browse/HDFS-223 “Asynchronous IO Handling in Hadoop and HDFS”
- [13] https://issues.apache.org/jira/browse/HDFS-918 “Use single Selector and small thread pool to replace many instances of BlockSender for reads”