Introduktion
Apache HBase er Hadoop open source, distribueret, versioneret storage manager velegnet til tilfældig , læse/skrive i realtid adgang.
Vent vent? tilfældig læse-/skriveadgang i realtid?
Hvordan er det muligt? Er Hadoop ikke bare et sekventielt læse/skrive, batchbehandlingssystem?
Ja, vi taler om det samme, og i de næste par afsnit vil jeg forklare dig, hvordan HBase opnår det tilfældige I/O, hvordan det gemmer data og udviklingen af HBase's HFile-format.
Apache Hadoop I/O-filformater
Hadoop kommer med et SequenceFile[1]-filformat, som du kan bruge til at tilføje dine nøgle/værdi-par, men på grund af hdfs-tilføjelsesfunktionen kan filformatet ikke tillade ændring eller fjernelse af en indsat værdi. Den eneste tilladte handling er tilføje, og hvis du vil slå en specificeret nøgle op, skal du læse filen igennem, indtil du finder din nøgle.
Som du kan se, er du tvunget til at følge det sekventielle læse-/skrivemønster... men hvordan er det muligt at bygge et tilfældigt læse-/skriveadgangssystem med lav latens som HBase oven på dette?
For at hjælpe dig med at løse dette problem har Hadoop et andet filformat, kaldet MapFile[1], en udvidelse af SequenceFile. MapFile er i virkeligheden en mappe, der indeholder to SequenceFiles:datafilen "/data" og indeksfilen "/index". MapFile giver dig mulighed for at tilføje sorterede nøgle/værdi-par, og hver N nøgler (hvor N er et konfigurerbart interval) gemmer nøglen og offset i indekset. Dette giver mulighed for et ret hurtigt opslag, da du i stedet for at scanne alle poster scanner indekset, som har færre poster. Når du har fundet din blok, kan du hoppe ind i den rigtige datafil.
MapFile er rart, fordi du hurtigt kan finde nøgle/værdi-par, men der er stadig to problemer:
- Hvordan kan jeg slette eller erstatte en nøgle/værdi?
- Når mit input ikke er sorteret, kan jeg ikke bruge MapFile.
HBase &MapFile
HBase-nøglen består af:rækkenøglen, kolonnefamilien, kolonnekvalifikationen, tidsstemplet og en type.
For at løse problemet med at slette nøgle/værdi-par, er ideen at bruge "type"-feltet til at markere nøgle som slettet (gravstensmarkører). At løse problemet med at erstatte nøgle/værdi-par er blot et spørgsmål om at vælge det senere tidsstempel (den korrekte værdi er nær slutningen af filen, kun tilføjelse betyder, at sidst indsatte er nær slutningen).
For at løse det "ikke-ordnede" nøgleproblem gemmer vi de sidst tilføjede nøgleværdier i hukommelsen. Når du har nået en tærskel, skyller HBase den til en MapFile. På denne måde ender du med at tilføje sorterede nøgle/værdier til en MapFile.
HBase gør præcis dette[2]:Når du tilføjer en værdi med table.put(), tilføjes din nøgle/værdi til MemStore (under hætten MemStore er et sorteret ConcurrentSkipListMap). Når tærsklen pr. memstore (hbase.hregion.memstore.flush.size) er nået, eller RegionServeren bruger for meget hukommelse til memstores (hbase.regionserver.global.memstore.upperLimit), tømmes data på disken som en ny MapFile .
Resultatet af hver flush er en ny MapFile, og det betyder, at for at finde en nøgle skal du søge i mere end én fil. Dette kræver flere ressourcer og er potentielt langsommere.
Hver gang en get eller en scanning udstedes, scanner HBase gennem hver fil for at finde resultatet, for at undgå at springe rundt for mange filer, er der en tråd, der vil registrere, når du har nået et bestemt antal filer (hbase.hstore.compaction .max). Den forsøger derefter at flette dem sammen i en proces kaldet komprimering, som grundlæggende opretter en ny stor fil som et resultat af filfletningen.
HBase har to typer komprimering:den ene kaldet "mindre komprimering", der blot fusionerer to eller flere små filer til en, og den anden kaldes "større komprimering", der samler alle filerne i regionen op, fusionerer dem og udfører en vis oprydning. I en større komprimering fjernes slettede nøgle/værdier, denne nye fil indeholder ikke gravstensmarkeringerne, og alle duplikatnøgler/værdier (erstatningsværdioperationer) fjernes.
Op til version 0.20 har HBase brugt MapFile-formatet til at gemme dataene, men i 0.20 blev en ny HBase-specifik MapFile introduceret (HBASE-61).
HFil v1
I HBase 0.20 er MapFile erstattet af HFile:en specifik kortfilimplementering for HBase. Ideen minder ret meget om MapFile, men den tilføjer flere funktioner end blot en almindelig nøgle-/værdifil. Funktioner såsom understøttelse af metadata og indekset opbevares nu i den samme fil.
Datablokkene indeholder den aktuelle nøgle/værdier som en MapFile. For hver "blok lukning" tilføjes den første nøgle til indekset, og indekset skrives på HFile close.
HFile-formatet tilføjer også to ekstra "metadata"-bloktyper:Meta og FileInfo. Disse to nøgle-/værdiblokke skrives ved fillukning.
Meta-blokken er designet til at opbevare en stor mængde data med dens nøgle som en streng, mens FileInfo er et simpelt kort, der foretrækkes til små informationer med nøgler og værdier, der begge er byte-array. Regionservers StoreFile bruger Meta-Blocks til at gemme et Bloom Filter, og FileInfo for Max SequenceId, Major Compaction Key og Timerange info. Disse oplysninger er nyttige for at undgå at læse filen, hvis der ikke er nogen chance for, at nøglen er til stede (Bloom Filter), hvis filen er for gammel (Max SequenceId), eller hvis filen er for ny (Timerange) til at indeholde det, vi leder efter for.
HFile v2
I HBase 0.92 blev HFile-formatet ændret en smule (HBASE-3857) for at forbedre ydeevnen, når store mængder data er lagret. Et af hovedproblemerne med HFile v1 er, at du skal indlæse alle de monolitiske indekser og store Bloom-filtre i hukommelsen, og for at løse dette problem introducerer v2 multi-level indekser og et blok-niveau Bloom Filter. Som et resultat heraf har HFile v2 forbedret hastighed, hukommelse og cachebrug.
Hovedfunktionen i denne v2 er "inline blokke", ideen er at bryde indekset og Bloom Filter pr. blok, i stedet for at have hele indekset og Bloom Filteret for hele filen i hukommelsen. På denne måde kan du holde i ram lige hvad du har brug for.
Da indekset flyttes til blokniveau, har du et indeks på flere niveauer, hvilket betyder, at hver blok har sit eget indeks (bladindeks). Den sidste nøgle i hver blok beholdes for at skabe det mellemliggende/indeks, der gør multilevel-indekset b+træ-agtigt.
Blokhovedet indeholder nu nogle oplysninger:"Block Magic"-feltet blev erstattet af "Block Type"-feltet, der beskriver indholdet af blokken "Data", Leaf-Index, Bloom, Metadata, Root-Index, osv. Også tre felter (komprimeret/ukomprimeret størrelse og offset prev blok) blev tilføjet for at tillade hurtige frem- og tilbagesøgninger.
Datablokkodninger
Da nøgler er sorteret og normalt meget ens, er det muligt at designe en bedre komprimering end hvad en generel algoritme kan gøre.
HBASE-4218 forsøgte at løse dette problem, og i HBase 0.94 kan du vælge mellem et par forskellige algoritmer:Prefix og Diff Encoding.
Hovedideen med præfikskodning er kun at gemme det fælles præfiks én gang, da rækkerne er sorteret og begyndelsen typisk er den samme.
Diff Encoding skubber dette koncept yderligere. I stedet for at betragte nøglen som en uigennemsigtig sekvens af bytes, opdeler Diff Encoder hvert nøglefelt for at komprimere hver del på en bedre måde. Dette er, at kolonnefamilien gemmes én gang. Hvis nøglelængden, værdilængden og typen er den samme som rækken forud, udelades feltet. For øget komprimering gemmes tidsstemplet også som en forskel fra det forrige.
Bemærk, at denne funktion er slået fra som standard, da skrivning og scanning er langsommere, men flere data er cachelagret. For at aktivere denne funktion kan du indstille DATA_BLOCK_ENCODING =PREFIX | DIFF | FAST_DIFF i tabeloplysningerne.
HFil v3
HBASE-5313 indeholder et forslag til omstrukturering af HFile-layoutet for at forbedre komprimeringen:
- Pak alle nøgler sammen i begyndelsen af blokken og alle værdier sammen i slutningen af blokken. På denne måde kan du bruge to forskellige algoritmer til at komprimere nøgle og værdier.
- Komprimer tidsstempler ved hjælp af XOR med den første værdi, og brug VInt i stedet for long.
Et søjleformat eller en søjleformet kodning er også under undersøgelse. Tag et kig på AVRO-806 for et søjleformet filformat af Doug Cutting.
Som du måske kan se, er udviklingen i udviklingen at være mere bevidst om, hvad filen indeholder, for at få bedre komprimering eller bedre placeringsbevidsthed, der omsættes til mindre data at skrive/læse fra disk. Mindre I/O betyder mere hastighed!
[1] https://cloouderatemp.wpengine.com/blog/2011/01/hadoop-io-sequence-map-set-array-bloommap-files/
[2] https://clouderatemp.wpengine. com/blog/2012/06/hbase-write-path/