Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Mae perfformiad uchel yn un o'r gofynion allweddol wrth weithio gyda data mawr. Yn yr adran llwytho data yn Sberbank, rydym yn pwmpio bron pob trafodiad i'n Cwmwl Data sy'n seiliedig ar Hadoop ac felly'n delio â llifoedd gwybodaeth mawr iawn. Yn naturiol, rydym bob amser yn chwilio am ffyrdd o wella perfformiad, ac yn awr rydym am ddweud wrthych sut y gwnaethom lwyddo i glytio RegionServer HBase a'r cleient HDFS, diolch i hynny roeddem yn gallu cynyddu cyflymder gweithrediadau darllen yn sylweddol.
Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Fodd bynnag, cyn symud ymlaen at hanfod y gwelliannau, mae'n werth siarad am gyfyngiadau na ellir, mewn egwyddor, eu hosgoi os ydych yn eistedd ar HDD.

Pam fod HDD a darlleniadau Mynediad ar Hap cyflym yn anghydnaws
Fel y gwyddoch, mae HBase, a llawer o gronfeydd data eraill, yn storio data mewn blociau o sawl degau o kilobytes o ran maint. Yn ddiofyn, mae tua 64 KB. Nawr, gadewch i ni ddychmygu bod angen i ni gael dim ond 100 beit a gofynnwn i HBase roi'r data hwn i ni gan ddefnyddio allwedd benodol. Gan mai maint y bloc yn HFiles yw 64 KB, bydd y cais 640 gwaith yn fwy (dim ond munud!) nag sydd angen.

Nesaf, gan y bydd y cais yn mynd trwy HDFS a'i fecanwaith caching metadata ShortCircuitCache (sy'n caniatáu mynediad uniongyrchol i ffeiliau), mae hyn yn arwain at ddarllen eisoes 1 MB o'r ddisg. Fodd bynnag, gellir addasu hyn gyda'r paramedr dfs.client.read.shortcircuit.maint byffer ac mewn llawer o achosion mae'n gwneud synnwyr i leihau'r gwerth hwn, er enghraifft i 126 KB.

Gadewch i ni ddweud ein bod yn gwneud hyn, ond yn ogystal, pan fyddwn yn dechrau darllen data trwy'r ap java, megis swyddogaethau fel FileChannel.read a gofyn i'r system weithredu ddarllen y swm penodedig o ddata, mae'n darllen “rhag ofn” 2 gwaith yn fwy , h.y. 256 KB yn ein hachos ni. Mae hyn oherwydd nad oes gan java ffordd hawdd i osod y faner FADV_RANDOM i atal yr ymddygiad hwn.

O ganlyniad, i gael ein 100 beit, darllenir 2600 gwaith yn fwy o dan y cwfl. Mae'n ymddangos bod yr ateb yn amlwg, gadewch i ni leihau maint y bloc i kilobyte, gosod y faner a grybwyllir ac ennill cyflymiad goleuedigaeth gwych. Ond y drafferth yw, trwy leihau maint y bloc 2 waith, ein bod hefyd yn lleihau nifer y beitau a ddarllenir fesul uned amser 2 waith.

Gellir cael rhywfaint o fudd o osod baner FADV_RANDOM, ond dim ond gydag aml-edafu uchel a maint bloc o 128 KB, ond mae hyn yn uchafswm o ychydig o ddegau y cant:

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Cynhaliwyd profion ar 100 o ffeiliau, pob un yn 1 GB o ran maint ac wedi'u lleoli ar 10 HDD.

Gadewch i ni gyfrifo beth allwn ni, mewn egwyddor, ddibynnu arno ar y cyflymder hwn:
Gadewch i ni ddweud ein bod yn darllen o 10 disg ar gyflymder o 280 MB/sec, h.y. 3 miliwn o weithiau 100 beit. Ond fel y cofiwn, mae’r data sydd ei angen arnom 2600 gwaith yn llai na’r hyn a ddarllenir. Felly, rydym yn rhannu 3 miliwn â 2600 ac yn cael 1100 cofnodion yr eiliad.

Digalon, ynte? Dyna natur Mynediad ar Hap mynediad at ddata ar yr HDD - waeth beth yw maint y bloc. Dyma gyfyngiad ffisegol mynediad ar hap ac ni all unrhyw gronfa ddata wasgu mwy o dan amodau o'r fath.

Sut felly mae cronfeydd data yn cyflawni cyflymderau llawer uwch? I ateb y cwestiwn hwn, gadewch i ni edrych ar yr hyn sy'n digwydd yn y llun canlynol:

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Yma gwelwn mai tua mil o recordiau yr eiliad yw'r cyflymder am yr ychydig funudau cyntaf. Fodd bynnag, ymhellach, oherwydd bod llawer mwy yn cael ei ddarllen nag y gofynnwyd amdano, mae'r data'n dod i ben yn llwydfelyn / storfa'r system weithredu (linux) ac mae'r cyflymder yn cynyddu i 60 mil yr eiliad mwy gweddus.

