Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Héich Leeschtung ass ee vun de Schlësselfuerderunge wann Dir mat Big Data schafft. An der Datebelaaschtungsabteilung bei Sberbank pumpe mir bal all Transaktiounen an eis Hadoop-baséiert Data Cloud an këmmeren also mat wierklech groussen Informatiounsfloss. Natierlech si mir ëmmer op der Sich no Weeër fir d'Performance ze verbesseren, an elo wëlle mir Iech soen wéi mir et fäerdeg bruecht hunn de RegionServer HBase an den HDFS Client ze patchen, dank deem mir d'Geschwindegkeet vun de Liesoperatioune wesentlech erhéijen.
Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Wéi och ëmmer, ier Dir op d'Essenz vun de Verbesserunge weidergeet, ass et derwäert iwwer Restriktiounen ze schwätzen, déi am Prinzip net ëmgoe kënnen wann Dir op enger HDD sëtzt.

Firwat HDD a séier Random Access Liesen inkompatibel sinn
Wéi Dir wësst, HBase, a vill aner Datenbanken, späicheren Daten a Blocken vun e puer Zéng Kilobytes an der Gréisst. Par défaut ass et ongeféier 64 KB. Loosst eis elo virstellen datt mir nëmmen 100 Bytes brauchen a mir froen HBase eis dës Donnéeën mat engem bestëmmte Schlëssel ze ginn. Well d'Blockgréisst an HFiles 64 KB ass, wäert d'Ufro 640 Mol méi grouss sinn (just eng Minutt!) Wéi néideg.

Als nächst wäert d'Ufro duerch HDFS a säi Metadaten-Caching-Mechanismus goen ShortCircuitCache (wat erlaabt direkten Zougang zu Fichieren), dëst féiert zu engem liesen schonn 1 MB vun der Scheif. Allerdéngs kann dëst mat dem Parameter ugepasst ginn dfs.client.read.shortcircuit.buffer.size an a ville Fäll mécht et Sënn fir dëse Wäert ze reduzéieren, zum Beispill op 126 KB.

Loosst eis soen datt mir dëst maachen, awer zousätzlech, wa mir ufänken Daten duerch den Java API ze liesen, wéi Funktiounen wéi FileChannel.read an de Betribssystem froen déi spezifizéiert Quantitéit un Daten ze liesen, liest et "just am Fall" 2 Mol méi , d.h. 256 KB an eisem Fall. Dëst ass well Java keen einfache Wee huet fir de FADV_RANDOM Fändel ze setzen fir dëst Verhalen ze vermeiden.

Als Resultat, fir eis 100 Bytes ze kréien, gëtt 2600 Mol méi ënnert der Hood gelies. Et géif schéngen datt d'Léisung offensichtlech ass, loosst eis d'Blockgréisst op e Kilobyte reduzéieren, de genannte Fändel setzen a grouss Erliichterungsbeschleunigung gewannen. Awer de Problem ass datt andeems mir d'Blockgréisst ëm 2 Mol reduzéieren, mir reduzéieren och d'Zuel vun de Bytes, déi pro Zäitunitéit gelies ginn, ëm 2 Mol.

E puer Gewënn aus der Astellung vum FADV_RANDOM Fändel ka kritt ginn, awer nëmme mat héijer Multi-Threading a mat enger Blockgréisst vun 128 KB, awer dëst ass maximal e puer Zéng Prozent:

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Tester goufen op 100 Dateien duerchgefouert, all 1 GB an der Gréisst a läit op 10 HDDs.

Loosst eis berechnen op wat mir am Prinzip mat dëser Geschwindegkeet zielen kënnen:
Loosst eis soen, mir liesen aus 10 Placken mat enger Geschwindegkeet vun 280 MB/s, d.h. 3 Millioune mol 100 Bytes. Awer wéi mir eis erënneren, sinn d'Donnéeën déi mir brauchen 2600 Mol manner wéi dat wat gelies gëtt. Mir deelen also 3 Milliounen op 2600 a kréien 1100 records pro Sekonn.

Depressiv, ass et net? Dat ass d'Natur Zoufälleg Zougang Zougang zu Daten op der HDD - onofhängeg vun der Blockgréisst. Dëst ass déi kierperlech Limit vum zoufälleg Zougang a keng Datebank kann ënner esou Bedéngungen méi ausdrécken.

Wéi erreechen dann Datenbanken vill méi héich Geschwindegkeet? Fir dës Fro ze beäntweren, kucke mer wat an der folgender Bild geschitt:

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Hei gesi mer datt fir déi éischt puer Minutten d'Vitesse wierklech ongeféier dausend Rekorder pro Sekonn ass. Wéi och ëmmer, wéinst der Tatsaach, datt vill méi gelies gëtt wéi gefrot gouf, kommen d'Donnéeën am Buff/Cache vum Betribssystem (Linux) an d'Geschwindegkeet erop op méi anstänneg 60 Tausend pro Sekonn

Also, weider wäerte mir beschleunegen Zougang nëmmen zu den Daten déi am OS Cache sinn oder an SSD / NVMe Späichergeräter mat vergläichbarer Zougangsgeschwindegkeet sinn.

An eisem Fall maache mir Tester op enger Bank vu 4 Serveren, déi jidderee wéi follegt gelueden ass:

