HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Чоң маалыматтар менен иштөөдө жогорку өндүрүмдүүлүк негизги талаптардын бири болуп саналат. Сбербанктагы маалыматтарды жүктөө бөлүмүндө биз дээрлик бардык транзакцияларды Hadoop негизиндеги Маалымат Булутуна куюп салабыз, демек, маалыматтын чындап эле чоң агымдары менен алектенебиз. Албетте, биз ар дайым иштөөнү жакшыртуунун жолдорун издеп жатабыз жана азыр биз RegionServer HBase жана HDFS кардарын кантип жаңыртканыбызды айткыбыз келет, анын аркасында окуу операцияларынын ылдамдыгын бир топ жогорулата алдык.
HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Бирок, жакшыртуулардын маңызына өтүүдөн мурун, эгер сиз HDDде отурсаңыз, негизинен, айланып өтүүгө мүмкүн болбогон чектөөлөр жөнүндө сөз кылуу керек.

Эмне үчүн HDD жана тез Random Access окуулары шайкеш келбейт
Белгилүү болгондой, HBase жана башка көптөгөн маалымат базалары маалыматтарды бир нече ондогон килобайттык блоктордо сакташат. Демейки боюнча бул болжол менен 64 КБ. Эми биз болгону 100 байт алышыбыз керек деп элестетип көрөлү жана биз HBaseден белгилүү бир ачкыч аркылуу бул маалыматты бизге берүүнү суранабыз. HFiles'теги блоктун көлөмү 64 КБ болгондуктан, суроо-талап зарыл болгондон 640 эсе чоң (бир эле мүнөт!) болот.

Андан кийин, сурам HDFS жана анын метадайындарын кэштөө механизми аркылуу өтөт ShortCircuitCache (бул файлдарга түз кирүүгө мүмкүндүк берет), бул дисктен 1 Мб окууга алып келет. Бирок, бул параметр менен жөнгө салынышы мүмкүн dfs.кардар.окуу.кыска туташуу.буфер.өлчөм жана көп учурларда бул маанини, мисалы, 126 КБ чейин азайтуу мааниси бар.

Биз муну жасайбыз дейли, бирок андан тышкары, FileChannel.read сыяктуу функциялар сыяктуу java api аркылуу маалыматтарды окуй баштаганда жана операциялык тутумдан көрсөтүлгөн көлөмдөгү маалыматтарды окуусун суранганда, ал "болбосо" 2 эсе көп окуйт. , б.а. Биздин учурда 256 KB. Себеби, javaда бул жүрүм-турумдун алдын алуу үчүн FADV_RANDOM желегин орнотуунун оңой жолу жок.

Натыйжада, биздин 100 байт алуу үчүн, капоттун астында 2600 эсе көп окулат. Чечим ачык эле көрүнүп турат, келгиле, блоктун көлөмүн килобайтка чейин азайтып, аталган желекти орнотуп, чоң агартуу ылдамдыгын алалы. Бирок кыйынчылык - блоктун көлөмүн 2 эсеге кыскартуу менен биз убакыт бирдигине окулган байттардын санын 2 эсеге азайтабыз.

FADV_RANDOM желекчесин коюудан бир аз пайда алууга болот, бирок жогорку көп жиптүү жана 128 КБ блоктун өлчөмү менен гана, бирок бул эң көп дегенде ондогон пайызды түзөт:

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Сыноолор ар бири 100 ГБ өлчөмүндө жана 1 HDDде жайгашкан 10 файлда жүргүзүлдү.

Келгиле, бул ылдамдыкта биз эмнеге ишене аларыбызды эсептеп көрөлү:
Айталы, 10 дисктен 280 МБ/сек ылдамдыкта окуйбуз, б.а. 3 миллион эсе 100 байт. Бирок биз эсибизде тургандай, бизге керектүү маалыматтар окулгандан 2600 эсе аз. Ошентип, 3 миллионду 2600гө бөлүп, алабыз секундасына 1100 жазуу.

Депрессия, туурабы? Табият ушундай Random access HDDдеги маалыматтарга жетүү - блоктун өлчөмүнө карабастан. Бул кокустан жетүүнүн физикалык чеги жана мындай шарттарда эч бир маалымат базасы көбүрөөк сыга албайт.