Felly, ymhellach byddwn yn delio â chyflymu mynediad yn unig i'r data sydd yn y storfa OS neu sydd wedi'i leoli mewn dyfeisiau storio SSD/NVMe o gyflymder mynediad tebyg.

Yn ein hachos ni, byddwn yn cynnal profion ar fainc o 4 gweinydd, a chodir tâl am bob un ohonynt fel a ganlyn:

CPU: Xeon E5-2680 v4 @ 2.40GHz 64 edafedd.
Cof: 730 GB.
fersiwn java: 1.8.0_111

Ac yma y pwynt allweddol yw faint o ddata yn y tablau sydd angen eu darllen. Y ffaith yw, os ydych chi'n darllen data o dabl sydd wedi'i osod yn gyfan gwbl yn y storfa HBase, yna ni fydd hyd yn oed yn dod i ddarllen o bwff / storfa'r system weithredu. Oherwydd bod HBase yn ddiofyn yn dyrannu 40% o gof i strwythur o'r enw BlockCache. Yn y bôn, ConcurrentHashMap yw hwn, lle'r allwedd yw enw ffeil + gwrthbwyso'r bloc, a'r gwerth yw'r data gwirioneddol ar y gwrthbwyso hwn.

Felly, wrth ddarllen o'r strwythur hwn yn unig, rydym ni rydym yn gweld cyflymder rhagorol, fel miliwn o geisiadau yr eiliad. Ond gadewch i ni ddychmygu na allwn ddyrannu cannoedd o gigabeit o gof yn unig ar gyfer anghenion cronfa ddata, oherwydd mae llawer o bethau defnyddiol eraill yn rhedeg ar y gweinyddwyr hyn.

Er enghraifft, yn ein hachos ni, mae cyfaint BlockCache ar un RS tua 12 GB. Fe wnaethon ni lanio dau RS ar un nod, h.y. Dyrennir 96 GB ar gyfer BlockCache ar bob nod. Ac mae yna lawer gwaith mwy o ddata, er enghraifft, gadewch iddo fod yn 4 tabl, 130 rhanbarth yr un, lle mae ffeiliau yn 800 MB o faint, wedi'u cywasgu gan FAST_DIFF, h.y. cyfanswm o 410 GB (data pur yw hwn, h.y. heb ystyried y ffactor atgynhyrchu).

Felly, dim ond tua 23% o gyfanswm cyfaint y data yw BlockCache ac mae hyn yn llawer agosach at amodau gwirioneddol yr hyn a elwir yn BigData. A dyma lle mae'r hwyl yn dechrau - oherwydd yn amlwg, y lleiaf o drawiadau cache, y gwaethaf yw'r perfformiad. Wedi’r cyfan, os byddwch yn methu, bydd yn rhaid i chi wneud llawer o waith – h.y. mynd i lawr i swyddogaethau system galw. Fodd bynnag, ni ellir osgoi hyn, felly gadewch i ni edrych ar agwedd hollol wahanol - beth sy'n digwydd i'r data y tu mewn i'r storfa?

Gadewch i ni symleiddio'r sefyllfa a thybio bod gennym storfa sydd ond yn ffitio 1 gwrthrych. Dyma enghraifft o'r hyn fydd yn digwydd pan geisiwn weithio gyda chyfaint data 3 gwaith yn fwy na'r storfa, bydd yn rhaid i ni:

1. Rhowch bloc 1 yn y storfa
2. Tynnwch bloc 1 o'r storfa
3. Rhowch bloc 2 yn y storfa
4. Tynnwch bloc 2 o'r storfa
5. Rhowch bloc 3 yn y storfa

5 cam wedi'u cwblhau! Fodd bynnag, ni ellir galw'r sefyllfa hon yn normal; mewn gwirionedd, rydym yn gorfodi HBase i wneud criw o waith cwbl ddiwerth. Mae'n darllen data o storfa'r AO yn gyson, yn ei osod yn BlockCache, dim ond i'w daflu bron yn syth oherwydd bod cyfran newydd o ddata wedi cyrraedd. Mae'r animeiddiad ar ddechrau'r post yn dangos hanfod y broblem - mae Garbage Collector yn mynd oddi ar y raddfa, mae'r awyrgylch yn cynhesu, Greta fach yn Sweden bell ac mae Sweden boeth yn cynhyrfu. A dydyn ni ddim yn hoffi TG pan fydd plant yn drist, felly rydyn ni'n dechrau meddwl beth allwn ni ei wneud amdano.

Beth os nad ydych chi'n rhoi pob bloc yn y storfa, ond dim ond canran benodol ohonyn nhw, fel nad yw'r storfa'n gorlifo? Gadewch i ni ddechrau trwy ychwanegu dim ond ychydig linellau o god i ddechrau'r swyddogaeth ar gyfer rhoi data yn BlockCache:

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

