Introduktion
Nogle af de konfigurationsegenskaber, der findes i Apache Hadoop, har en direkte effekt på klienter, såsom Apache HBase. En af disse egenskaber kaldes "dfs.datanode.max.xcievers" og hører til HDFS-underprojektet. Den definerer antallet af serversidetråde og – til en vis grad – sockets, der bruges til dataforbindelser. Hvis du indstiller dette tal for lavt, kan det forårsage problemer, efterhånden som du vokser eller øger udnyttelsen af din klynge. Dette indlæg hjælper dig med at forstå, hvad der sker mellem klienten og serveren, og hvordan du bestemmer et rimeligt antal for denne ejendom.
Problemet
Da HBase gemmer alt, hvad det har brug for inde i HDFS, kan den hårde øvre grænse, der pålægges af “dfs.datanode.max.xcievers”-konfigurationsegenskaben, resultere i, at for få ressourcer er tilgængelige for HBase, hvilket manifesterer sig som IOExceptions på begge sider af forbindelsen. Her er et eksempel fra HBase-mailinglisten [1], hvor følgende beskeder oprindeligt blev logget på RegionServer-siden:
2008-11-11 19:55:52,451 INFO org.apache.hadoop.dfs.DFSClient: Undtagelse i createBlockOutputStream java.io.IOException:Kunne ikke læse fra stream
2008-11-11 19:55:52,451 INFO org.apache.hadoop.dfs.DFSClient: Abandoning block blk_-54670141087501_3907501_3907501_39507501_-546701410875011 11 19:55:58,455 ADVARSEL org.apache.hadoop.dfs.DFSClient: DataStreamer Undtagelse:java.io.IOException:Kan ikke oprette ny blok.
2008-11-11 19:55:58,455 ADVARSEL org.apache .hadoop.dfs.DFSClient:Error Recovery for block blk_-5467014108758633036_595771 bad datanode[0]
2008-11-11 19:55:58,482 FATAL dooph.Flush. . Tvinger servernedlukning
Korrelering af dette med Hadoop DataNode-logfilerne afslørede følgende indgang:
FEJL org.apache.hadoop.dfs.DataNode: DatanodeRegistration(10.10.10.53:50010,storageID=DS-1570581820-10.10.10.53-50010-12241117842339,infoPort=50075, ipcPort=50020):DataXceiver:java.io.IOException af 58xceiverCount x6 overskrider P-grænsen58x6
I dette eksempel fik den lave værdi af "dfs.datanode.max.xcievers" for DataNodes hele RegionServeren til at lukke ned. Det er en rigtig dårlig situation. Desværre er der ingen fast-og-hurtig regel, der forklarer, hvordan man beregner den påkrævede grænse. Det anbefales almindeligvis at hæve tallet fra standardværdien på 256 til noget i retning af 4096 (se [1], [2], [3], [4] og [5] for reference). Dette gøres ved at tilføje denne egenskab til filen hdfs-site.xml for alle DataNodes (bemærk, at den er stavet forkert):
Bemærk:Du skal genstarte dine DataNodes efter at have foretaget denne ændring af konfigurationsfilen.
Dette burde hjælpe med ovenstående problem, men du vil måske stadig gerne vide mere om, hvordan det hele spiller sammen, og hvad HBase laver med disse ressourcer. Vi vil diskutere dette i resten af dette indlæg. Men før vi gør det, skal vi være klar over, hvorfor du ikke bare kan sætte dette tal meget højt, f.eks. 64K og være færdig med det.
Der er en grund til en øvre grænse, og den er todelt:For det første har tråde brug for deres egen stak, hvilket betyder, at de optager hukommelsen. For nuværende servere betyder dette 1 MB pr. tråd[6] som standard. Med andre ord, hvis du bruger alle 4096 DataXceiver-trådene, har du brug for omkring 4 GB heap for at rumme dem. Dette skærer ind i den plads, du har tildelt til memstores og blokcaches, såvel som alle de andre bevægelige dele af JVM. I værste fald kan du løbe ind i en OutOfMemoryException, og RegionServer-processen er toast. Du vil indstille denne egenskab til et rimeligt højt tal, men heller ikke for højt.
For det andet, når du har disse mange tråde aktive, vil du også se din CPU blive mere og mere indlæst. Der vil ske mange kontekstskift for at håndtere alt det samtidige arbejde, hvilket fjerner ressourcer til det rigtige arbejde. Ligesom med bekymringerne omkring hukommelsen, ønsker man, at antallet af tråde ikke vokser grænseløst, men giver en rimelig øvre grænse – og det er det "dfs.datanode.max.xcievers" er til for.
Hadoop-filsystemdetaljer
Fra klientsiden leverer HDFS-biblioteket abstraktionen kaldet Path. Denne klasse repræsenterer en fil i et filsystem, der understøttes af Hadoop, repræsenteret af FileSystem-klassen. Der er et par konkrete implementeringer af den abstrakte FileSystem-klasse, hvoraf den ene er DistributedFileSytem, der repræsenterer HDFS. Denne klasse omslutter igen den faktiske DFSClient-klasse, der håndterer alle interaktioner med fjernserverne, dvs. NameNode og de mange DataNodes.
Når en klient, såsom HBase, åbner en fil, gør den det ved for eksempel at kalde open() eller create() metoderne i FileSystem-klassen, her de mest forenklede inkarnationer
public DFSInputStream open(String src) throws IOException
public FSDataOutputStream create(Path f) throws IOException
Den returnerede stream-instans er det, der har brug for en socket og tråd på serversiden, som bruges til at læse og skrive datablokke. De indgår i kontrakten om udveksling af data mellem klienten og serveren. Bemærk, at der er andre, RPC-baserede protokoller i brug mellem de forskellige maskiner, men med henblik på denne diskussion kan de ignoreres.
Den returnerede streamforekomst er en specialiseret DFSOutputStream eller DFSInputStream-klasse, som håndterer al interaktion med NameNode for at finde ud af, hvor kopierne af blokkene findes, og datakommunikationen pr. blok pr. DataNode.
På serversiden ombryder DataNode en forekomst af DataXceiverServer, som er den faktiske klasse, der læser ovenstående konfigurationsnøgle og også kaster ovenstående undtagelse, når grænsen overskrides.
Når DataNode starter, opretter den en trådgruppe og starter den nævnte DataXceiverServer forekomst sådan:
this.threadGroup =new ThreadGroup(“dataXceiverServer”);
this.dataXceiverServer =new Daemon( threadGroup,
ny DataXceiverServer(ss, conf, this));
this.threadGroup.setDaemon(true); // ødelægge automatisk når tom
Bemærk, at DataXceiverServer tråden allerede optager én plads i trådgruppen. DataNode har også denne interne klasse til at hente antallet af aktuelt aktive tråde i denne gruppe:
/** Antal samtidige xceivere pr. node. */
int getXceiverCount() {
return threadGroup ==null ? 0 :threadGroup.activeCount();
}
Læse- og skriveblokke, som initieret af klienten, forårsager, at der oprettes en forbindelse, som pakkes af DataXceiverServer tråden ind i en DataXceiver instans. Under denne aflevering oprettes en tråd og registreres i ovenstående trådgruppe. Så for hver aktiv læse- og skriveoperation spores en ny tråd på serversiden. Hvis antallet af tråde i gruppen overstiger det konfigurerede maksimum, kastes den nævnte undtagelse og registreres i DataNodes logfiler:
if (curXceiverCount> dataXceiverServer.maxXceiverCount) {
throw new IOException(“xceiverCount ” + curXceiverCount
+ ” overskrider grænsen for samtidige xcievers ”
+ dataXceiverServer.maxXceiverCount);
}
Konsekvenser for kunder
Nu er spørgsmålet, hvordan klientens læsning og skrivning relaterer sig til serversidetrådene. Før vi går ind i detaljerne, lad os dog bruge fejlfindingsoplysningerne, som DataXceiver-klassen logger, når den oprettes og lukkes
LOG.debug(“Antal aktive forbindelser er:” + datanode.getXceiverCount());
…
LOG.debug(datanode.dnRegistration + “:Antallet af aktive forbindelser er:” + datanode.getXceiverCount());
og overvåg under en start af HBase, hvad der er logget på DataNode. For nemheds skyld gøres dette på en pseudo-distribueret opsætning med en enkelt DataNode og RegionServer-instans. Det følgende viser toppen af RegionServers statusside.
Den vigtige del er i afsnittet "Metrics", hvor der står "storefiles=22". Så hvis vi antager, at HBase har mindst så mange filer at håndtere, plus nogle ekstra filer til fremskrivningsloggen, skulle vi se ovenstående logmeddelelse, at vi har mindst 22 "aktive forbindelser". Lad os starte HBase og tjekke DataNode- og RegionServer-logfilerne:
Kommandolinje:
$ bin/start-hbase.sh
…
Datanodelog:
2012-03-05 13:01:35,309 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Antal aktive forbindelser er: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):Antallet af aktive forbindelser er:2
12/03/05 13:01:35 INFO3642448-10.0.0.64-50010-1321352233772, ipcPort=50020:Antal aktive forbindelser er:2
12/03/05 13:01:35 INFO3642448-10.0.0.65 globalMemStoreLimitLowMark=347.1m, maxHeap=991.7m
12/03/05 13:01:39 INFO http.HttpServer:Port returneret af webServer.getConnectors()[0].getLocalPort() før open() er -1 . Åbning af lytteren på 60030
2012-03-05 13:01:40,003 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:1
12/03/05 13:01:40 INFO regionserver.HRegionServer:Modtaget anmodning om at åbne region:-ROOT-,,0.70236052
2012-03-05 13:01:40,882 DEBUG org.apache.hadoop.hdfs.Dataserver.Nodenode. :Antal aktive forbindelser er:3
2012-03-05 13:01:40,884 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS44238 -10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Antallet af aktive forbindelser er:4
2012-03-05 13:01:40,888 DEBUG org.hdfsserver.ap datanode.DataNode:Antal aktive forbindelser er:3
…
12/03/05 13:01:40 INFO regionserver.HRegion:Onlined -ROOT-,,0.70236052; næste sequenceid=63083
2012-03-05 13:01:40,982 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:3
2012-03-05 13 :01:40,983 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-50010-23210,07010-23210-23210-23210-port 50010-50010-232010-23210-23210-10.0.0.64-50010-232010-232010-23210-10. Antal aktive forbindelser er:4
…
12/03/05 13:01:41 INFO regionserver.HRegionServer:Modtaget anmodning om at åbne region:.META.,,1.1028785192
2012-03 -05 13:01:41,026 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er: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, infoPort=50075=50, 023642448-10.0.0.64-50010-1321352233772, infoPort=50075=50, 02c-forbindelse er aktiv:/Number:ipc:<…
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined .META.,,1.1028785192; næste sequenceid=63082
2012-03-05 13:01:41,109 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antallet af aktive forbindelser er:3
2012-03-05 13 :01:41,114 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:4
2012-03-05 13:01:41,117 DEBUG org.apache.hadoop.hdfs.server .datanode.DataNode:Antal aktive forbindelser er:5
12/03/05 13:01:41 INFO regionserver.HRegionServer:Modtaget anmodning om at åbne 16 region(er)
12/03/05 13 :01:41 INFO regionserver.HRegionServer:Modtaget anmodning om at åbne region:usertable,,1330944810191.62a312d67981c86c42b6bc02e6ec7e3f.
12/03/05 13:01S 1330944810191.90d287473fe223f0ddc137020efda25d.
…
2012-03-05 13:01:41,246 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Antal aktive forbindelser er:6
2012-03-05 13:01:41,248 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:7
…
2012-03-05 13:01:41,257 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-14236420508-16236420508-1623-16236420500-16236420500-16236420500-13236420500.321-13236420500.323-13236420500-1323642050. , infoPort=50075, ipcPort=50020):Antallet af aktive forbindelser er:10
2012-03-05 13:01:41,257 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):Antallet af aktive forbindelser er:9
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable,,1330944810191.62a312d67981c86c42b6bc02e6ec7e3f.; næste sequenceid=62916
…
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable,user1361265841,1330944811370.80663fcf291e39099640f; næste sequenceid=62919
2012-03-05 13:01:41,474 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:6
2012-03-05 13 :01:41,491 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:7
2012-03-05 13:01:41,495 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=1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020 aktiv forbindelse):Number:2020 -05 13:01:41,508 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:7
…
12/03/05 13:01:41 INFO regionserver .HRegion:Onlined usertable,user1964968041,1330944848231.dd89596e9129e1caa7e07f8a491c9734.; næste sequenceid=62920
2012-03-05 13:01:41,618 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antallet af aktive forbindelser er: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-50010-50010-25207,025010-23210, 50010-23210, 50010-23210, 50010-23210, 50010-232010, 50010-23210, 50010-232010, 0.0.64-50010-23210-232010-232010-2321000 Antal aktive forbindelser er:7
…
2012-03-05 13:01:41,829 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):Antallet af aktive forbindelser er:7
12/03/05 13:01:41 Online-region:41-serveren INFO-server. ,user515290649,1330944849739.d23924dc9e9d5891f332c337977af83d.; næste sequenceid=62926
2012-03-05 13:01:41,832 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:6
2012-03-05 13 :01:41,838 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-50010-232107,0250107, 23210, 50010-23210, 50010-23210, 50010-23210, 50010-23210, 50010, 0.0.0.64-50010-50010-232010-232010-23210-10.0.0.64-50010-232010-23210-2321 Antal aktive forbindelser er:7
12/03/05 13:01:41 INFO regionserver.HRegion:Onlined usertable,user757669512,1330944850808.cd0d6f16d8ae9cf0c9277c6b9f.; næste sequenceid=62929
…
2012-03-05 14:01:39,711 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:4
2012 -03-05 22:48:41,945 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.614-13270,3270-10.0.0.614-10.0.0.601,3270-1270,3270,3270,3270,3270 ipcPort=50020):Antallet af aktive forbindelser er:4
12/03/05 22:48:41 INFO regionserver.HRegion:Onlined usertable,user757669512,1330944850808.cd0d6f16d08aeee;cd0d6f17d5c9aee;cd0d6f17d5c9ae96cd5cf6c96cdcf6cf6cf6cf6cdcf6c9b6cf6cdf6c69b næste sequenceid=62929
2012-03-05 22:48:41,963 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-144236.40.40236.4 -50010-1321352233772, infoPort=50075, ipcPort=50020):Antallet af aktive forbindelser er:4
Du kan se, hvordan regionerne åbnes efter hinanden, men hvad du måske også bemærker er, at antallet af aktive forbindelser aldrig stiger til 22 - det når knap engang op på 10. Hvorfor det? For at forstå dette bedre, er vi nødt til at se, hvordan filer i HDFS knytter sig til server-side DataXceivers instans – og de faktiske tråde, de repræsenterer.
Hadoop Deep Dive
De førnævnte DFSInputStream og DFSOutputStream er virkelig facader omkring de sædvanlige stream-koncepter. De pakker klient-server-kommunikationen ind i disse standard Java-grænseflader, mens de internt dirigerer trafikken til en valgt DataNode - som er den, der har en kopi af den aktuelle blok. Det har friheden til at åbne og lukke disse forbindelser efter behov. Når en klient læser en fil i HDFS, skifter klientbiblioteksklasserne transparent fra blok til blok og derfor fra DataNode til DataNode, så den skal åbne og lukke forbindelser efter behov.
DFSInputStream har en forekomst af en DFSClient.BlockReader-klasse, der åbner forbindelsen til DataNode. Stream-instansen kalder blockSeekTo() for hvert kald til read() som sørger for at åbne forbindelsen, hvis der ikke allerede er nogen. Når en blok er fuldstændig læst, lukkes forbindelsen. At lukke strømmen har selvfølgelig samme effekt.
DFSOutputStream har en lignende hjælpeklasse, DataStreamer. Den sporer forbindelsen til serveren, som initieres af nextBlockOutputStream()-metoden. Den har yderligere interne klasser, der hjælper med at skrive blokdataene ud, som vi udelader her for kortheds skyld.
Både skrive- og læseblokke kræver en tråd til at holde stikket og mellemliggende data på serversiden, pakket ind i DataXceiver-instansen. Afhængigt af, hvad din klient laver, vil du se antallet af forbindelser svinge omkring antallet af aktuelt tilgåede filer i HDFS.
Tilbage til HBase-gåden ovenfor:grunden til, at du ikke ser op til 22 (og flere) forbindelser under starten, er, at mens regionerne åbner, er de eneste nødvendige data HFiles infoblok. Denne blok læses for at få vigtige detaljer om hver fil, men lukkes derefter igen. Det betyder, at ressourcen på serversiden frigives hurtigt efter hinanden. De resterende fire forbindelser er sværere at bestemme. Du kan bruge JStack til at dumpe alle tråde på DataNode, som i dette eksempel viser denne post:
“DataXceiver for client /127.0.0.1:64281 [sender blok blk_5532741233443227208_4201]” daemon prio=904 tid=71b prio=906 tid nid=0x1178b4000 kan køres [1178b3000]
java.lang.Thread.State:RUNNABLE
…
“DataXceiver for client /127.0.0.1:64172 [receiving block blk_-2005512129579433420_4199_1 client=DFSCl.0sient=0.2SCl. ,60020,1330984111693_1330984118810]” dæmon prio=5 tid=7fb966109000 nid=0x1169cb000 kan køres [1169ca000]
java.lang.
Tråden...ABLE
Dette er de eneste DataXceiver-indgange (i dette eksempel), så antallet i trådgruppen er en smule misvisende. Husk på, at DataXceiverServer-dæmontråden allerede tegner sig for en ekstra post, som kombineret med de to ovenstående står for de tre aktive forbindelser – hvilket faktisk betyder tre aktive tråde. Grunden til, at loggen angiver fire i stedet, er, at den logger antallet fra en aktiv tråd, der er ved at afslutte. Så kort efter, at antallet af fire er logget, er det faktisk én mindre, dvs. tre, og matcher derfor vores hovedantal af aktive tråde.
Bemærk også, at de interne hjælperklasser, såsom PacketResponder, optager en anden tråd i gruppen, mens de er aktive. JStack-outputtet indikerer dette faktum, idet tråden angives som sådan:
"PacketResponder 0 for Block blk_-2005512129579433420_4199" daemon prio=5 tid=7fb96384d001 nidaceit=0x00 nid. () [116acd000]
java.lang.Thread.State:TIMED_WAITING (på objektmonitor)
på java.lang.Object.wait(Native Method)
på org.apache.hadoop. hdfs.server.datanode.BlockReceiver$PacketResponder \
.lastDataNodeRun(BlockReceiver.java:779)
– låst (en org.apache.hadoop.hdfs.server.datanode.BlockReceiver$PacketResponder)
på org.apache.hadoop.hdfs.server.datanode.BlockReceiver$PacketResponder.run(BlockReceiver.java:870)
på java.lang.Thread.run(Thread.java:680)
Denne tråd er i øjeblikket i tilstanden TIMED_WAITING og anses ikke for at være aktiv. Det er grunden til, at tællingen, der udsendes af DataXceiver-logsætningerne, ikke inkluderer denne slags tråde. Hvis de bliver aktive på grund af, at klienten sender afsendende data, vil antallet af aktive tråde stige igen. En anden ting at bemærke er, at denne tråd ikke behøver en separat forbindelse eller socket mellem klienten og serveren. PacketResponder er kun en tråd på serversiden til at modtage blokdata og streame dem til den næste DataNode i skrivepipelinen.
Hadoop fsck-kommandoen har også en mulighed for at rapportere, hvilke filer der i øjeblikket er åbne til skrivning:
$ hadoop fsck /hbase -openforwrite
FSCK startet af larsgeorge fra /10.0.0.29 for sti / hbase på Man Mar 05 22:59:47 CET 2012
……/hbase/.logs/10.0.0.29,60020,1330984111693/10.0.0.29%3A60020.13380984110 af WRITEs, OPEN ………………………………..Status:SUND
Samlet størrelse: 2088783626 B
Samlet dirs: 54
I alt filer: 45
…
Dette relaterer sig ikke umiddelbart til en optaget server-side tråd, da disse er allokeret af blok ID. Men du kan udlede af det, at der er én åben blok til at skrive. Hadoop-kommandoen har yderligere muligheder for at udskrive de faktiske filer og blok-id, de består af:
$ hadoop fsck /hbase -files -blocks
FSCK startet af larsgeorge fra /10.0.0.29 for sti /hbase kl. Tue Mar 06 10:39:50 CET 2012
…
/hbase/.META./1028785192/.tmp
/hbase/.META./1028785192/info
/hbase/.META./1028785192/info/4027596949915293355 36517 bytes, 1 blok(er): OK
0. blk_5532741233443227208_4201 len=36517 repl=1
...
Status:SUND
Samlet størrelse: 2088788703 B
Samlet dirs. : 54
I alt filer: 45 (Filer, der skrives i øjeblikket:1)
Samlet antal blokeringer (valideret): 64 (gennemsnitlig blokstørrelse 32637323 B) (Total åbne filblokke (ikke valideret):1)
Minimalt replikerede blokke: 64 (100,0 %)
…
Dette giver dig to ting. For det første angiver resuméet, at der er en åben filblok på det tidspunkt, hvor kommandoen kørte - hvilket svarer til antallet rapporteret af "-openforwrite"-indstillingen ovenfor. For det andet giver listen over blokke ved siden af hver fil dig mulighed for at matche trådnavnet med filen, der indeholder den blok, der tilgås. I dette eksempel sendes blokken med ID "blk_5532741233443227208_4201" fra serveren til klienten, her en RegionServer. Denne blok tilhører HBase .META. tabel, som vist ved output fra Hadoop fsck-kommandoen. Kombinationen af JStack og fsck kan tjene som en fattigmandserstatning for lsof (et værktøj på Linux-kommandolinjen til at "liste åbne filer").
JStack rapporterer også, at der er en DataXceiver-tråd, med en medfølgende PacketResponder, for blok-ID "blk_-2005512129579433420_4199", men dette ID mangler på listen over blokke rapporteret af fsck. Dette skyldes, at blokken endnu ikke er færdig og derfor ikke tilgængelig for læserne. Med andre ord rapporterer Hadoop fsck kun om komplette (eller synkroniserede[7][8], for Hadoop-versioner, der understøtter denne funktion) blokke.
Tilbage til HBase
At åbne alle regionerne kræver ikke så mange ressourcer på serveren, som du ville have forventet. Hvis du dog scanner hele HBase-tabellen, tvinger du HBase til at læse alle blokkene i alle HFiles:
HBase Shell:
hbase(main):003:0> scan 'usertable'
…
1000000 række(r) på 1460,3120 sekunder
Datanodelog:
2012-03-05 14:42:20,580 DEBUG org.apache.hadoop.hdfs.server.datanode. DataNode:Antal aktive forbindelser er:6
2012-03-05 14:43:23,293 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:7
2012 -03-05 14:43:23,299 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.134-13270,3270-10.0.0.614-10.0.0.614-1270,3250,3270,3270 ipcPort=50020):Antallet af aktive forbindelser er: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):Antallet af aktive forbindelser er:11
3402:3492 DE 4-02:3492 DE .apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:10
2012-03-05 14:49:59,987 DEBUG org.apache.hadoop.hdfs.server.datanod e.DataNode:Antal aktive forbindelser er:11
2012-03-05 14:51:12,603 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, infoPort=50075, ipcPort=50020):Antallet af aktive forbindelser er:12
2012-03-05 124:605:DEophGhas. .server.datanode.DataNode:Antal aktive forbindelser er:11
2012-03-05 14:51:46,473 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:12
…
2012-03-05 14:56:59,420 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:15
2012-03-05 14:57:31,722 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:16
2012-03-05 14:58:24,909 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=5002):Number of act ive-forbindelser er:17
2012-03-05 14:58:24,910 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:16
…
2012-03-05 15:04:17,688 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:21
2012-03-05 15:04:17,689 DEBUG org.ap .hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, info5Port=0ip207 aktiv:N-port=52c207) br />2012-03-05 15:04:54,545 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:21
2012-03-05 15:05:55,901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:DatanodeRegistration(127.0.0.1:50010, storageID=DS-1423642448-10.0.0.64-50010-1321352233772, info5Port of0-forbindelse):75Port of0 :22
2012-03-05 15:05:55,901 DEBUG org.apache.hadoop.hdfs.server.datanode.DataNode:Antal aktive forbindelser er:21
Antallet af aktive forbindelser når de uhåndgribelige 22 nu. Bemærk, at denne optælling allerede inkluderer servertråden, så vi mangler stadig lidt, hvad vi kunne betragte som det teoretiske maksimum – baseret på antallet af filer, som HBase skal håndtere.
Hvad betyder det hele?
Så hvor mange "xcievers (sic)" har du brug for? Da du kun bruger HBase, kan du simpelthen overvåge ovenstående "storefiles"-metrik (som du også får gennem Ganglia eller JMX) og tilføje et par procent til mellemliggende og fremskrivningslogfiler. Dette burde fungere for systemer i bevægelse. Men hvis du skulle bestemme tallet på et inaktivt, fuldt komprimeret system og antage, at det er det maksimale, vil du måske finde, at dette tal er for lavt, når du begynder at tilføje flere butiksfiler under almindelige memstore flushes, dvs. så snart du begynder at tilføje data til HBase-tabellerne. Eller hvis du også bruger MapReduce på den samme klynge, Flume-logaggregering og så videre. Du bliver nødt til at tage højde for de ekstra filer og, endnu vigtigere, åbne blokke til læsning og skrivning.
Bemærk igen, at eksemplerne i dette indlæg bruger en enkelt DataNode, noget du ikke vil have på en rigtig klynge. Til det formål skal du dividere det samlede antal butiksfiler (i henhold til HBase-metrikken) med antallet af DataNodes, du har. Hvis du f.eks. har et butiksfilantal på 1000, og din klynge har 10 DataNodes, så burde du være OK med standardindstillingen på 256 xceiver-tråde pr. DataNode.
Det værste tilfælde ville være antallet af alle aktive læsere og skribenter, dvs. dem, der i øjeblikket sender eller modtager data. Men da dette er svært at bestemme på forhånd, vil du måske overveje at bygge i en anstændig reserve. Da skriveprocessen har brug for en ekstra – selvom kortere levetid – tråd (til PacketResponder), skal du også tage højde for det. Så en rimelig, men ret forsimplet formel kunne være:
Denne formel tager højde for, at du har brug for omkring to tråde til en aktiv forfatter og en anden til en aktiv læser. Dette opsummeres og divideres med antallet af DataNodes, da du skal angive "dfs.datanode.max.xcievers" pr. DataNode.
Hvis du går tilbage til HBase RegionServer-skærmbilledet ovenfor, så du, at der var 22 butiksfiler. 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”