Кантип маалымат базалары алда канча жогорку ылдамдыкка жетишет? Бул суроого жооп берүү үчүн, келгиле, төмөнкү сүрөттө эмне болуп жатканын карап көрөлү:

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Бул жерде биз биринчи бир нече мүнөттө ылдамдык чындап секундасына миң рекордду түзөрүн көрөбүз. Бирок, андан ары, суралгандан алда канча көп окулгандыгына байланыштуу, маалыматтар операциялык системанын (linux) буфф/кэшинде аяктайт жана ылдамдыгы секундасына 60 миңге чейин жогорулайт.

Ошентип, мындан ары биз ОС кэшинде же SSD/NVMe сактагыч түзүлүштөрүндө жайгашкан маалыматтарга жетүү ылдамдыгын тездетүү менен алектенебиз.

Биздин учурда, биз сыноолорду 4 серверден турган отургучта өткөрөбүз, алардын ар бири төмөнкүдөй заряддалат:

CPU: Xeon E5-2680 v4 @ 2.40GHz 64 жип.
Эстутум: 730 ГБ.
java версиясы: 1.8.0_111

Ал эми бул жерде негизги нерсе - таблицалардагы маалыматтардын көлөмү, аларды окуш керек. Чындыгында, эгер сиз толугу менен HBase кэшине жайгаштырылган таблицадан маалыматтарды окусаңыз, анда ал иштөө тутумунун буфф/кэшинен окууга да келбейт. Анткени HBase демейки боюнча эстутумдун 40% BlockCache деп аталган структурага бөлөт. Негизинен бул ConcurrentHashMap, мында ачкыч файлдын аты + блоктун офсети, ал эми маани бул офсеттеги чыныгы маалыматтар.

Ошентип, ушул структурадан гана окуганда биз сонун ылдамдыкты көрөбүз, секундасына миллион суроо сыяктуу. Бирок, келгиле, биз жүздөгөн гигабайт эстутумду маалымат базасынын муктаждыктары үчүн гана бөлө албайбыз деп элестетип көрөлү, анткени бул серверлерде башка көптөгөн пайдалуу нерселер иштейт.

Мисалы, биздин учурда, бир RS боюнча BlockCache көлөмү болжол менен 12 ГБ түзөт. Биз бир түйүнгө эки RS кондук, б.а. Бардык түйүндөрдө BlockCache үчүн 96 ГБ бөлүнгөн. Жана дагы бир нече эсе көп маалыматтар бар, мисалы, 4 таблица, ар бири 130 регион болсун, анда файлдардын көлөмү 800 МБ, FAST_DIFF тарабынан кысылган, б.а. жалпысынан 410 ГБ (бул таза маалымат, б.а. репликация факторун эске албаганда).

Ошентип, BlockCache жалпы маалымат көлөмүнүн 23% гана түзөт жана бул BigData деп аталган реалдуу шарттарга алда канча жакын. Бул жерде кызыктуу башталат - анткени, албетте, азыраак кэш хит, начар аткаруу. Кантсе да, сагынсаң, көп иштерди жасоого туура келет - б.а. тутум функцияларын чакырууга өтүңүз. Бирок, муну болтурбоо мүмкүн эмес, ошондуктан келгиле, такыр башка аспектти карап көрөлү - кэштин ичиндеги маалыматтар менен эмне болот?

Кырдаалды жөнөкөйлөтүп, бизде 1 объектке гана туура келген кэш бар деп ойлойлу. Бул жерде кэштен 3 эсе чоңураак маалымат көлөмү менен иштөөгө аракет кылганыбызда эмне болорун мисал келтирсек, биз төмөнкүлөргө туура келет:

1. 1-блокту кэшке салыңыз
2. 1-блокту кэштен алып салыңыз
3. 2-блокту кэшке салыңыз
4. 2-блокту кэштен алып салыңыз
5. 3-блокту кэшке салыңыз

5 аракет аткарылды! Бирок, бул абалды нормалдуу деп айтууга болбойт; чындыгында, биз HBaseди бир топ пайдасыз иштерди жасоого мажбурлап жатабыз. Ал тынымсыз OS кэшинен берилиштерди окуп, аны BlockCacheке жайгаштырат, бирок маалыматтардын жаңы бөлүктөрү келгендиктен, аны дароо чыгарып салуу үчүн. Посттун башындагы анимация көйгөйдүн маңызын көрсөтөт - Таштанды жыйноочу масштабдан чыгып баратат, атмосфера ысып жатат, алыскы жана ысык Швециядагы кичинекей Грета капаланып жатат. Ал эми биз IT адамдары балдардын кайгырганын жактырбайбыз, ошондуктан биз бул тууралуу эмне кылсак болот деп ойлоно баштайбыз.