Y pwynt yma yw'r canlynol: gwrthbwyso yw lleoliad y bloc yn y ffeil ac mae ei ddigidau olaf wedi'u dosbarthu ar hap ac yn gyfartal o 00 i 99. Felly, byddwn yn hepgor y rhai sy'n dod o fewn yr ystod sydd ei angen arnom yn unig.

Er enghraifft, gosodwch cacheDataBlockPercent = 20 a gweld beth sy'n digwydd:

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Mae'r canlyniad yn amlwg. Yn y graffiau isod, daw'n amlwg pam y digwyddodd cyflymiad o'r fath - rydym yn arbed llawer o adnoddau GC heb wneud y gwaith Sisyphean o osod data yn y storfa dim ond i'w daflu ar unwaith i lawr draen cŵn y blaned:

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Ar yr un pryd, mae'r defnydd o CPU yn cynyddu, ond mae'n llawer llai na chynhyrchiant:

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Mae'n werth nodi hefyd bod y blociau sy'n cael eu storio yn BlockCache yn wahanol. Mae'r rhan fwyaf, tua 95%, yn ddata ei hun. Ac mae'r gweddill yn fetadata, fel hidlwyr Bloom neu LEAF_INDEX a д.д.. Nid yw'r data hwn yn ddigon, ond mae'n ddefnyddiol iawn, oherwydd cyn cyrchu'r data yn uniongyrchol, mae HBase yn troi at y meta i ddeall a oes angen chwilio yma ymhellach ac, os felly, ble yn union y mae'r bloc o ddiddordeb wedi'i leoli.

Felly, yn y cod rydym yn gweld cyflwr gwirio buf.getBlockType().isData() a diolch i'r meta hwn, byddwn yn ei adael yn y storfa beth bynnag.

Nawr, gadewch i ni gynyddu'r llwyth a thynhau'r nodwedd ychydig ar yr un pryd. Yn y prawf cyntaf fe wnaethom y canran toriad = 20 ac roedd BlockCache ychydig yn cael ei danddefnyddio. Nawr, gadewch i ni ei osod i 23% ac ychwanegu 100 o edafedd bob 5 munud i weld ar ba bwynt mae dirlawnder yn digwydd:

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Yma gwelwn fod y fersiwn wreiddiol bron yn syth yn cyrraedd y nenfwd ar tua 100 mil o geisiadau yr eiliad. Tra bod y clwt yn rhoi cyflymiad o hyd at 300 mil. Ar yr un pryd, mae'n amlwg nad yw cyflymiad pellach mor “rhad ac am ddim” bellach; mae'r defnydd o CPU hefyd yn cynyddu.

Fodd bynnag, nid yw hwn yn ddatrysiad cain iawn, gan nad ydym yn gwybod ymlaen llaw pa ganran o flociau sydd angen eu storio, mae'n dibynnu ar y proffil llwyth. Felly, gweithredwyd mecanwaith i addasu'r paramedr hwn yn awtomatig yn dibynnu ar weithgaredd gweithrediadau darllen.

Ychwanegwyd tri opsiwn i reoli hyn:

hbase.lru.cache.trwm.troi.terfyn.cyfrif — yn gosod sawl gwaith y dylai’r broses o ddadfeddiannu data o’r storfa redeg cyn i ni ddechrau defnyddio optimeiddio (h.y. sgipio blociau). Yn ddiofyn mae'n hafal i MAX_INT = 2147483647 ac mewn gwirionedd yn golygu na fydd y nodwedd byth yn dechrau gweithio gyda'r gwerth hwn. Oherwydd bod y broses dadfeddiannu yn dechrau bob 5 - 10 eiliad (mae'n dibynnu ar y llwyth) a 2147483647 * 10 / 60 / 60 / 24 / 365 = 680 mlynedd. Fodd bynnag, gallwn osod y paramedr hwn i 0 a gwneud i'r nodwedd weithio yn syth ar ôl ei lansio.

Fodd bynnag, mae yna hefyd lwyth tâl yn y paramedr hwn. Os yw ein llwyth yn golygu bod darlleniadau tymor byr (dyweder yn ystod y dydd) a darlleniadau tymor hir (yn y nos) yn gymysg yn gyson, yna gallwn sicrhau bod y nodwedd yn cael ei throi ymlaen dim ond pan fydd gweithrediadau darllen hir ar y gweill.

Er enghraifft, rydym yn gwybod bod darlleniadau tymor byr fel arfer yn para tua 1 munud. Nid oes angen dechrau taflu blociau allan, ni fydd gan y storfa amser i ddod yn hen ffasiwn ac yna gallwn osod y paramedr hwn yn hafal i, er enghraifft, 10. Bydd hyn yn arwain at y ffaith y bydd y optimization yn dechrau gweithio dim ond pan fydd yn hir- darllen gweithredol tymor wedi dechrau, h.y. mewn 100 eiliad. Felly, os oes gennym ddarlleniad tymor byr, yna bydd yr holl flociau yn mynd i'r storfa a byddant ar gael (ac eithrio'r rhai a fydd yn cael eu troi allan gan yr algorithm safonol). A phan fyddwn yn darllen yn y tymor hir, mae'r nodwedd yn cael ei droi ymlaen a byddai gennym berfformiad llawer uwch.