CPU: Xeon E5-2680 v4 @ 2.40GHz 64 thread.
Erënnerung: 730 GB.
Java Versioun: 1.8.0_111

An hei ass de Schlësselpunkt d'Quantitéit un Daten an den Dëscher déi gelies musse ginn. D'Tatsaach ass datt wann Dir Daten aus enger Tabell liest déi ganz am HBase Cache plazéiert ass, da wäert et net emol kommen aus dem Buff / Cache vum Betribssystem ze liesen. Well HBase als Standard 40% vun der Erënnerung un eng Struktur genannt BlockCache verdeelt. Wesentlech ass dëst e ConcurrentHashMap, wou de Schlëssel den Dateinumm + Offset vum Block ass, an de Wäert ass déi aktuell Donnéeën bei dëser Offset.

Also, wann Dir nëmmen aus dëser Struktur liesen, mir mir gesinn excellent Vitesse, wéi eng Millioun Ufroen pro Sekonn. Awer loosst eis virstellen datt mir Honnerte vu Gigabytes Erënnerung net nëmme fir Datebankbedürfnisser kënnen ausdeelen, well et vill aner nëtzlech Saachen op dëse Server lafen.

Zum Beispill, an eisem Fall ass de Volume vum BlockCache op engem RS ongeféier 12 GB. Mir hunn zwee RS op engem Node gelant, d.h. 96 GB gi fir BlockCache op all Noden zougewisen. An et gëtt vill Mol méi Daten, zum Beispill, loosst et 4 Dëscher sinn, all 130 Regiounen, an deenen Dateien 800 MB grouss sinn, kompriméiert duerch FAST_DIFF, d.h. insgesamt 410 GB (dëst ass reng Daten, dh ouni de Replikatiounsfaktor ze berücksichtegen).

Also ass BlockCache nëmmen ongeféier 23% vum Gesamtdatenvolumen an dëst ass vill méi no un déi reell Bedéngungen vun deem wat BigData genannt gëtt. An hei fänkt de Spaass un - well selbstverständlech, wat manner Cache Hits, desto méi schlecht ass d'Leeschtung. Nodeems Dir alles verpasst, musst Dir vill Aarbecht maachen - d.h. erofgoen op Uruff System Funktiounen. Dëst kann awer net vermeit ginn, also loosst eis e ganz aneren Aspekt kucken - wat geschitt mat den Daten am Cache?

Loosst eis d'Situatioun vereinfachen an huelen un datt mir e Cache hunn deen nëmmen 1 Objet passt. Hei ass e Beispill vu wat geschitt wa mir probéieren mat engem Datevolumen ze schaffen 3 Mol méi grouss wéi de Cache, mir mussen:

1. Plaz Spär 1 am Cache
2. Ewechzehuelen Spär 1 aus Cache
3. Plaz Spär 2 am Cache
4. Ewechzehuelen Spär 2 aus Cache
5. Plaz Spär 3 am Cache

5 Aktiounen ofgeschloss! Wéi och ëmmer, dës Situatioun kann net normal genannt ginn; Tatsächlech forcéiere mir HBase eng Rëtsch komplett nëtzlos Aarbecht ze maachen. Et liest dauernd Daten aus dem OS Cache, placéiert se an BlockCache, just fir se bal direkt eraus ze geheien well en neien Deel vun den Donnéeën ukomm ass. D'Animatioun am Ufank vum Post weist d'Essenz vum Problem - Garbage Collector geet aus Skala, d'Atmosphär erwiermt, kleng Greta a wäitem a waarme Schweden gëtt opgeregt. A mir IT Leit hunn et wierklech net gär wann Kanner traureg sinn, also fänken mir un ze denken wat mir doriwwer maache kënnen.