Кэш толуп кетпеши үчүн бардык блокторду эмес, алардын белгилүү бир пайызын гана койсоңузчу? Келгиле, BlockCache'ге маалыматтарды киргизүү үчүн функциянын башына жөн гана бир нече сап кодду кошуу менен баштайлы:

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

Бул жерде сөз болуп жатат: офсет файлдагы блоктун абалы жана анын акыркы сандары 00дөн 99га чейин туш келди жана бирдей бөлүштүрүлөт. Ошондуктан, биз керектүү диапазонго түшкөндөрдү гана өткөрүп жиберебиз.

Мисалы, cacheDataBlockPercent = 20 коюңуз жана эмне болорун көрүңүз:

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Натыйжа ачык-айкын. Төмөнкү графиктерде эмне үчүн мындай ылдамдануу болгону айкын көрүнүп турат - биз маалыматтарды кэшке жайгаштыруу боюнча Sisyphean ишин жасабастан, көп GC ресурстарын үнөмдөп, аны дароо Марс иттеринин агымына ыргытып жиберебиз:

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Ошол эле учурда, CPU колдонуу көбөйөт, бирок өндүрүмдүүлүктөн бир топ азыраак:

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Бул BlockCache сакталган блоктордун ар түрдүү экенин белгилей кетүү керек. Көпчүлүгү, болжол менен 95%, маалыматтын өзү. Ал эми калганы метадайындар, мисалы Bloom чыпкалары же LEAF_INDEX жана жана башкалар. Бул маалымат жетишсиз, бирок бул абдан пайдалуу, анткени маалыматтарга түздөн-түз жетүүдөн мурун, HBase бул жерде мындан ары издөө керекпи же жокпу, түшүнүү үчүн метага кайрылат, эгер ошондой болсо, кызыкчылык блогу так кайда жайгашкан.

Ошондуктан, коддон биз текшерүү шартын көрөбүз buf.getBlockType().isData() жана бул метанын аркасында биз аны кандай болгон күндө да кэште калтырабыз.

Эми жүктү көбөйтүп, функцияны бир аз күчөтөлү. Биринчи тестте биз кесүү пайызын = 20 кылдык жана BlockCache бир аз пайдаланылган. Эми аны 23% кылып коелу жана каныккандык кайсы учурда пайда болоорун көрүү үчүн ар 100 мүнөт сайын 5 жипти кошолу:

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Бул жерде биз оригиналдуу версия секундасына 100 миңге жакын суроо-талаптар менен дароо шыпка жеткенин көрөбүз. Ал эми патч 300 миңге чейин ылдамдатууну берет. Ошол эле учурда, андан ары тездетүү мындан ары "эркин" эмес экени көрүнүп турат; CPU колдонуу да көбөйүүдө.

Бирок, бул абдан жарашыктуу чечим эмес, анткени биз блоктордун канча пайызын кэштештирүү керек экенин алдын ала билбейбиз, бул жүк профилине жараша болот. Ошондуктан, окуу операцияларынын активдүүлүгүнө жараша бул параметрди автоматтык түрдө жөнгө салуу механизми ишке ашырылган.

Муну көзөмөлдөө үчүн үч вариант кошулду:

hbase.lru.cache.heavy.evction.count.limit — оптималдаштырууну (б.а. блокторду өткөрүп жиберүү) колдонууну баштаганга чейин кэштен маалыматтарды чыгаруу процесси канча жолу аткарылышы керектигин белгилейт. Демейки боюнча ал MAX_INT = 2147483647ге барабар жана чындыгында бул функция эч качан бул маани менен иштей баштабайт дегенди билдирет. Анткени көчүрүү процесси ар бир 5 - 10 секундада башталат (бул жүккө жараша) жана 2147483647 * 10/60/60/24/365 = 680 жыл. Бирок, биз бул параметрди 0 кылып, ишке киргизгенден кийин функцияны дароо иштете алабыз.

Бирок, бул параметрде пайдалуу жүк да бар. Эгерде биздин жүктөм кыска мөөнөттүү окуулар (айталы, күндүз) жана узак мөөнөттүү окуулар (түндө) тынымсыз кесилишкендей болсо, анда функция узак окуу операциялары жүрүп жатканда гана күйгүзүлгөнүн текшере алабыз.