hbase.lru.cache.trwm.dadfeddiannu.mb.size.limit — yn gosod faint o megabeit yr hoffem ei roi yn y storfa (ac, wrth gwrs, ei droi allan) mewn 10 eiliad. Bydd y nodwedd yn ceisio cyrraedd y gwerth hwn a'i gynnal. Y pwynt yw hyn: os byddwn yn gwthio gigabeit i'r storfa, yna bydd yn rhaid i ni droi gigabeit allan, ac mae hyn, fel y gwelsom uchod, yn ddrud iawn. Fodd bynnag, ni ddylech geisio ei osod yn rhy fach, gan y bydd hyn yn achosi'r modd sgip bloc i adael yn gynamserol. Ar gyfer gweinyddwyr pwerus (tua 20-40 creiddiau corfforol), mae'n optimaidd gosod tua 300-400 MB. Ar gyfer y dosbarth canol (~10 cores) 200-300 MB. Ar gyfer systemau gwan (2-5 craidd) gall 50-100 MB fod yn normal (heb ei brofi ar y rhain).

Gadewch i ni edrych ar sut mae hyn yn gweithio: gadewch i ni ddweud ein bod yn gosod hbase.lru.cache.heavy.eviction.mb.size.limit = 500, mae rhyw fath o lwyth (darllen) ac yna bob ~10 eiliad rydym yn cyfrifo faint o beit oedd cael ei droi allan gan ddefnyddio'r fformiwla:

Gorbenion = Swm Beitiau Rhyddhawyd (MB) * 100 / Terfyn (MB) - 100;

Pe bai 2000 MB mewn gwirionedd yn cael eu troi allan, yna mae Gorbenion yn hafal i:

2000 * 100 / 500 - 100 = 300%

Mae'r algorithmau'n ceisio cynnal dim mwy nag ychydig ddegau y cant, felly bydd y nodwedd yn lleihau canran y blociau wedi'u storio, a thrwy hynny weithredu mecanwaith tiwnio awtomatig.

Fodd bynnag, os bydd y llwyth yn gostwng, gadewch i ni ddweud mai dim ond 200 MB sy'n cael eu troi allan a bod Gorbenion yn dod yn negyddol (yr hyn a elwir yn or-saethu):

200 * 100 / 500 - 100 = -60%

I'r gwrthwyneb, bydd y nodwedd yn cynyddu canran y blociau wedi'u storio nes bod Overhead yn dod yn bositif.

Isod mae enghraifft o sut mae hyn yn edrych ar ddata go iawn. Nid oes angen ceisio cyrraedd 0%, mae'n amhosibl. Mae'n dda iawn pan fydd tua 30 - 100%, mae hyn yn helpu i osgoi gadael cynamserol o'r modd optimeiddio yn ystod ymchwyddiadau tymor byr.

hbase.lru.cache.trwm.troi.cyfernod.uwchben — yn gosod pa mor gyflym yr hoffem gael y canlyniad. Os ydym yn gwybod yn sicr bod ein darlleniadau yn hir ar y cyfan ac nad ydym am aros, gallwn gynyddu'r gymhareb hon a chael perfformiad uchel yn gyflymach.

Er enghraifft, rydym yn gosod y cyfernod hwn = 0.01. Mae hyn yn golygu y bydd Gorbenion (gweler uchod) yn cael ei luosi â'r rhif hwn â'r canlyniad canlyniadol a bydd canran y blociau wedi'u storio yn cael eu lleihau. Gadewch i ni dybio bod Gorbenion = 300% a chyfernod = 0.01, yna bydd canran y blociau wedi'u storio yn cael eu lleihau 3%.

Gweithredir rhesymeg “Bwysau Cefn” tebyg hefyd ar gyfer gwerthoedd Uwchben (gorbenion) negyddol. Gan fod amrywiadau tymor byr yn nifer y darlleniadau a dadfeddiannau bob amser yn bosibl, mae'r mecanwaith hwn yn caniatáu ichi osgoi gadael y modd optimeiddio yn gynnar. Mae gan backpressure resymeg wrthdro: y cryfaf yw'r gor-saethu, y mwyaf o flociau sy'n cael eu storio.

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Cod gweithredu

        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;
       }

Gadewch i ni nawr edrych ar hyn i gyd gan ddefnyddio enghraifft wirioneddol. Mae gennym y sgript prawf canlynol:

  1. Gadewch i ni ddechrau gwneud Scan (25 edafedd, swp = 100)
  2. Ar ôl 5 munud, ychwanegwch aml-gets (25 edafedd, swp = 100)
  3. Ar ôl 5 munud, diffoddwch aml-gets (dim ond sgan sydd ar ôl eto)