Wat wann Dir net all Block an de Cache setzt, awer nëmmen e gewësse Prozentsaz vun hinnen, sou datt de Cache net iwwerflësseg ass? Loosst eis ufänken einfach nëmmen e puer Zeilen Code un den Ufank vun der Funktioun ze addéieren fir Daten an BlockCache ze setzen:

  public void cacheBlock(BlockCacheKey cacheKey, Cacheable buf, boolean inMemory) {
    if (cacheDataBlockPercent != 100 && buf.getBlockType().isData()) {
      if (cacheKey.getOffset() % 100 >= cacheDataBlockPercent) {
        return;
      }
    }
...

De Punkt hei ass déi folgend: Offset ass d'Positioun vum Block an der Datei a seng lescht Ziffere sinn zoufälleg a gläichméisseg vun 00 op 99 verdeelt. Dofir sprange mir nëmmen déi, déi an de Beräich falen, déi mir brauchen.

Zum Beispill, set cacheDataBlockPercent = 20 a kuckt wat geschitt:

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

D'Resultat ass evident. An de Grafiken hei drënner gëtt et kloer firwat sou eng Beschleunegung geschitt ass - mir spuere vill GC Ressourcen ouni déi Sisyphean Aarbecht ze maachen fir Daten am Cache ze setzen nëmmen fir se direkt an d'Drain vun de Marshënn ze geheien:

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Zur selwechter Zäit erhéicht d'CPU Notzung, awer ass vill manner wéi d'Produktivitéit:

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Et ass och derwäert ze notéieren datt d'Blocker, déi am BlockCache gespäichert sinn, anescht sinn. Déi meescht, ongeféier 95%, sinn Daten selwer. An de Rescht ass Metadaten, wéi Bloom Filteren oder LEAF_INDEX an asw.. Dës Donnéeën sinn net genuch, awer et ass ganz nëtzlech, well ier Dir direkt op d'Donnéeën zougitt, dréit HBase sech op d'Meta fir ze verstoen ob et néideg ass hei weider ze sichen an, wa jo, wou genau de Block vun Interesse läit.

Dofir gesi mir am Code e Scheckkonditioun buf.getBlockType().isData() an dank dëser Meta wäerte mir et op alle Fall am Cache loossen.

Loosst eis elo d'Belaaschtung erhéijen an d'Feature liicht an enger Kéier zéien. Am éischten Test hu mir de Cutoff Prozentsaz = 20 gemaach a BlockCache war liicht ënnerbenotzt. Loosst eis et elo op 23% setzen an all 100 Minutten 5 Threads addéieren fir ze kucken a wéi engem Punkt Sättigung geschitt:

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Hei gesi mir datt d'Originalversioun bal direkt op d'Plafong op ongeféier 100 Tausend Ufroen pro Sekonn trefft. Wou de Patch eng Beschleunegung vu bis zu 300 dausend gëtt. Zur selwechter Zäit ass et kloer datt weider Beschleunegung net méi sou "gratis" ass; CPU Notzung ass och erop.

Wéi och ëmmer, dëst ass net eng ganz elegant Léisung, well mir net am Viraus wësse wéi ee Prozentsaz vu Blocks musse cache ginn, et hänkt vum Lastprofil of. Dofir gouf e Mechanismus ëmgesat fir dësen Parameter automatesch unzepassen ofhängeg vun der Aktivitéit vu Liesoperatiounen.

Dräi Optiounen goufen derbäigesat fir dëst ze kontrolléieren:

hbase.lru.cache.heavy.eviction.count.limit - stellt wéivill Mol de Prozess fir Daten aus dem Cache ze läschen soll lafen ier mir ufänken d'Optimiséierung ze benotzen (dh Spären ze sprangen). Par défaut ass et gläich wéi MAX_INT = 2147483647 a bedeit tatsächlech datt d'Feature ni mat dësem Wäert ufänkt ze schaffen. Well d'Eviction Prozess fänkt all 5 - 10 Sekonnen (et hänkt op der Laascht) an 2147483647 * 10 / 60 / 60 / 24 / 365 = 680 Joer. Wéi och ëmmer, mir kënnen dëse Parameter op 0 setzen an d'Feature direkt nom Start funktionnéieren.

Wéi och ëmmer, et gëtt och eng Notzlaascht an dësem Parameter. Wann eis Belaaschtung esou ass, datt kuerzfristeg Liesungen (z.b. am Dag) a laangfristeg Liesungen (an der Nuecht) dauernd ofwiesselnd sinn, da kënne mir sécher sinn datt d'Feature nëmmen ageschalt gëtt wann laang Liesoperatiounen amgaang sinn.

Zum Beispill wësse mir datt kuerzfristeg Liesungen normalerweis ongeféier 1 Minutt daueren. Et ass net néideg fir Blocken ze werfen, de Cache wäert keng Zäit hunn ze veränneren an da kënne mir dëse Parameter gläich wéi zum Beispill 10 setzen. Begrëff aktive Liesen huet ugefaang, d.h. an 100 Sekonnen. Also, wa mir eng kuerzfristeg Liesung hunn, da ginn all Block an de Cache a wäerte verfügbar sinn (ausser déi, déi vum Standardalgorithmus evictéiert ginn). A wa mir laangfristeg Liesungen maachen, ass d'Feature ageschalt a mir hätte vill méi héich Leeschtung.

hbase.lru.cache.heavy.eviction.mb.size.limit - setzt wéivill Megabytes mir gären am Cache placéieren (an, natierlech, evict) an 10 Sekonnen. D'Feature wäert probéieren dëse Wäert z'erreechen an z'erhalen. De Punkt ass dëst: wa mir Gigabytes an de Cache drécken, da musse mir Gigabytes evictéieren, an dëst, wéi mir uewen gesinn, ass ganz deier. Wéi och ëmmer, Dir sollt net probéieren et ze kleng ze setzen, well dëst wäert de Block Skip Modus ze fréi ausgoen. Fir mächteg Serveren (ongeféier 20-40 kierperlech Kären) ass et optimal fir ongeféier 300-400 MB ze setzen. Fir d'Mëttelklass (~ 10 Kären) 200-300 MB. Fir schwaach Systemer (2-5 Kär) 50-100 MB kann normal ginn (net op dës getest).

Loosst eis kucken wéi dëst funktionnéiert: loosst eis soen datt mir hbase.lru.cache.heavy.eviction.mb.size.limit = 500 setzen, et gëtt eng Zort Belaaschtung (Liesen) an dann all ~10 Sekonnen berechent wéivill Bytes waren evictéiert mat der Formel:

Overhead = Freed Bytes Zomm (MB) * 100 / Limit (MB) - 100;

Wann tatsächlech 2000 MB evictéiert goufen, dann ass Overhead gläich wéi:

2000 * 100 / 500 - 100 = 300%

D'Algorithmen probéieren net méi wéi e puer Zéng Prozent z'erhalen, sou datt d'Feature de Prozentsaz vun de cachéierte Blocken reduzéiert, an doduerch en Autotuningmechanismus implementéiert.

Wéi och ëmmer, wann d'Laascht fällt, loosst eis soen datt nëmmen 200 MB evictéiert ginn an Overhead gëtt negativ (de sougenannte Overshooting):

200 * 100 / 500 - 100 = -60%

Am Géigendeel, d'Fonktioun wäert de Prozentsaz vun de cachéierte Blocken erhéijen bis Overhead positiv gëtt.

Drënner ass e Beispill vu wéi dëst op realen Daten ausgesäit. Et ass net néideg ze probéieren 0% z'erreechen, et ass onméiglech. Et ass ganz gutt wann et ongeféier 30 - 100% ass, dëst hëlleft virzäitegen Austrëtt aus dem Optimiséierungsmodus während kuerzfristeg Iwwerschwemmungen ze vermeiden.

hbase.lru.cache.heavy.eviction.overhead.coefficient - setzt wéi séier mir d'Resultat wëllen kréien. Wa mir sécher wëssen datt eis Liesunge meeschtens laang sinn an net wëllen waarden, kënne mir dëst Verhältnis erhéijen a méi séier héich Leeschtung kréien.

Zum Beispill setze mir dëse Koeffizient = 0.01. Dëst bedeit datt Overhead (kuckt hei uewen) mat dëser Zuel multiplizéiert gëtt duerch dat resultéierend Resultat an de Prozentsaz vun de Cache-Blöcke gëtt reduzéiert. Loosst eis unhuelen datt Overhead = 300% a Koeffizient = 0.01, da gëtt de Prozentsaz vun de cacheblocken ëm 3% reduzéiert.

Eng ähnlech "Backpressure" Logik gëtt och fir negativ Overhead (Overshoot) Wäerter implementéiert. Zënter kuerzfristeg Schwankungen am Volume vu Liesen an Evictioune sinn ëmmer méiglech, dëse Mechanismus erlaabt Iech virzäitegen Austrëtt aus dem Optimiséierungsmodus ze vermeiden. Backpressure huet eng ëmgedréint Logik: wat méi staark d'Iwwerschoss ass, wat méi Blocks cache sinn.

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Ëmsetzung Code

        LruBlockCache cache = this.cache.get();
        if (cache == null) {
          break;
        }
        freedSumMb += cache.evict()/1024/1024;
        /*
        * Sometimes we are reading more data than can fit into BlockCache
        * and it is the cause a high rate of evictions.
        * This in turn leads to heavy Garbage Collector works.
        * So a lot of blocks put into BlockCache but never read,
        * but spending a lot of CPU resources.
        * Here we will analyze how many bytes were freed and decide
        * decide whether the time has come to reduce amount of caching blocks.
        * It help avoid put too many blocks into BlockCache
        * when evict() works very active and save CPU for other jobs.
        * More delails: https://issues.apache.org/jira/browse/HBASE-23887
        */

        // First of all we have to control how much time
        // has passed since previuos evict() was launched
        // This is should be almost the same time (+/- 10s)
        // because we get comparable volumes of freed bytes each time.
        // 10s because this is default period to run evict() (see above this.wait)
        long stopTime = System.currentTimeMillis();
        if ((stopTime - startTime) > 1000 * 10 - 1) {
          // Here we have to calc what situation we have got.
          // We have the limit "hbase.lru.cache.heavy.eviction.bytes.size.limit"
          // and can calculte overhead on it.
          // We will use this information to decide,
          // how to change percent of caching blocks.
          freedDataOverheadPercent =
            (int) (freedSumMb * 100 / cache.heavyEvictionMbSizeLimit) - 100;
          if (freedSumMb > cache.heavyEvictionMbSizeLimit) {
            // Now we are in the situation when we are above the limit
            // But maybe we are going to ignore it because it will end quite soon
            heavyEvictionCount++;
            if (heavyEvictionCount > cache.heavyEvictionCountLimit) {
              // It is going for a long time and we have to reduce of caching
              // blocks now. So we calculate here how many blocks we want to skip.
              // It depends on:
             // 1. Overhead - if overhead is big we could more aggressive
              // reducing amount of caching blocks.
              // 2. How fast we want to get the result. If we know that our
              // heavy reading for a long time, we don't want to wait and can
              // increase the coefficient and get good performance quite soon.
              // But if we don't sure we can do it slowly and it could prevent
              // premature exit from this mode. So, when the coefficient is
              // higher we can get better performance when heavy reading is stable.
              // But when reading is changing we can adjust to it and set
              // the coefficient to lower value.
              int change =
                (int) (freedDataOverheadPercent * cache.heavyEvictionOverheadCoefficient);
              // But practice shows that 15% of reducing is quite enough.
              // We are not greedy (it could lead to premature exit).
              change = Math.min(15, change);
              change = Math.max(0, change); // I think it will never happen but check for sure
              // So this is the key point, here we are reducing % of caching blocks
              cache.cacheDataBlockPercent -= change;
              // If we go down too deep we have to stop here, 1% any way should be.
              cache.cacheDataBlockPercent = Math.max(1, cache.cacheDataBlockPercent);
            }
          } else {
            // Well, we have got overshooting.
            // Mayby it is just short-term fluctuation and we can stay in this mode.
            // It help avoid permature exit during short-term fluctuation.
            // If overshooting less than 90%, we will try to increase the percent of
            // caching blocks and hope it is enough.
            if (freedSumMb >= cache.heavyEvictionMbSizeLimit * 0.1) {
              // Simple logic: more overshooting - more caching blocks (backpressure)
              int change = (int) (-freedDataOverheadPercent * 0.1 + 1);
              cache.cacheDataBlockPercent += change;
              // But it can't be more then 100%, so check it.
              cache.cacheDataBlockPercent = Math.min(100, cache.cacheDataBlockPercent);
            } else {
              // Looks like heavy reading is over.
              // Just exit form this mode.
              heavyEvictionCount = 0;
              cache.cacheDataBlockPercent = 100;
            }
          }
          LOG.info("BlockCache evicted (MB): {}, overhead (%): {}, " +
            "heavy eviction counter: {}, " +
            "current caching DataBlock (%): {}",
            freedSumMb, freedDataOverheadPercent,
            heavyEvictionCount, cache.cacheDataBlockPercent);

          freedSumMb = 0;
          startTime = stopTime;
       }

Loosst eis elo all dëst mat engem richtege Beispill kucken. Mir hunn de folgenden Testskript:

  1. Loosst eis ufänken Scan ze maachen (25 Threads, Batch = 100)
  2. No 5 Minutten addéiere mer Multi-Get (25 Threads, Batch = 100)
  3. No 5 Minutten, schalt Multi-gets aus (nëmme Scan bleift erëm)

Mir maachen zwee Lafen, éischt hbase.lru.cache.heavy.eviction.count.limit = 10000 (wat eigentlech d'Fonktioun deaktivéiert), an dann Limite setzen = 0 (aktivéiert et).

An de Logbicher hei drënner gesi mir wéi d'Feature ageschalt ass a Reset Overshooting op 14-71%. Vun Zäit zu Zäit hëlt d'Laascht erof, wat de Backpressure ausschalt an HBase Cache méi Blocks erëm.

Log RegionServer
evicted (MB): 0, Verhältnis 0.0, Overhead (%): -100, schwéier Eviction Konter: 0, aktuell Caching DataBlock (%): 100
evicted (MB): 0, Verhältnis 0.0, Overhead (%): -100, schwéier Eviction Konter: 0, aktuell Caching DataBlock (%): 100
evicted (MB): 2170, Verhältnis 1.09, Overhead (%): 985, schwéier Eviction Konter: 1, aktuell Caching DataBlock (%): 91 < Start
evictéiert (MB): 3763, Verhältnis 1.08, Overhead (%): 1781, schwéier Eviction Konter: 2, aktuell Caching DataBlock (%): 76
evictéiert (MB): 3306, Verhältnis 1.07, Overhead (%): 1553, schwéier Eviction Konter: 3, aktuell Caching DataBlock (%): 61
evictéiert (MB): 2508, Verhältnis 1.06, Overhead (%): 1154, schwéier Eviction Konter: 4, aktuell Caching DataBlock (%): 50
evictéiert (MB): 1824, Verhältnis 1.04, Overhead (%): 812, schwéier Eviction Konter: 5, aktuell Caching DataBlock (%): 42
evictéiert (MB): 1482, Verhältnis 1.03, Overhead (%): 641, schwéier Eviction Konter: 6, aktuell Caching DataBlock (%): 36
evictéiert (MB): 1140, Verhältnis 1.01, Overhead (%): 470, schwéier Eviction Konter: 7, aktuell Caching DataBlock (%): 32
evictéiert (MB): 913, Verhältnis 1.0, Overhead (%): 356, schwéier Eviction Konter: 8, aktuell Caching DataBlock (%): 29
evictéiert (MB): 912, Verhältnis 0.89, Overhead (%): 356, schwéier Eviction Konter: 9, aktuell Caching DataBlock (%): 26
evictéiert (MB): 684, Verhältnis 0.76, Overhead (%): 242, schwéier Eviction Konter: 10, aktuell Caching DataBlock (%): 24
evictéiert (MB): 684, Verhältnis 0.61, Overhead (%): 242, schwéier Eviction Konter: 11, aktuell Caching DataBlock (%): 22
evictéiert (MB): 456, Verhältnis 0.51, Overhead (%): 128, schwéier Eviction Konter: 12, aktuell Caching DataBlock (%): 21
evictéiert (MB): 456, Verhältnis 0.42, Overhead (%): 128, schwéier Eviction Konter: 13, aktuell Caching DataBlock (%): 20
evictéiert (MB): 456, Verhältnis 0.33, Overhead (%): 128, schwéier Eviction Konter: 14, aktuell Caching DataBlock (%): 19
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 15, aktuell Caching DataBlock (%): 19
evictéiert (MB): 342, Verhältnis 0.32, Overhead (%): 71, schwéier Eviction Konter: 16, aktuell Caching DataBlock (%): 19
evictéiert (MB): 342, Verhältnis 0.31, Overhead (%): 71, schwéier Eviction Konter: 17, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.3, Overhead (%): 14, schwéier Eviction Konter: 18, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.29, Overhead (%): 14, schwéier Eviction Konter: 19, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.27, Overhead (%): 14, schwéier Eviction Konter: 20, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.25, Overhead (%): 14, schwéier Eviction Konter: 21, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.24, Overhead (%): 14, schwéier Eviction Konter: 22, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.22, Overhead (%): 14, schwéier Eviction Konter: 23, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.21, Overhead (%): 14, schwéier Eviction Konter: 24, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.2, Overhead (%): 14, schwéier Eviction Konter: 25, aktuell Caching DataBlock (%): 19
evictéiert (MB): 228, Verhältnis 0.17, Overhead (%): 14, schwéier Eviction Konter: 26, aktuell Caching DataBlock (%): 19
evicted (MB): 456, Verhältnis 0.17, Overhead (%): 128, schwéier Eviction Konter: 27, aktuell Caching DataBlock (%): 18 < dobäi kritt (awer Dësch déi selwecht)
evictéiert (MB): 456, Verhältnis 0.15, Overhead (%): 128, schwéier Eviction Konter: 28, aktuell Caching DataBlock (%): 17
evictéiert (MB): 342, Verhältnis 0.13, Overhead (%): 71, schwéier Eviction Konter: 29, aktuell Caching DataBlock (%): 17
evictéiert (MB): 342, Verhältnis 0.11, Overhead (%): 71, schwéier Eviction Konter: 30, aktuell Caching DataBlock (%): 17
evictéiert (MB): 342, Verhältnis 0.09, Overhead (%): 71, schwéier Eviction Konter: 31, aktuell Caching DataBlock (%): 17
evictéiert (MB): 228, Verhältnis 0.08, Overhead (%): 14, schwéier Eviction Konter: 32, aktuell Caching DataBlock (%): 17
evictéiert (MB): 228, Verhältnis 0.07, Overhead (%): 14, schwéier Eviction Konter: 33, aktuell Caching DataBlock (%): 17
evictéiert (MB): 228, Verhältnis 0.06, Overhead (%): 14, schwéier Eviction Konter: 34, aktuell Caching DataBlock (%): 17
evictéiert (MB): 228, Verhältnis 0.05, Overhead (%): 14, schwéier Eviction Konter: 35, aktuell Caching DataBlock (%): 17
evictéiert (MB): 228, Verhältnis 0.05, Overhead (%): 14, schwéier Eviction Konter: 36, aktuell Caching DataBlock (%): 17
evictéiert (MB): 228, Verhältnis 0.04, Overhead (%): 14, schwéier Eviction Konter: 37, aktuell Caching DataBlock (%): 17
evicted (MB): 109, Verhältnis 0.04, Overhead (%): -46, schwéier Eviction Konter: 37, aktuell Caching DataBlock (%): 22 < Réckdrock
evictéiert (MB): 798, Verhältnis 0.24, Overhead (%): 299, schwéier Eviction Konter: 38, aktuell Caching DataBlock (%): 20
evictéiert (MB): 798, Verhältnis 0.29, Overhead (%): 299, schwéier Eviction Konter: 39, aktuell Caching DataBlock (%): 18
evictéiert (MB): 570, Verhältnis 0.27, Overhead (%): 185, schwéier Eviction Konter: 40, aktuell Caching DataBlock (%): 17
evictéiert (MB): 456, Verhältnis 0.22, Overhead (%): 128, schwéier Eviction Konter: 41, aktuell Caching DataBlock (%): 16
evictéiert (MB): 342, Verhältnis 0.16, Overhead (%): 71, schwéier Eviction Konter: 42, aktuell Caching DataBlock (%): 16
evictéiert (MB): 342, Verhältnis 0.11, Overhead (%): 71, schwéier Eviction Konter: 43, aktuell Caching DataBlock (%): 16
evictéiert (MB): 228, Verhältnis 0.09, Overhead (%): 14, schwéier Eviction Konter: 44, aktuell Caching DataBlock (%): 16
evictéiert (MB): 228, Verhältnis 0.07, Overhead (%): 14, schwéier Eviction Konter: 45, aktuell Caching DataBlock (%): 16
evictéiert (MB): 228, Verhältnis 0.05, Overhead (%): 14, schwéier Eviction Konter: 46, aktuell Caching DataBlock (%): 16
evictéiert (MB): 222, Verhältnis 0.04, Overhead (%): 11, schwéier Eviction Konter: 47, aktuell Caching DataBlock (%): 16
evicted (MB): 104, Verhältnis 0.03, Overhead (%): -48, schwéier Eviction Konter: 47, aktuell Caching DataBlock (%): 21 < Ënnerbriechung kritt
evictéiert (MB): 684, Verhältnis 0.2, Overhead (%): 242, schwéier Eviction Konter: 48, aktuell Caching DataBlock (%): 19
evictéiert (MB): 570, Verhältnis 0.23, Overhead (%): 185, schwéier Eviction Konter: 49, aktuell Caching DataBlock (%): 18
evictéiert (MB): 342, Verhältnis 0.22, Overhead (%): 71, schwéier Eviction Konter: 50, aktuell Caching DataBlock (%): 18
evictéiert (MB): 228, Verhältnis 0.21, Overhead (%): 14, schwéier Eviction Konter: 51, aktuell Caching DataBlock (%): 18
evictéiert (MB): 228, Verhältnis 0.2, Overhead (%): 14, schwéier Eviction Konter: 52, aktuell Caching DataBlock (%): 18
evictéiert (MB): 228, Verhältnis 0.18, Overhead (%): 14, schwéier Eviction Konter: 53, aktuell Caching DataBlock (%): 18
evictéiert (MB): 228, Verhältnis 0.16, Overhead (%): 14, schwéier Eviction Konter: 54, aktuell Caching DataBlock (%): 18
evictéiert (MB): 228, Verhältnis 0.14, Overhead (%): 14, schwéier Eviction Konter: 55, aktuell Caching DataBlock (%): 18
evicted (MB): 112, Verhältnis 0.14, Overhead (%): -44, schwéier Eviction Konter: 55, aktuell Caching DataBlock (%): 23 < Réckdrock
evictéiert (MB): 456, Verhältnis 0.26, Overhead (%): 128, schwéier Eviction Konter: 56, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.31, Overhead (%): 71, schwéier Eviction Konter: 57, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 58, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 59, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 60, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 61, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 62, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 63, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.32, Overhead (%): 71, schwéier Eviction Konter: 64, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 65, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 66, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.32, Overhead (%): 71, schwéier Eviction Konter: 67, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 68, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.32, Overhead (%): 71, schwéier Eviction Konter: 69, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.32, Overhead (%): 71, schwéier Eviction Konter: 70, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 71, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 72, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 73, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 74, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 75, aktuell Caching DataBlock (%): 22
evictéiert (MB): 342, Verhältnis 0.33, Overhead (%): 71, schwéier Eviction Konter: 76, aktuell Caching DataBlock (%): 22
evicted (MB): 21, Verhältnis 0.33, Overhead (%): -90, schwéier Eviction Konter: 76, aktuell Caching DataBlock (%): 32
evicted (MB): 0, Verhältnis 0.0, Overhead (%): -100, schwéier Eviction Konter: 0, aktuell Caching DataBlock (%): 100
evicted (MB): 0, Verhältnis 0.0, Overhead (%): -100, schwéier Eviction Konter: 0, aktuell Caching DataBlock (%): 100

D'Scans waren néideg fir dee selwechte Prozess a Form vun enger Grafik vun der Bezéiung tëscht zwee Cache-Sektiounen ze weisen - eenzel (wou Blocken déi ni virdru gefrot goufen) a Multi (Daten "gefrot" op d'mannst eemol sinn hei gespäichert):

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

A schliisslech, wéi gesäit d'Operatioun vun de Parameteren a Form vun enger Grafik aus. Zum Verglach war de Cache am Ufank komplett ausgeschalt, duerno gouf HBase mat Cache gestart an de Start vun der Optimisatiounsaarbecht ëm 5 Minutten (30 Eviction Zyklen) verzögert.

Voll Code kann an Pull Request fonnt ginn HBASE 23887 op github.

Wéi och ëmmer, 300 Tausend Liesungen pro Sekonn ass net alles wat op dëser Hardware ënner dëse Konditiounen erreecht ka ginn. D'Tatsaach ass datt wann Dir Zougang zu Daten iwwer HDFS braucht, gëtt de ShortCircuitCache (nodréiglech SSC bezeechent) Mechanismus benotzt, wat Iech erlaabt direkt op d'Donnéeën ze kommen, an d'Netzwierkinteraktiounen vermeiden.

Profiling huet gewisen, datt obwuel dëse Mechanismus e grousse Gewënn gëtt, et och iergendwann e Flaschenhals gëtt, well bal all schwéier Operatiounen an enger Spär geschéien, wat zu enger Spär déi meescht vun der Zäit féiert.

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Nodeems mir dëst gemierkt hunn, hu mir gemierkt datt de Problem kann ëmgoen andeems en eng Rei vun onofhängege SSCs erstellt:

private final ShortCircuitCache[] shortCircuitCache;
...
shortCircuitCache = new ShortCircuitCache[this.clientShortCircuitNum];
for (int i = 0; i < this.clientShortCircuitNum; i++)
  this.shortCircuitCache[i] = new ShortCircuitCache(…);

An da schafft mat hinnen, ausser Kräizungen och op der leschter Offset Ziffer:

public ShortCircuitCache getShortCircuitCache(long idx) {
    return shortCircuitCache[(int) (idx % clientShortCircuitNum)];
}

Elo kënnt Dir ufänken ze testen. Fir dëst ze maachen, liesen mir Dateien aus HDFS mat enger einfacher Multi-threaded Applikatioun. Setzt d'Parameteren:

conf.set("dfs.client.read.shortcircuit", "true");
conf.set("dfs.client.read.shortcircuit.buffer.size", "65536"); // по дефолту = 1 МБ и это сильно замедляет чтение, поэтому лучше привести в соответствие к реальным нуждам
conf.set("dfs.client.short.circuit.num", num); // от 1 до 10

A liest just d'Dateien:

FSDataInputStream in = fileSystem.open(path);
for (int i = 0; i < count; i++) {
    position += 65536;
    if (position > 900000000)
        position = 0L;
    int res = in.read(position, byteBuffer, 0, 65536);
}

Dëse Code gëtt an getrennten Threads ausgefouert a mir wäerten d'Zuel vu gläichzäiteg gelies Dateien erhéijen (vu 10 op 200 - horizontal Achs) an d'Zuel vun de Cache (vun 1 op 10 - Grafiken). Déi vertikal Achs weist d'Beschleunigung déi aus enger Erhéijung vum SSC relativ zum Fall resultéiert wann et nëmmen ee Cache gëtt.

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Wéi liesen d'Grafik: D'Ausféierungszäit fir 100 Tausend Liesungen an 64 KB Blocken mat engem Cache erfuerdert 78 Sekonnen. Woubäi et mat 5 Cache dauert 16 Sekonnen. Déi. et gëtt eng Beschleunegung vu ~5 Mol. Wéi aus der Grafik ze gesinn ass, ass den Effekt net ganz opfälleg fir eng kleng Unzuel vu parallele Liesungen, et fänkt un eng merkbar Roll ze spillen wann et méi wéi 50 thread Liesungen ass. an uewen gëtt eng däitlech méi kleng Leeschtung Erhéijung.

Notiz 1: Well d'Testresultater zimlech liichtflüchteg sinn (kuckt hei ënnen), goufen 3 Lafen duerchgefouert an déi resultéierend Wäerter goufen duerchschnëttlech.

Notiz 2: D'Leeschtungsgewënn vum Zoufallszougang konfiguréieren ass d'selwecht, obwuel den Zougang selwer liicht méi lues ass.

Wéi och ëmmer, et ass néideg ze klären datt, am Géigesaz zum Fall mat HBase, dës Beschleunegung net ëmmer gratis ass. Hei "spären" mir d'Kapazitéit vun der CPU fir méi Aarbecht ze maachen, anstatt op Sperren ze hänken.

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Hei kënnt Dir beobachten datt allgemeng eng Erhéijung vun der Unzuel vun de Cache eng ongeféier proportional Erhéijung vun der CPU Notzung gëtt. Allerdéngs ginn et e bësse méi gewënnt Kombinatioune.

Zum Beispill, loosst eis e méi genau kucken op d'Astellung SSC = 3. D'Erhéijung vun der Leeschtung op der Streck ass ongeféier 3.3 Mol. Drënner sinn d'Resultater vun allen dräi separat Lafen.

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Wärend de CPU Konsum ëm ongeféier 2.8 Mol eropgeet. Den Ënnerscheed ass net ganz grouss, awer déi kleng Greta ass scho frou an huet vläicht Zäit fir an d'Schoul ze goen a Lektioune ze huelen.

Also wäert dëst e positiven Effekt fir all Tool hunn dat e bulk Zougang zu HDFS benotzt (zum Beispill Spark, etc.), virausgesat datt den Applikatiounscode liicht ass (dh de Plug ass op der HDFS Client Säit) an et gëtt gratis CPU Kraaft . Fir z'iwwerpréiwen, loosst eis testen wéi en Effekt déi kombinéiert Notzung vun der BlockCache Optimiséierung an der SSC Tuning fir d'Liesen vun HBase wäert hunn.

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Et kann gesi ginn datt ënner sou Bedéngungen den Effekt net sou grouss ass wéi an raffinéierten Tester (liesen ouni Veraarbechtung), awer et ass ganz méiglech eng zousätzlech 80K hei auszedrécken. Zesumme bidden béid Optimisatiounen bis zu 4x Geschwindegkeet.

E PR gouf och fir dës Optimisatioun gemaach [HDFS-15202], déi fusionéiert gouf an dës Funktionalitéit wäert an zukünfteg Verëffentlechungen verfügbar sinn.

A schlussendlech war et interessant d'Liesleistung vun enger ähnlecher breetkolonn Datebank ze vergläichen, Cassandra an HBase.

Fir dëst ze maachen, hu mir Instanzen vum Standard YCSB Lasttest Utility vun zwee Hosten lancéiert (am Ganzen 800 Threads). Op der Server Säit - 4 Instanzen vu RegionServer a Cassandra op 4 Hosten (net déi wou d'Clientë lafen, fir hiren Afloss ze vermeiden). Liesungen koumen aus Dëscher vun der Gréisst:

HBase - 300 GB op HDFS (100 GB reng Daten)

Cassandra - 250 GB (Replikatiounsfaktor = 3)

Déi. de Volume war ongeféier d'selwecht (an HBase e bësse méi).

HBase Parameteren:

dfs.client.short.circuit.num = 5 (HDFS Client Optimisatioun)

hbase.lru.cache.heavy.eviction.count.limit = 30 - dat heescht datt de Patch ufänkt no 30 Evictiounen (~ 5 Minutten) ze schaffen

hbase.lru.cache.heavy.eviction.mb.size.limit = 300 - Zilvolumen vum Caching an Eviction

YCSB Logbicher goufen parséiert a kompiléiert an Excel Grafike:

Wéi d'Liesgeschwindegkeet vun HBase bis zu 3 Mol erhéijen a vun HDFS bis zu 5 Mol

Wéi Dir gesitt, maachen dës Optimisatiounen et méiglech d'Performance vun dësen Datenbanken ënner dëse Konditiounen ze vergläichen an 450 Tausend Liesungen pro Sekonn z'erreechen.

Mir hoffen, datt dës Informatioun fir een nëtzlech ka sinn während dem spannende Kampf fir Produktivitéit.

Source: will.com

Setzt e Commentaire