Мисалы, биз кыска мөөнөттүү окуу адатта 1 мүнөткө созулаарын билебиз. Блокторду ыргытып баштоонун кереги жок, кэш эскирип калууга үлгүрбөй калат, андан кийин биз бул параметрди, мисалы, 10го барабар коё алабыз. Бул оптималдаштыруу узакка созулганда гана иштей баштайт деп алып келет. мөөнөттүү активдүү окуу башталды, б.а. 100 секунданын ичинде. Ошентип, бизде кыска мөөнөттүү окуу болсо, анда бардык блоктор кэшке кирип, жеткиликтүү болот (стандарттык алгоритм менен чыгарыла тургандардан тышкары). Ал эми биз узак мөөнөттүү окуганда, функция күйгүзүлөт жана биз бир топ жогору көрсөткүчкө ээ болмокпуз.

hbase.lru.cache.heavy.evction.mb.size.limit — 10 секунданын ичинде кэшке канча мегабайт жайгаштыргыбыз келерин (жана, албетте, чыгарууну) белгилейт. Өзгөчөлүк бул мааниге жетүү жана аны сактоого аракет кылат. Кеп мына ушунда: эгерде биз гигабайттарды кэшке киргизсек, анда гигабайттарды чыгарууга туура келет жана бул, жогоруда көргөндөй, абдан кымбат. Бирок, сиз аны өтө кичине коюуга аракет кылбаңыз, анткени бул блокту өткөрүп жиберүү режиминин мөөнөтүнөн мурда чыгуусуна алып келет. Күчтүү серверлер үчүн (болжол менен 20-40 физикалык ядро) 300-400 МБ орнотуу оптималдуу. Орто класс үчүн (~10 ядро) 200-300 МБ. Алсыз системалар үчүн (2-5 ядро) 50-100 МБ нормалдуу болушу мүмкүн (буларда текшерилген эмес).

Мунун кантип иштээрин карап көрөлү: биз hbase.lru.cache.heavy.eviction.mb.size.limit = 500 койдук дейли, кандайдыр бир жүк (окуу) бар, анан ар бир ~10 секунд сайын биз канча байт болгонун эсептейбиз. формула боюнча чыгарылат:

Кошумча чыгымдар = Бошогон байт суммасы (МБ) * 100 / Лимит (МБ) - 100;

Эгерде чындыгында 2000 МБ чыгарылып кетсе, анда кошумча чыгым төмөнкүгө барабар болот:

2000 * 100 / 500 - 100 = 300%

Алгоритмдер бир нече ондогон пайыздан ашык эмес сактоого аракет кылышат, андыктан функция кэштелген блоктордун пайызын азайтат, ошону менен авто-тюнинг механизмин ишке ашырат.

Бирок, жүк төмөндөп кетсе, 200 МБ гана чыгарылды деп коёлу жана Ашыкча чыгым терс болуп калат (ашып кетүү деп аталган):

200 * 100 / 500 - 100 = -60%

Тескерисинче, функция кэштелген блоктордун пайызын Overhead оң болуп калганга чейин жогорулатат.

Төмөндө бул реалдуу маалыматтарга кандайча көрүнгөнүнүн мисалы келтирилген. 0% жетүү үчүн аракет кылуунун кереги жок, мүмкүн эмес. Ал болжол менен 30 - 100% болгондо абдан жакшы, бул кыска мөөнөттүү толкундар учурунда оптималдаштыруу режиминен мөөнөтүнөн мурда чыгуудан качууга жардам берет.

hbase.lru.cache.оор.кучуруу.кошумча.коэффициент — натыйжага канчалык тез жетүүнү каалай турганыбызды белгилейт. Эгерде биз окууларыбыз негизинен узак экенин жана күтүүнү каалабай турганын так билсек, биз бул катышты көбөйтүп, жогорку көрсөткүчтөргө тезирээк жете алабыз.

Мисалы, биз бул коэффициентти = 0.01 койдук. Бул кошумча чыгым (жогоруда караңыз) натыйжада ушул санга көбөйтүлөт жана кэштелген блоктордун пайызы азаят дегенди билдирет. Кошумча чыгым = 300% жана коэффициент = 0.01 деп коёлу, анда кэштелген блоктордун пайызы 3% га азаят.