Rydyn ni'n gwneud dau rediad, yn gyntaf hbase.lru.cache.heavy.eviction.count.limit = 10000 (sydd mewn gwirionedd yn analluogi'r nodwedd), ac yna gosod terfyn = 0 (yn ei alluogi).

Yn y logiau isod gwelwn sut mae'r nodwedd yn cael ei droi ymlaen ac yn ailosod Overshooting i 14-71%. O bryd i'w gilydd mae'r llwyth yn lleihau, sy'n troi Backpressure ymlaen a HBase yn storio mwy o flociau eto.

Log RhanbarthGweinydd
troi allan (MB): 0, cymhareb 0.0, uwchben (%): -100, cownter dadfeddiannu trwm: 0, caching cyfredol DataBlock (%): 100
troi allan (MB): 0, cymhareb 0.0, uwchben (%): -100, cownter dadfeddiannu trwm: 0, caching cyfredol DataBlock (%): 100
troi allan (MB): 2170, cymhareb 1.09, uwchben (%): 985, cownter dadfeddiannu trwm: 1, caching cyfredol DataBlock (%): 91 < cychwyn
troi allan (MB): 3763, cymhareb 1.08, uwchben (%): 1781, cownter dadfeddiannu trwm: 2, caching cyfredol DataBlock (%): 76
troi allan (MB): 3306, cymhareb 1.07, uwchben (%): 1553, cownter dadfeddiannu trwm: 3, caching cyfredol DataBlock (%): 61
troi allan (MB): 2508, cymhareb 1.06, uwchben (%): 1154, cownter dadfeddiannu trwm: 4, caching cyfredol DataBlock (%): 50
troi allan (MB): 1824, cymhareb 1.04, uwchben (%): 812, cownter dadfeddiannu trwm: 5, caching cyfredol DataBlock (%): 42
troi allan (MB): 1482, cymhareb 1.03, uwchben (%): 641, cownter dadfeddiannu trwm: 6, caching cyfredol DataBlock (%): 36
troi allan (MB): 1140, cymhareb 1.01, uwchben (%): 470, cownter dadfeddiannu trwm: 7, caching cyfredol DataBlock (%): 32
troi allan (MB): 913, cymhareb 1.0, uwchben (%): 356, cownter dadfeddiannu trwm: 8, caching cyfredol DataBlock (%): 29
troi allan (MB): 912, cymhareb 0.89, uwchben (%): 356, cownter dadfeddiannu trwm: 9, caching cyfredol DataBlock (%): 26
troi allan (MB): 684, cymhareb 0.76, uwchben (%): 242, cownter dadfeddiannu trwm: 10, caching cyfredol DataBlock (%): 24
troi allan (MB): 684, cymhareb 0.61, uwchben (%): 242, cownter dadfeddiannu trwm: 11, caching cyfredol DataBlock (%): 22
troi allan (MB): 456, cymhareb 0.51, uwchben (%): 128, cownter dadfeddiannu trwm: 12, caching cyfredol DataBlock (%): 21
troi allan (MB): 456, cymhareb 0.42, uwchben (%): 128, cownter dadfeddiannu trwm: 13, caching cyfredol DataBlock (%): 20
troi allan (MB): 456, cymhareb 0.33, uwchben (%): 128, cownter dadfeddiannu trwm: 14, caching cyfredol DataBlock (%): 19
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 15, caching cyfredol DataBlock (%): 19
troi allan (MB): 342, cymhareb 0.32, uwchben (%): 71, cownter dadfeddiannu trwm: 16, caching cyfredol DataBlock (%): 19
troi allan (MB): 342, cymhareb 0.31, uwchben (%): 71, cownter dadfeddiannu trwm: 17, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.3, uwchben (%): 14, cownter dadfeddiannu trwm: 18, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.29, uwchben (%): 14, cownter dadfeddiannu trwm: 19, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.27, uwchben (%): 14, cownter dadfeddiannu trwm: 20, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.25, uwchben (%): 14, cownter dadfeddiannu trwm: 21, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.24, uwchben (%): 14, cownter dadfeddiannu trwm: 22, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.22, uwchben (%): 14, cownter dadfeddiannu trwm: 23, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.21, uwchben (%): 14, cownter dadfeddiannu trwm: 24, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.2, uwchben (%): 14, cownter dadfeddiannu trwm: 25, caching cyfredol DataBlock (%): 19
troi allan (MB): 228, cymhareb 0.17, uwchben (%): 14, cownter dadfeddiannu trwm: 26, caching cyfredol DataBlock (%): 19
troi allan (MB): 456, cymhareb 0.17, gorbenion (%): 128, cownter dadfeddiannu trwm: 27, caching cyfredol DataBlock (%): 18 < yn cael ei ychwanegu (ond tabl yr un peth)
troi allan (MB): 456, cymhareb 0.15, uwchben (%): 128, cownter dadfeddiannu trwm: 28, caching cyfredol DataBlock (%): 17
troi allan (MB): 342, cymhareb 0.13, uwchben (%): 71, cownter dadfeddiannu trwm: 29, caching cyfredol DataBlock (%): 17
troi allan (MB): 342, cymhareb 0.11, uwchben (%): 71, cownter dadfeddiannu trwm: 30, caching cyfredol DataBlock (%): 17
troi allan (MB): 342, cymhareb 0.09, uwchben (%): 71, cownter dadfeddiannu trwm: 31, caching cyfredol DataBlock (%): 17
troi allan (MB): 228, cymhareb 0.08, uwchben (%): 14, cownter dadfeddiannu trwm: 32, caching cyfredol DataBlock (%): 17
troi allan (MB): 228, cymhareb 0.07, uwchben (%): 14, cownter dadfeddiannu trwm: 33, caching cyfredol DataBlock (%): 17
troi allan (MB): 228, cymhareb 0.06, uwchben (%): 14, cownter dadfeddiannu trwm: 34, caching cyfredol DataBlock (%): 17
troi allan (MB): 228, cymhareb 0.05, uwchben (%): 14, cownter dadfeddiannu trwm: 35, caching cyfredol DataBlock (%): 17
troi allan (MB): 228, cymhareb 0.05, uwchben (%): 14, cownter dadfeddiannu trwm: 36, caching cyfredol DataBlock (%): 17
troi allan (MB): 228, cymhareb 0.04, uwchben (%): 14, cownter dadfeddiannu trwm: 37, caching cyfredol DataBlock (%): 17
troi allan (MB): 109, cymhareb 0.04, uwchben (%): -46, cownter dadfeddiannu trwm: 37, caching cyfredol DataBlock (%): 22 < pwysau cefn
troi allan (MB): 798, cymhareb 0.24, uwchben (%): 299, cownter dadfeddiannu trwm: 38, caching cyfredol DataBlock (%): 20
troi allan (MB): 798, cymhareb 0.29, uwchben (%): 299, cownter dadfeddiannu trwm: 39, caching cyfredol DataBlock (%): 18
troi allan (MB): 570, cymhareb 0.27, uwchben (%): 185, cownter dadfeddiannu trwm: 40, caching cyfredol DataBlock (%): 17
troi allan (MB): 456, cymhareb 0.22, uwchben (%): 128, cownter dadfeddiannu trwm: 41, caching cyfredol DataBlock (%): 16
troi allan (MB): 342, cymhareb 0.16, uwchben (%): 71, cownter dadfeddiannu trwm: 42, caching cyfredol DataBlock (%): 16
troi allan (MB): 342, cymhareb 0.11, uwchben (%): 71, cownter dadfeddiannu trwm: 43, caching cyfredol DataBlock (%): 16
troi allan (MB): 228, cymhareb 0.09, uwchben (%): 14, cownter dadfeddiannu trwm: 44, caching cyfredol DataBlock (%): 16
troi allan (MB): 228, cymhareb 0.07, uwchben (%): 14, cownter dadfeddiannu trwm: 45, caching cyfredol DataBlock (%): 16
troi allan (MB): 228, cymhareb 0.05, uwchben (%): 14, cownter dadfeddiannu trwm: 46, caching cyfredol DataBlock (%): 16
troi allan (MB): 222, cymhareb 0.04, uwchben (%): 11, cownter dadfeddiannu trwm: 47, caching cyfredol DataBlock (%): 16
troi allan (MB): 104, cymhareb 0.03, uwchben (%): -48, cownter dadfeddiannu trwm: 47, caching cyfredol DataBlock (%): 21 < torri ar draws yn cael
troi allan (MB): 684, cymhareb 0.2, uwchben (%): 242, cownter dadfeddiannu trwm: 48, caching cyfredol DataBlock (%): 19
troi allan (MB): 570, cymhareb 0.23, uwchben (%): 185, cownter dadfeddiannu trwm: 49, caching cyfredol DataBlock (%): 18
troi allan (MB): 342, cymhareb 0.22, uwchben (%): 71, cownter dadfeddiannu trwm: 50, caching cyfredol DataBlock (%): 18
troi allan (MB): 228, cymhareb 0.21, uwchben (%): 14, cownter dadfeddiannu trwm: 51, caching cyfredol DataBlock (%): 18
troi allan (MB): 228, cymhareb 0.2, uwchben (%): 14, cownter dadfeddiannu trwm: 52, caching cyfredol DataBlock (%): 18
troi allan (MB): 228, cymhareb 0.18, uwchben (%): 14, cownter dadfeddiannu trwm: 53, caching cyfredol DataBlock (%): 18
troi allan (MB): 228, cymhareb 0.16, uwchben (%): 14, cownter dadfeddiannu trwm: 54, caching cyfredol DataBlock (%): 18
troi allan (MB): 228, cymhareb 0.14, uwchben (%): 14, cownter dadfeddiannu trwm: 55, caching cyfredol DataBlock (%): 18
troi allan (MB): 112, cymhareb 0.14, uwchben (%): -44, cownter dadfeddiannu trwm: 55, caching cyfredol DataBlock (%): 23 < pwysau cefn
troi allan (MB): 456, cymhareb 0.26, uwchben (%): 128, cownter dadfeddiannu trwm: 56, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.31, uwchben (%): 71, cownter dadfeddiannu trwm: 57, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 58, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 59, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 60, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 61, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 62, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 63, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.32, uwchben (%): 71, cownter dadfeddiannu trwm: 64, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 65, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 66, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.32, uwchben (%): 71, cownter dadfeddiannu trwm: 67, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 68, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.32, uwchben (%): 71, cownter dadfeddiannu trwm: 69, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.32, uwchben (%): 71, cownter dadfeddiannu trwm: 70, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 71, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 72, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 73, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 74, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 75, caching cyfredol DataBlock (%): 22
troi allan (MB): 342, cymhareb 0.33, uwchben (%): 71, cownter dadfeddiannu trwm: 76, caching cyfredol DataBlock (%): 22
troi allan (MB): 21, cymhareb 0.33, uwchben (%): -90, cownter dadfeddiannu trwm: 76, caching cyfredol DataBlock (%): 32
troi allan (MB): 0, cymhareb 0.0, uwchben (%): -100, cownter dadfeddiannu trwm: 0, caching cyfredol DataBlock (%): 100
troi allan (MB): 0, cymhareb 0.0, uwchben (%): -100, cownter dadfeddiannu trwm: 0, caching cyfredol DataBlock (%): 100