Окшош "Артка басым" логикасы терс кошумча (ашып кетүү) маанилери үчүн да ишке ашырылат. Окуулардын жана чыгаруулардын көлөмүнүн кыска мөөнөттүү өзгөрүүсү ар дайым мүмкүн болгондуктан, бул механизм оптималдаштыруу режиминен мөөнөтүнөн мурда чыгуудан качууга мүмкүндүк берет. Арткы басымдын тескери логикасы бар: ашып кетүү канчалык күчтүү болсо, блоктор ошончолук кэште сакталат.

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Ишке ашыруу коду

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

Эми мунун баарын реалдуу мисал менен карап көрөлү. Бизде төмөнкү сыноо сценарийи бар:

  1. Скандоону баштайлы (25 жип, партия = 100)
  2. 5 мүнөттөн кийин, көп алууларды кошуңуз (25 жип, партия = 100)
  3. 5 мүнөттөн кийин multi-gets өчүрүңүз (кайра сканерлөө гана калат)

Биз эки чуркоо жасайбыз, адегенде hbase.lru.cache.heavy.eviction.count.limit = 10000 (ал иш жүзүндө функцияны өчүрөт), андан кийин чекти = 0 коет (аны иштетет).

Төмөндөгү журналдарда биз функция кантип күйгүзүлгөнүн жана Overshooting 14-71% га кайтарылганын көрөбүз. Мезгил-мезгили менен жүк төмөндөйт, бул Backpressure жана HBase кэштерин кайра көбүрөөк блокторду күйгүзөт.

Log RegionServer
чыгарылды (МБ): 0, катышы 0.0, кошумча чыгым (%): -100, оор чыгаруу эсептегичи: 0, учурдагы кэштөө DataBlock (%): 100
чыгарылды (МБ): 0, катышы 0.0, кошумча чыгым (%): -100, оор чыгаруу эсептегичи: 0, учурдагы кэштөө DataBlock (%): 100
чыгарылды (МБ): 2170, катышы 1.09, кошумча чыгымдар (%): 985, оор көчүрүү эсептегичи: 1, учурдагы кэштөө DataBlock (%): 91 < баштоо
чыгарылды (МБ): 3763, катышы 1.08, кошумча чыгым (%): 1781, оор көчүрүү эсептегичи: 2, учурдагы кэштөө DataBlock (%): 76
чыгарылды (МБ): 3306, катышы 1.07, кошумча чыгым (%): 1553, оор көчүрүү эсептегичи: 3, учурдагы кэштөө DataBlock (%): 61
чыгарылды (МБ): 2508, катышы 1.06, кошумча чыгым (%): 1154, оор көчүрүү эсептегичи: 4, учурдагы кэштөө DataBlock (%): 50
чыгарылды (МБ): 1824, катышы 1.04, кошумча чыгым (%): 812, оор көчүрүү эсептегичи: 5, учурдагы кэштөө DataBlock (%): 42
чыгарылды (МБ): 1482, катышы 1.03, кошумча чыгым (%): 641, оор көчүрүү эсептегичи: 6, учурдагы кэштөө DataBlock (%): 36
чыгарылды (МБ): 1140, катышы 1.01, кошумча чыгым (%): 470, оор көчүрүү эсептегичи: 7, учурдагы кэштөө DataBlock (%): 32
чыгарылды (МБ): 913, катышы 1.0, кошумча чыгым (%): 356, оор көчүрүү эсептегичи: 8, учурдагы кэштөө DataBlock (%): 29
чыгарылды (МБ): 912, катышы 0.89, кошумча чыгым (%): 356, оор көчүрүү эсептегичи: 9, учурдагы кэштөө DataBlock (%): 26
чыгарылды (МБ): 684, катышы 0.76, кошумча чыгым (%): 242, оор көчүрүү эсептегичи: 10, учурдагы кэштөө DataBlock (%): 24
чыгарылды (МБ): 684, катышы 0.61, кошумча чыгым (%): 242, оор көчүрүү эсептегичи: 11, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 456, катышы 0.51, кошумча чыгым (%): 128, оор көчүрүү эсептегичи: 12, учурдагы кэштөө DataBlock (%): 21
чыгарылды (МБ): 456, катышы 0.42, кошумча чыгым (%): 128, оор көчүрүү эсептегичи: 13, учурдагы кэштөө DataBlock (%): 20
чыгарылды (МБ): 456, катышы 0.33, кошумча чыгым (%): 128, оор көчүрүү эсептегичи: 14, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 15, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 342, катышы 0.32, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 16, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 342, катышы 0.31, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 17, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.3, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 18, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.29, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 19, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.27, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 20, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.25, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 21, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.24, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 22, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.22, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 23, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.21, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 24, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.2, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 25, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 228, катышы 0.17, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 26, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 456, катышы 0.17, үстөк (%): 128, оор көчүрүү эсептегичи: 27, учурдагы кэштөө DataBlock (%): 18 <кошулган алат (бирок таблица бирдей)
чыгарылды (МБ): 456, катышы 0.15, кошумча чыгым (%): 128, оор көчүрүү эсептегичи: 28, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 342, катышы 0.13, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 29, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 342, катышы 0.11, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 30, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 342, катышы 0.09, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 31, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 228, катышы 0.08, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 32, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 228, катышы 0.07, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 33, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 228, катышы 0.06, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 34, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 228, катышы 0.05, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 35, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 228, катышы 0.05, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 36, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 228, катышы 0.04, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 37, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 109, катышы 0.04, үстүнкү чыгым (%): -46, оор көчүрүү эсептегичи: 37, учурдагы кэштөө DataBlock (%): 22 < арткы басым
чыгарылды (МБ): 798, катышы 0.24, кошумча чыгым (%): 299, оор көчүрүү эсептегичи: 38, учурдагы кэштөө DataBlock (%): 20
чыгарылды (МБ): 798, катышы 0.29, кошумча чыгым (%): 299, оор көчүрүү эсептегичи: 39, учурдагы кэштөө DataBlock (%): 18
чыгарылды (МБ): 570, катышы 0.27, кошумча чыгым (%): 185, оор көчүрүү эсептегичи: 40, учурдагы кэштөө DataBlock (%): 17
чыгарылды (МБ): 456, катышы 0.22, кошумча чыгым (%): 128, оор көчүрүү эсептегичи: 41, учурдагы кэштөө DataBlock (%): 16
чыгарылды (МБ): 342, катышы 0.16, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 42, учурдагы кэштөө DataBlock (%): 16
чыгарылды (МБ): 342, катышы 0.11, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 43, учурдагы кэштөө DataBlock (%): 16
чыгарылды (МБ): 228, катышы 0.09, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 44, учурдагы кэштөө DataBlock (%): 16
чыгарылды (МБ): 228, катышы 0.07, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 45, учурдагы кэштөө DataBlock (%): 16
чыгарылды (МБ): 228, катышы 0.05, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 46, учурдагы кэштөө DataBlock (%): 16
чыгарылды (МБ): 222, катышы 0.04, кошумча чыгым (%): 11, оор көчүрүү эсептегичи: 47, учурдагы кэштөө DataBlock (%): 16
чыгарылды (МБ): 104, катышы 0.03, кошумча чыгым (%): -48, оор чыгаруу эсептегичи: 47, учурдагы кэштөө DataBlock (%): 21 < үзгүлтүккө учурайт
чыгарылды (МБ): 684, катышы 0.2, кошумча чыгым (%): 242, оор көчүрүү эсептегичи: 48, учурдагы кэштөө DataBlock (%): 19
чыгарылды (МБ): 570, катышы 0.23, кошумча чыгым (%): 185, оор көчүрүү эсептегичи: 49, учурдагы кэштөө DataBlock (%): 18
чыгарылды (МБ): 342, катышы 0.22, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 50, учурдагы кэштөө DataBlock (%): 18
чыгарылды (МБ): 228, катышы 0.21, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 51, учурдагы кэштөө DataBlock (%): 18
чыгарылды (МБ): 228, катышы 0.2, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 52, учурдагы кэштөө DataBlock (%): 18
чыгарылды (МБ): 228, катышы 0.18, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 53, учурдагы кэштөө DataBlock (%): 18
чыгарылды (МБ): 228, катышы 0.16, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 54, учурдагы кэштөө DataBlock (%): 18
чыгарылды (МБ): 228, катышы 0.14, кошумча чыгым (%): 14, оор көчүрүү эсептегичи: 55, учурдагы кэштөө DataBlock (%): 18
чыгарылды (МБ): 112, катышы 0.14, үстүнкү чыгым (%): -44, оор көчүрүү эсептегичи: 55, учурдагы кэштөө DataBlock (%): 23 < арткы басым
чыгарылды (МБ): 456, катышы 0.26, кошумча чыгым (%): 128, оор көчүрүү эсептегичи: 56, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.31, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 57, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 58, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 59, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 60, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 61, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 62, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 63, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.32, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 64, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 65, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 66, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.32, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 67, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 68, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.32, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 69, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.32, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 70, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 71, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 72, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 73, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 74, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 75, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 342, катышы 0.33, кошумча чыгым (%): 71, оор көчүрүү эсептегичи: 76, учурдагы кэштөө DataBlock (%): 22
чыгарылды (МБ): 21, катышы 0.33, кошумча чыгым (%): -90, оор чыгаруу эсептегичи: 76, учурдагы кэштөө DataBlock (%): 32
чыгарылды (МБ): 0, катышы 0.0, кошумча чыгым (%): -100, оор чыгаруу эсептегичи: 0, учурдагы кэштөө DataBlock (%): 100
чыгарылды (МБ): 0, катышы 0.0, кошумча чыгым (%): -100, оор чыгаруу эсептегичи: 0, учурдагы кэштөө DataBlock (%): 100