Roedd angen y sganiau i ddangos yr un broses ar ffurf graff o'r berthynas rhwng dwy adran cache - sengl (lle mae blociau na ofynnwyd amdanynt erioed o'r blaen) ac aml (data "gofynnwyd" o leiaf unwaith yn cael eu storio yma):

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Ac yn olaf, sut olwg sydd ar weithrediad y paramedrau ar ffurf graff. Er mwyn cymharu, cafodd y storfa ei ddiffodd yn llwyr ar y dechrau, yna lansiwyd HBase gyda caching ac oedi dechrau'r gwaith optimeiddio gan 5 munud (30 o gylchoedd dadfeddiannu).

Mae'r cod llawn i'w weld yn Pull Request HBASE 23887 ar github.

Fodd bynnag, nid 300 mil o ddarlleniadau yr eiliad yw'r cyfan y gellir ei gyflawni ar y caledwedd hwn o dan yr amodau hyn. Y ffaith yw, pan fydd angen i chi gael mynediad at ddata trwy HDFS, defnyddir y mecanwaith ShortCircuitCache (y cyfeirir ato o hyn ymlaen fel SSC), sy'n eich galluogi i gael mynediad at y data yn uniongyrchol, gan osgoi rhyngweithiadau rhwydwaith.

Dangosodd proffilio, er bod y mecanwaith hwn yn rhoi mantais fawr, mae hefyd ar ryw adeg yn dod yn dagfa, oherwydd bod bron pob gweithrediad trwm yn digwydd y tu mewn i glo, sy'n arwain at rwystro'r rhan fwyaf o'r amser.

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Ar ôl sylweddoli hyn, sylweddolom y gellir goresgyn y broblem trwy greu amrywiaeth o Gynghorau Sgiliau Sector annibynnol:

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

Ac yna gweithio gyda nhw, heb gynnwys croestoriadau hefyd ar y digid gwrthbwyso olaf:

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

Nawr gallwch chi ddechrau profi. I wneud hyn, byddwn yn darllen ffeiliau o HDFS gyda chymhwysiad aml-edau syml. Gosodwch y paramedrau:

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 dim ond darllen y ffeiliau:

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);
}

Mae'r cod hwn yn cael ei weithredu mewn edafedd ar wahân a byddwn yn cynyddu nifer y ffeiliau sy'n cael eu darllen ar yr un pryd (o 10 i 200 - echel lorweddol) a nifer y caches (o 1 i 10 - graffeg). Mae'r echelin fertigol yn dangos y cyflymiad sy'n deillio o gynnydd mewn SSC o'i gymharu â'r achos pan nad oes ond un storfa.

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Sut i ddarllen y graff: Mae'r amser gweithredu ar gyfer 100 mil yn darllen mewn blociau 64 KB gydag un celc yn gofyn am 78 eiliad. Tra gyda 5 caches mae'n cymryd 16 eiliad. Y rhai. mae cyflymiad o ~5 gwaith. Fel y gwelir o'r graff, nid yw'r effaith yn amlwg iawn ar gyfer nifer fach o ddarlleniadau paralel; mae'n dechrau chwarae rhan amlwg pan fydd mwy na 50 o ddarlleniadau llinynnol. Mae hefyd yn amlwg bod cynyddu nifer y CSSau o 6 ac uwch yn rhoi cynnydd sylweddol llai mewn perfformiad.