Скандоолор ошол эле процессти эки кэш бөлүмдөрүнүн - жалгыз (мурда эч качан талап кылынбаган блоктор) жана көп (бул жерде жок дегенде бир жолу "суралган" маалыматтар сакталат) ортосундагы өз ара байланыштын графиги түрүндө көрсөтүү үчүн керек болгон.

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Акырында, параметрлердин иштеши график түрүндө кандай болот. Салыштыруу үчүн, кэш башында толугу менен өчүрүлгөн, андан кийин HBase кэштөө менен ишке киргизилген жана оптималдаштыруу иштеринин башталышын 5 мүнөткө кечиктирген (30 чыгаруу цикли).

Толук кодду Тартуу өтүнүчүнөн тапса болот HBASE 23887 github боюнча.

Бирок, секундасына 300 миң окуу бул шарттарда бул аппараттык камсыздоодо жетишүүгө мүмкүн болгон нерсе эмес. Чындыгында, HDFS аркылуу берилиштерге жетүү керек болгондо, тармактын өз ара аракеттенүүсүн болтурбай, маалыматтарга түз кирүүгө мүмкүндүк берүүчү ShortCircuitCache (мындан ары - SSC) механизми колдонулат.

Профильдештирүү көрсөткөндөй, бул механизм чоң пайда бергени менен, ал да кандайдыр бир учурда бут тосууга айланат, анткени дээрлик бардык оор операциялар кулпу ичинде ишке ашат, бул көпчүлүк учурда блокадага алып келет.

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Муну түшүнүп, биз көз карандысыз SSC массивдерин түзүү менен көйгөйдү айланып өтүүгө болорун түшүндүк:

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

Анан алар менен иштөө, кесилиштерди кошпогондо, акыркы офсеттик санда:

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

Эми сиз сыноону баштасаңыз болот. Бул үчүн, биз HDFS файлдарын жөнөкөй көп жиптүү тиркеме менен окуйбуз. Параметрлерди коюңуз:

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

Жана жөн гана файлдарды окуңуз:

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

Бул код өзүнчө жиптерде аткарылат жана биз бир эле учурда окулуучу файлдардын санын (10дон 200гө чейин - горизонталдык огу) жана кэштердин санын (1ден 10го чейин - графика) көбөйтөбүз. Вертикалдуу огу бир гана кэш болгон учурга салыштырмалуу SSC көбөйүшүнөн келип чыккан ылдамданууну көрсөтөт.

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Графиканы кантип окуу керек: Бир кэш менен 100 КБ блоктордо 64 миң окуу үчүн аткаруу убактысы 78 секундду талап кылат. Ал эми 5 кэш менен 16 секунд талап кылынат. Ошол. ~5 эсе ылдамдатуу бар. Графиктен көрүнүп тургандай, аз сандагы параллелдүү окуулар үчүн эффект анча байкалбайт, ал 50дөн ашык жипти окуганда байкаларлык роль ойной баштайт.Ошондой эле 6дан SSC саны көбөйгөндүгү байкалат. жана жогоруда бир кыйла азыраак өндүрүмдүүлүктү жогорулатат.

Эскертүү 1: сыноонун натыйжалары бир топ туруксуз болгондуктан (төмөндө караңыз), 3 чуркоо жүргүзүлүп, натыйжадагы маанилер орточо алынган.

Эскертүү 2: Кокус кирүүнү конфигурациялоонун натыйжасы бирдей, бирок кирүүнүн өзү бир аз жайыраак.

Бирок, бул HBase менен болгон учурдан айырмаланып, бул тездетүү дайыма эле бекер эмес экенин тактоо зарыл. Бул жерде биз процессордун кулпуларга илинбей, көбүрөөк иштөө мүмкүнчүлүгүн "кулпусун ачабыз".

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Бул жерде, жалпысынан, кэштердин санынын көбөйүшү CPU колдонуунун болжолдуу пропорционалдуу өсүшүн камсыздай тургандыгын байкай аласыз. Бирок, бир аз көбүрөөк утуп комбинациялар бар.

Мисалы, SSC = 3 орнотуусун жакшыраак карап көрөлү. диапазондо өндүрүмдүүлүктүн өсүшү болжол менен 3.3 эсеге жетет. Төмөндө үч өзүнчө чуркоолордун жыйынтыгы келтирилген.

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Ал эми CPU керектөө болжол менен 2.8 эсеге көбөйөт. Айырмасы анча деле чоң эмес, бирок кичинекей Грета буга чейин эле бактылуу жана мектепке барып, сабак алганга убактысы болушу мүмкүн.

Ошентип, бул HDFSге жапырт кирүү мүмкүнчүлүгүн колдонгон ар кандай курал үчүн оң таасирин тийгизет (мисалы, Spark ж.б.), эгерде тиркеме коду жеңил болсо (б.а. сайгыч HDFS кардар тарабында) жана CPU бош кубаттуулугу бар болсо. . Текшерүү үчүн, келгиле, HBaseден окуу үчүн BlockCache оптималдаштыруу жана SSC ​​тюнингди чогуу колдонуу кандай натыйжа берерин текшерип көрөлү.

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Көрүнүп тургандай, мындай шарттарда эффект такталган тесттердегидей чоң эмес (эч кандай иштетүүсүз окуу), бирок бул жерден кошумча 80K сыгып алуу толук мүмкүн. Экөө тең оптималдаштыруу 4 эсе ылдамдыкты камсыз кылат.

Бул оптималдаштыруу үчүн пиар да жасалган [HDFS-15202], ал бириктирилген жана бул функция келечектеги чыгарылыштарда жеткиликтүү болот.

Акыр-аягы, Кассандра жана HBase сыяктуу кеңири тилкелүү маалымат базасынын окуу көрсөткүчтөрүн салыштыруу кызыктуу болду.

Бул үчүн, биз эки хосттон (бардыгы 800 жип) стандарттык YCSB жүктөөнү сыноо утилитасынын нускаларын ишке киргиздик. Сервер тарапта - 4 хостто RegionServer жана Кассандранын 4 инстанциясы (алардын таасиринен качуу үчүн кардарлар иштеп жаткандар эмес). Окуулар өлчөмдөгү таблицалардан келди:

HBase – HDFS боюнча 300 ГБ (100 ГБ таза маалымат)

Кассандра - 250 ГБ (репликация фактору = 3)

Ошол. көлөмү болжол менен бирдей болгон (HBaseде бир аз көбүрөөк).

HBase параметрлери:

dfs.client.short.circuit.num = 5 (HDFS кардар оптималдаштыруу)

hbase.lru.cache.heavy.evction.count.limit = 30 - бул патч 30 чыгаруудан кийин иштей баштайт дегенди билдирет (~5 мүнөт)

hbase.lru.cache.heavy.eviction.mb.size.limit = 300 — кэштөө жана чыгаруунун максаттуу көлөмү

YCSB журналдары талданып, Excel графиктерине түзүлдү:

HBaseден окуу ылдамдыгын 3 эсеге жана HDFSден 5 эсеге чейин кантип жогорулатуу керек

Көрүнүп тургандай, бул оптималдаштыруу ушул шарттарда бул маалымат базаларынын иштешин салыштырууга жана секундасына 450 миң окууга жетишүүгө мүмкүндүк берет.

Бул маалымат өндүрүмдүүлүк үчүн кызыктуу күрөш учурунда кимдир бирөө үчүн пайдалуу болот деп үмүттөнөбүз.

Source: www.habr.com

Комментарий кошуу