Nodyn 1: gan fod canlyniadau'r prawf yn eithaf cyfnewidiol (gweler isod), cynhaliwyd 3 rhediad a chyfartaledd y gwerthoedd canlyniadol.

Nodyn 2: Mae'r cynnydd perfformiad o ffurfweddu mynediad ar hap yr un fath, er bod y mynediad ei hun ychydig yn arafach.

Fodd bynnag, mae angen egluro, yn wahanol i'r achos gyda HBase, nad yw'r cyflymiad hwn bob amser yn rhad ac am ddim. Yma rydyn ni'n “datgloi” gallu'r CPU i wneud mwy o waith, yn lle hongian ar gloeon.

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Yma gallwch arsylwi, yn gyffredinol, bod cynnydd yn nifer y caches yn rhoi cynnydd tua chymesuredd yn y defnydd o CPU. Fodd bynnag, mae yna ychydig mwy o gyfuniadau buddugol.

Er enghraifft, gadewch i ni edrych yn agosach ar y gosodiad SSC = 3. Mae'r cynnydd mewn perfformiad ar yr ystod tua 3.3 gwaith. Isod mae canlyniadau pob un o'r tri rhediad ar wahân.

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Er bod defnydd CPU yn cynyddu tua 2.8 gwaith. Nid yw'r gwahaniaeth yn fawr iawn, ond ychydig o Greta sydd eisoes yn hapus ac efallai bod ganddi amser i fynychu'r ysgol a chymryd gwersi.

Felly, bydd hyn yn cael effaith gadarnhaol ar unrhyw offeryn sy'n defnyddio mynediad swmp i HDFS (er enghraifft Spark, ac ati), ar yr amod bod cod y cais yn ysgafn (h.y. mae'r plwg ar ochr cleient HDFS) a bod pŵer CPU am ddim . I wirio, gadewch i ni brofi pa effaith a gaiff y defnydd cyfun o optimeiddio BlockCache a thiwnio SSC ar gyfer darllen o HBase.

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Gellir gweld nad yw'r effaith mor fawr o dan amodau o'r fath ag mewn profion mireinio (darllen heb unrhyw brosesu), ond mae'n eithaf posibl gwasgu 80K ychwanegol allan yma. Gyda'i gilydd, mae'r ddau optimeiddiad yn darparu hyd at gyflymu 4x.

Gwnaethpwyd cysylltiadau cyhoeddus hefyd ar gyfer yr optimeiddio hwn [HDFS-15202], sydd wedi'i uno a bydd y swyddogaeth hon ar gael mewn datganiadau yn y dyfodol.

Ac yn olaf, roedd yn ddiddorol cymharu perfformiad darllen cronfa ddata colofn lydan debyg, Cassandra a HBase.

I wneud hyn, fe wnaethom lansio enghreifftiau o gyfleustodau profi llwyth safonol YCSB gan ddau westeiwr (cyfanswm o 800 o edafedd). Ar ochr y gweinydd - 4 achos o RegionServer a Cassandra ar 4 gwesteiwr (nid y rhai lle mae'r cleientiaid yn rhedeg, er mwyn osgoi eu dylanwad). Daeth darlleniadau o dablau maint:

HBase - 300 GB ar HDFS (data pur 100 GB)

Cassandra - 250 GB (ffactor atgynhyrchu = 3)

Y rhai. roedd y gyfrol tua'r un peth (mewn HBase ychydig yn fwy).

Paramedrau HBase:

dfs.client.short.circuit.num = 5 (Optimeiddio cleient HDFS)

hbase.lru.cache.heavy.eviction.count.limit = 30 - mae hyn yn golygu y bydd y clwt yn dechrau gweithio ar ôl 30 o droi allan (~5 munud)

hbase.lru.cache.heavy.eviction.mb.size.limit = 300 — nifer targed y caching a dadfeddiannu

Cafodd logiau YCSB eu dosrannu a'u crynhoi yn graffiau Excel:

Sut i gynyddu cyflymder darllen o HBase hyd at 3 gwaith ac o HDFS hyd at 5 gwaith

Fel y gallwch weld, mae'r optimeiddiadau hyn yn ei gwneud hi'n bosibl cymharu perfformiad y cronfeydd data hyn o dan yr amodau hyn a chyflawni 450 mil o ddarlleniadau yr eiliad.

Gobeithiwn y gall y wybodaeth hon fod yn ddefnyddiol i rywun yn ystod y frwydr gyffrous dros gynhyrchiant.

Ffynhonnell: hab.com

Ychwanegu sylw