HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Katta ma'lumotlar bilan ishlashda yuqori unumdorlik asosiy talablardan biridir. Sberbank ma'lumotlarini yuklash bo'limida biz deyarli barcha tranzaktsiyalarni Hadoop-ga asoslangan ma'lumotlar bulutiga joylashtiramiz va shuning uchun haqiqatan ham katta ma'lumotlar oqimlari bilan shug'ullanamiz. Tabiiyki, biz har doim ishlashni yaxshilash yo'llarini qidiramiz va endi biz sizga RegionServer HBase va HDFS mijozini qanday tuzatishga muvaffaq bo'lganimizni aytib bermoqchimiz, buning natijasida biz o'qish operatsiyalari tezligini sezilarli darajada oshira oldik.
HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Biroq, yaxshilanishlarning mohiyatiga o'tishdan oldin, agar siz HDD-da o'tirsangiz, printsipial jihatdan chetlab bo'lmaydigan cheklovlar haqida gapirishga arziydi.

Nima uchun HDD va tezkor tasodifiy kirish o'qishlari mos kelmaydi
Ma'lumki, HBase va boshqa ko'plab ma'lumotlar bazalari ma'lumotlarni bir necha o'nlab kilobayt hajmdagi bloklarda saqlaydi. Odatiy bo'lib, u taxminan 64 KB ni tashkil qiladi. Endi tasavvur qiling-a, biz atigi 100 bayt olishimiz kerak va biz HBase-dan ma'lum bir kalit yordamida ushbu ma'lumotlarni bizga berishini so'raymiz. HFiles-dagi blok hajmi 64 KB bo'lganligi sababli, so'rov zarur bo'lganidan 640 baravar katta bo'ladi (atigi bir daqiqa!).

Keyinchalik, so'rov HDFS va uning metadata keshlash mexanizmi orqali o'tadi ShortCircuitCache (bu fayllarga to'g'ridan-to'g'ri kirish imkonini beradi), bu diskdan allaqachon 1 MB o'qishga olib keladi. Biroq, bu parametr bilan sozlanishi mumkin dfs.client.read.shortcircuit.bufer.size va ko'p hollarda bu qiymatni, masalan, 126 KB ga kamaytirish mantiqan.

Aytaylik, biz buni qilamiz, lekin bundan tashqari, FileChannel.read kabi funksiyalar kabi java api orqali maʼlumotlarni oʻqishni boshlaganimizda va operatsion tizimdan belgilangan hajmdagi maʼlumotlarni oʻqishni soʻrasak, u “har holda” 2 barobar koʻp oʻqiydi. , ya'ni. Bizning holatda 256 KB. Buning sababi, java'da bu xatti-harakatning oldini olish uchun FADV_RANDOM bayrog'ini o'rnatishning oson usuli yo'q.

Natijada, bizning 100 baytimizni olish uchun kaput ostida 2600 marta ko'proq o'qiladi. Ko'rinishidan, yechim aniq, keling, blok hajmini bir kilobaytgacha kamaytiramiz, yuqorida aytib o'tilgan bayroqni o'rnatamiz va katta ma'rifiy tezlashuvga erishamiz. Ammo muammo shundaki, blok hajmini 2 baravar kamaytirish orqali biz vaqt birligi uchun o'qiladigan baytlar sonini 2 baravar kamaytiramiz.

FADV_RANDOM bayrog'ini o'rnatishdan bir oz foyda olish mumkin, lekin faqat yuqori ko'p tarmoqli va 128 KB blok hajmi bilan, lekin bu maksimal bir necha o'n foizni tashkil qiladi:

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Sinovlar har biri 100 GB hajmdagi va 1 ta HDDda joylashgan 10 ta faylda o'tkazildi.

Keling, ushbu tezlikda nimaga ishonishimiz mumkinligini hisoblaylik:
Aytaylik, biz 10 ta diskdan 280 MB/sek tezlikda o'qiymiz, ya'ni. 3 million marta 100 bayt. Ammo biz eslaganimizdek, bizga kerak bo'lgan ma'lumotlar o'qilganidan 2600 baravar kam. Shunday qilib, biz 3 millionni 2600 ga bo'lamiz va olamiz Bir soniyada 1100 ta yozuv.

Tushkunlikka soladi, shunday emasmi? Bu tabiat Tasodifiy kirish HDD-dagi ma'lumotlarga kirish - blok hajmidan qat'i nazar. Bu tasodifiy kirishning jismoniy chegarasi va hech qanday ma'lumotlar bazasi bunday sharoitlarda ko'proq siqib chiqa olmaydi.

Qanday qilib ma'lumotlar bazalari ancha yuqori tezlikka erishadi? Bu savolga javob berish uchun keling, quyidagi rasmda nima sodir bo'layotganini ko'rib chiqaylik:

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Bu erda biz birinchi daqiqalarda tezlik haqiqatan ham sekundiga mingta rekordni tashkil etishini ko'ramiz. Biroq, so'ralgandan ko'ra ko'proq o'qilganligi sababli, ma'lumotlar operatsion tizimning (linux) buff/keshida tugaydi va tezligi sekundiga 60 mingga ko'tariladi.

Shunday qilib, biz faqat OS keshidagi yoki SSD/NVMe xotira qurilmalarida joylashgan ma'lumotlarga kirishni tezlashtirish bilan shug'ullanamiz.

Bizning holatda, biz 4 ta serverdan iborat skameykada sinovlarni o'tkazamiz, ularning har biri quyidagicha to'lanadi:

Protsessor: Xeon E5-2680 v4 @ 2.40 gigagertsli 64 ta ip.
Xotira: 730 GB.
java versiyasi: 1.8.0_111

Va bu erda asosiy nuqta - o'qilishi kerak bo'lgan jadvallardagi ma'lumotlar miqdori. Haqiqat shundaki, agar siz HBase keshiga to'liq joylashtirilgan jadvaldagi ma'lumotlarni o'qisangiz, u operatsion tizimning buff/keshini o'qishga ham kelmaydi. Chunki HBase sukut bo'yicha xotiraning 40% BlockCache deb nomlangan tuzilishga ajratadi. Aslini olganda, bu ConcurrentHashMap bo'lib, bu erda kalit fayl nomi + blokning ofsetidir va qiymat bu ofsetdagi haqiqiy ma'lumotlardir.

Shunday qilib, faqat ushbu tuzilmadan o'qiyotganda, biz ajoyib tezlikni ko'ramiz, soniyada million so'rov kabi. Tasavvur qilaylik, biz yuzlab gigabayt xotirani faqat ma'lumotlar bazasi ehtiyojlari uchun ajrata olmaymiz, chunki bu serverlarda boshqa foydali narsalar ham ko'p.

Masalan, bizning holatlarimizda bitta RS-dagi BlockCache hajmi taxminan 12 GB ni tashkil qiladi. Biz ikkita RSni bitta tugunga qo'ydik, ya'ni. Barcha tugunlarda BlockCache uchun 96 GB ajratilgan. Va bir necha marta ko'proq ma'lumotlar mavjud, masalan, 4 ta jadval, har biri 130 ta mintaqa bo'lsin, unda fayllar 800 MB hajmga ega, FAST_DIFF tomonidan siqilgan, ya'ni. jami 410 GB (bu sof ma'lumotlar, ya'ni replikatsiya faktorini hisobga olmagan holda).

Shunday qilib, BlockCache umumiy ma'lumotlar hajmining atigi 23% ni tashkil qiladi va bu BigData deb ataladigan real sharoitlarga ancha yaqinroqdir. Qiziq shu erda boshlanadi - aniqki, kesh qancha kam bo'lsa, ishlash shunchalik yomon bo'ladi. Axir, agar siz sog'insangiz, siz juda ko'p ish qilishingiz kerak bo'ladi - ya'ni. qo'ng'iroq qilish tizimi funktsiyalariga o'ting. Biroq, buning oldini olish mumkin emas, shuning uchun keling, butunlay boshqa jihatni ko'rib chiqaylik - kesh ichidagi ma'lumotlar bilan nima sodir bo'ladi?

Keling, vaziyatni soddalashtiramiz va bizda faqat 1 ob'ektga mos keladigan kesh bor deb faraz qilaylik. Mana, keshdan 3 baravar kattaroq ma'lumotlar hajmi bilan ishlashga harakat qilganimizda nima sodir bo'lishining misoli:

1. 1-blokni keshga joylashtiring
2. 1-blokni keshdan olib tashlang
3. 2-blokni keshga joylashtiring
4. 2-blokni keshdan olib tashlang
5. 3-blokni keshga joylashtiring

5 ta amal bajarildi! Biroq, bu holatni normal deb atash mumkin emas, aslida biz HBase-ni mutlaqo foydasiz ishlarni bajarishga majbur qilamiz. U doimiy ravishda OS keshidagi ma'lumotlarni o'qiydi, uni BlockCache-ga joylashtiradi, faqat ma'lumotlarning yangi qismi kelganligi sababli uni deyarli darhol o'chirib tashlaydi. Xabar boshidagi animatsiya muammoning mohiyatini ko'rsatadi - Chiqindilarni yig'uvchi miqyosdan chiqib ketmoqda, atmosfera qizib bormoqda, uzoq va issiq Shvetsiyadagi kichkina Greta xafa bo'lmoqda. Va biz IT xodimlari bolalarning qayg'uli bo'lishini yoqtirmaymiz, shuning uchun biz bu haqda nima qilishimiz mumkinligi haqida o'ylay boshlaymiz.

Kesh to'lib ketmasligi uchun barcha bloklarni emas, balki faqat ma'lum bir foizini keshga qo'ysangiz nima bo'ladi? BlockCache-ga ma'lumotlarni joylashtirish uchun funktsiyaning boshiga oddiygina bir necha qator kod qo'shishdan boshlaylik:

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

Bu yerda gap quyidagilardan iborat: ofset fayldagi blokning o‘rni va uning oxirgi raqamlari 00 dan 99 gacha tasodifiy va teng taqsimlanadi. Shuning uchun biz faqat kerakli diapazonga kiradiganlarni o‘tkazib yuboramiz.

Masalan, cacheDataBlockPercent = 20 ni o'rnating va nima bo'lishini ko'ring:

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Buning natijasi aniq. Quyidagi grafiklarda nima uchun bunday tezlashuv sodir bo'lganligi aniq bo'ladi - biz ma'lumotlarni keshga joylashtirish bo'yicha Sisyphean ishini bajarmasdan, ko'plab GC resurslarini tejaymiz, faqat uni darhol marslik itlarning kanaliga tashlash uchun:

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Shu bilan birga, protsessordan foydalanish oshadi, lekin unumdorlikdan ancha past:

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Shuni ham ta'kidlash kerakki, BlockCache-da saqlangan bloklar boshqacha. Ko'pchilik, taxminan 95%, ma'lumotlarning o'zi. Qolganlari esa Bloom filtrlari yoki LEAF_INDEX va kabi metadata va boshqalar.. Bu ma'lumotlar yetarli emas, lekin bu juda foydali, chunki ma'lumotlarga to'g'ridan-to'g'ri kirishdan oldin, HBase bu erda qo'shimcha qidirish kerakmi yoki yo'qligini tushunish uchun meta-ga murojaat qiladi va agar shunday bo'lsa, qiziqish bloki aynan qayerda joylashgan.

Shuning uchun kodda biz tekshirish shartini ko'ramiz buf.getBlockType().isData() va bu meta tufayli biz uni har qanday holatda keshda qoldiramiz.

Endi yukni ko'paytiramiz va bir vaqtning o'zida xususiyatni biroz tortamiz. Birinchi sinovda biz kesish foizini = 20 ni tashkil qildik va BlockCache biroz kam foydalanildi. Keling, uni 23% ga o'rnatamiz va to'yinganlik qaysi nuqtada sodir bo'lishini ko'rish uchun har 100 daqiqada 5 ta ip qo'shamiz:

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Bu erda biz original versiya deyarli darhol shiftga sekundiga 100 ming so'rovni urganini ko'ramiz. Yamoq esa 300 minggacha tezlashtirishni beradi. Shu bilan birga, keyingi tezlashtirish endi unchalik "bepul" emasligi aniq, protsessordan foydalanish ham ortib bormoqda.

Biroq, bu juda oqlangan yechim emas, chunki biz bloklarning qancha foizini keshlash kerakligini oldindan bilmaymiz, bu yuk profiliga bog'liq. Shu sababli, ushbu parametrni o'qish operatsiyalari faolligiga qarab avtomatik ravishda sozlash mexanizmi amalga oshirildi.

Buni boshqarish uchun uchta variant qo'shildi:

hbase.lru.cache.heavy.evaction.count.limit — optimallashtirishdan foydalanishni boshlashdan oldin (ya'ni bloklarni o'tkazib yuborish) keshdan ma'lumotlarni o'chirish jarayoni necha marta bajarilishi kerakligini belgilaydi. Odatiy bo'lib, u MAX_INT = 2147483647 ga teng va aslida bu xususiyat hech qachon bu qiymat bilan ishlamasligini bildiradi. Chunki ko'chirish jarayoni har 5 - 10 soniyada boshlanadi (bu yukga bog'liq) va 2147483647 * 10/60/60/24/365 = 680 yil. Biroq, biz ushbu parametrni 0 ga o'rnatishimiz va funksiyani ishga tushirilgandan so'ng darhol ishlashini ta'minlashimiz mumkin.

Biroq, bu parametrda foydali yuk ham mavjud. Agar bizning yukimiz shunday bo'lsa, qisqa muddatli o'qishlar (aytaylik, kunduzi) va uzoq muddatli o'qishlar (kechasi) doimiy ravishda kesishib tursa, biz bu xususiyat faqat uzoq o'qish operatsiyalari bajarilayotganda yoqilganligiga ishonch hosil qilishimiz mumkin.

Misol uchun, biz bilamizki, qisqa muddatli o'qishlar odatda taxminan 1 daqiqa davom etadi. Bloklarni tashlashni boshlashning hojati yo'q, kesh eskirishga vaqt topa olmaydi va keyin biz ushbu parametrni, masalan, 10 ga tenglashtira olamiz. Bu optimallashtirish faqat uzoq vaqt davomida ishlay boshlaydi. muddatli faol o'qish boshlandi, ya'ni. 100 soniyada. Shunday qilib, agar biz qisqa muddatli o'qishga ega bo'lsak, unda barcha bloklar keshga kiradi va mavjud bo'ladi (standart algoritm tomonidan chiqarib yuboriladiganlardan tashqari). Va biz uzoq muddatli o'qishlar qilganimizda, funksiya yoqiladi va biz ancha yuqori ishlashga ega bo'lamiz.

hbase.lru.cache.heavy.evition.mb.size.limit — 10 soniya ichida keshga qancha megabayt joylashtirmoqchi ekanligimizni (va, albatta, chiqarib tashlashni) belgilaydi. Funktsiya ushbu qiymatga erishishga va uni saqlab qolishga harakat qiladi. Gap shundaki: agar biz gigabaytlarni keshga joylashtirsak, gigabaytlarni chiqarib tashlashimiz kerak bo'ladi va bu, yuqorida ko'rganimizdek, juda qimmat. Biroq, siz uni juda kichik qilib o'rnatishga urinmasligingiz kerak, chunki bu blokni o'tkazib yuborish rejimidan muddatidan oldin chiqishiga olib keladi. Kuchli serverlar uchun (taxminan 20-40 jismoniy yadro) taxminan 300-400 MB o'rnatish maqbuldir. O'rta sinf uchun (~10 yadro) 200-300 MB. Zaif tizimlar uchun (2-5 yadroli) 50-100 MB normal bo'lishi mumkin (bularda sinovdan o'tkazilmagan).

Keling, bu qanday ishlashini ko'rib chiqaylik: deylik, hbase.lru.cache.heavy.eviction.mb.size.limit = 500 ni o'rnatdik, qandaydir yuk (o'qish) mavjud va keyin har ~10 soniyada biz qancha bayt borligini hisoblaymiz. formula yordamida chiqarib yuboriladi:

Qo'shimcha xarajatlar = Bo'shatilgan baytlar summasi (MB) * 100 / Limit (MB) - 100;

Agar haqiqatda 2000 MB chiqarilgan bo'lsa, u holda Umumjahon quyidagilarga teng:

2000 * 100 / 500 - 100 = 300%

Algoritmlar bir necha o'n foizdan ko'p bo'lmagan holda saqlashga harakat qiladi, shuning uchun xususiyat keshlangan bloklar foizini kamaytiradi va shu bilan avtomatik sozlash mexanizmini amalga oshiradi.

Biroq, agar yuk tushib qolsa, deylik, atigi 200 MB chiqarib tashlandi va Overhead salbiy bo'ladi (ortiqcha o'tish deb ataladi):

200 * 100 / 500 - 100 = -60%

Aksincha, funksiya keshlangan bloklar foizini "Umumiy yuk" ijobiy holga kelguncha oshiradi.

Quyida bu haqiqiy ma'lumotlarda qanday ko'rinishiga misol keltirilgan. 0% ga erishishga harakat qilishning hojati yo'q, bu mumkin emas. Taxminan 30 - 100% bo'lsa, bu juda yaxshi, bu qisqa muddatli kuchlanish paytida optimallashtirish rejimidan muddatidan oldin chiqib ketishning oldini olishga yordam beradi.

hbase.lru.cache.heavy.evaction.overhead.koeffitsienti - natijaga qanchalik tez erishmoqchi ekanligimizni belgilaydi. Agar biz o'qishlarimiz asosan uzoq ekanligini va kutishni istamasligimizni aniq bilsak, biz bu nisbatni oshirib, tezroq yuqori ishlashga erishishimiz mumkin.

Misol uchun, biz ushbu koeffitsientni = 0.01 o'rnatamiz. Bu shuni anglatadiki, qo'shimcha xarajatlar (yuqoriga qarang) natijada ushbu raqamga ko'paytiriladi va keshlangan bloklar ulushi kamayadi. Faraz qilaylik, qo'shimcha yuk = 300% va koeffitsient = 0.01, keyin keshlangan bloklar ulushi 3% ga kamayadi.

Shunga o'xshash "Backpressure" mantig'i salbiy Overhead (ortiqcha o'tish) qiymatlari uchun ham amalga oshiriladi. O'qish va ko'chirish hajmining qisqa muddatli o'zgarishi har doim ham mumkin bo'lganligi sababli, ushbu mexanizm optimallashtirish rejimidan muddatidan oldin chiqib ketishdan qochish imkonini beradi. Orqa bosim teskari mantiqqa ega: haddan tashqari o'tish qanchalik kuchli bo'lsa, ko'proq bloklar keshlanadi.

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Amalga oshirish kodi

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

Keling, bularning barchasini haqiqiy misol yordamida ko'rib chiqaylik. Bizda quyidagi test skripti mavjud:

  1. Skanlashni boshlaylik (25 ta mavzu, to'plam = 100)
  2. 5 daqiqadan so'ng, multi-get qo'shing (25 ta mavzu, partiya = 100)
  3. 5 daqiqadan so'ng multi-getlarni o'chiring (faqat skanerlash yana qoladi)

Biz ikkita yugurishni qilamiz, birinchi navbatda hbase.lru.cache.heavy.eviction.count.limit = 10000 (bu xususiyatni o'chirib qo'yadi) va keyin limit = 0 (uni yoqadi) o'rnating.

Quyidagi jurnallarda biz funksiya qanday yoqilganligini va Overshootingni 14-71% ga tiklaganini ko'ramiz. Vaqti-vaqti bilan yuk kamayadi, bu esa Backpressure-ni yoqadi va HBase yana bloklarni keshlaydi.

RegionServer jurnali
evakuatsiya qilingan (MB): 0, nisbat 0.0, qo'shimcha xarajatlar (%): -100, og'ir ko'chirish hisoblagichi: 0, joriy kesh DataBlock (%): 100
evakuatsiya qilingan (MB): 0, nisbat 0.0, qo'shimcha xarajatlar (%): -100, og'ir ko'chirish hisoblagichi: 0, joriy kesh DataBlock (%): 100
quvilgan (MB): 2170, nisbat 1.09, qoʻshimcha xarajatlar (%): 985, ogʻir koʻchirish hisoblagichi: 1, joriy keshlash DataBlock (%): 91 < boshlash
quvilgan (MB): 3763, nisbat 1.08, qoʻshimcha xarajatlar (%): 1781, ogʻir koʻchirish hisoblagichi: 2, joriy kesh DataBlock (%): 76
quvilgan (MB): 3306, nisbat 1.07, qoʻshimcha xarajatlar (%): 1553, ogʻir koʻchirish hisoblagichi: 3, joriy kesh DataBlock (%): 61
quvilgan (MB): 2508, nisbat 1.06, qoʻshimcha xarajatlar (%): 1154, ogʻir koʻchirish hisoblagichi: 4, joriy kesh DataBlock (%): 50
quvilgan (MB): 1824, nisbat 1.04, qoʻshimcha xarajatlar (%): 812, ogʻir koʻchirish hisoblagichi: 5, joriy kesh DataBlock (%): 42
quvilgan (MB): 1482, nisbat 1.03, qoʻshimcha xarajatlar (%): 641, ogʻir koʻchirish hisoblagichi: 6, joriy kesh DataBlock (%): 36
quvilgan (MB): 1140, nisbat 1.01, qoʻshimcha xarajatlar (%): 470, ogʻir koʻchirish hisoblagichi: 7, joriy kesh DataBlock (%): 32
quvilgan (MB): 913, nisbat 1.0, qoʻshimcha xarajatlar (%): 356, ogʻir koʻchirish hisoblagichi: 8, joriy kesh DataBlock (%): 29
quvilgan (MB): 912, nisbat 0.89, qoʻshimcha xarajatlar (%): 356, ogʻir koʻchirish hisoblagichi: 9, joriy kesh DataBlock (%): 26
quvilgan (MB): 684, nisbat 0.76, qoʻshimcha xarajatlar (%): 242, ogʻir koʻchirish hisoblagichi: 10, joriy kesh DataBlock (%): 24
quvilgan (MB): 684, nisbat 0.61, qoʻshimcha xarajatlar (%): 242, ogʻir koʻchirish hisoblagichi: 11, joriy kesh DataBlock (%): 22
quvilgan (MB): 456, nisbat 0.51, qoʻshimcha xarajatlar (%): 128, ogʻir koʻchirish hisoblagichi: 12, joriy kesh DataBlock (%): 21
quvilgan (MB): 456, nisbat 0.42, qoʻshimcha xarajatlar (%): 128, ogʻir koʻchirish hisoblagichi: 13, joriy kesh DataBlock (%): 20
quvilgan (MB): 456, nisbat 0.33, qoʻshimcha xarajatlar (%): 128, ogʻir koʻchirish hisoblagichi: 14, joriy kesh DataBlock (%): 19
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 15, joriy kesh DataBlock (%): 19
quvilgan (MB): 342, nisbat 0.32, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 16, joriy kesh DataBlock (%): 19
quvilgan (MB): 342, nisbat 0.31, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 17, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.3, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 18, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.29, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 19, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.27, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 20, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.25, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 21, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.24, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 22, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.22, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 23, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.21, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 24, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.2, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 25, joriy kesh DataBlock (%): 19
quvilgan (MB): 228, nisbat 0.17, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 26, joriy kesh DataBlock (%): 19
evakuatsiya qilingan (MB): 456, nisbat 0.17, qo'shimcha xarajatlar (%): 128, og'ir ko'chirish hisoblagichi: 27, joriy kesh DataBlock (%): 18 < qo'shilgan oladi (lekin jadval bir xil)
quvilgan (MB): 456, nisbat 0.15, qoʻshimcha xarajatlar (%): 128, ogʻir koʻchirish hisoblagichi: 28, joriy kesh DataBlock (%): 17
quvilgan (MB): 342, nisbat 0.13, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 29, joriy kesh DataBlock (%): 17
quvilgan (MB): 342, nisbat 0.11, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 30, joriy kesh DataBlock (%): 17
quvilgan (MB): 342, nisbat 0.09, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 31, joriy kesh DataBlock (%): 17
quvilgan (MB): 228, nisbat 0.08, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 32, joriy kesh DataBlock (%): 17
quvilgan (MB): 228, nisbat 0.07, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 33, joriy kesh DataBlock (%): 17
quvilgan (MB): 228, nisbat 0.06, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 34, joriy kesh DataBlock (%): 17
quvilgan (MB): 228, nisbat 0.05, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 35, joriy kesh DataBlock (%): 17
quvilgan (MB): 228, nisbat 0.05, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 36, joriy kesh DataBlock (%): 17
quvilgan (MB): 228, nisbat 0.04, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 37, joriy kesh DataBlock (%): 17
evakuatsiya qilingan (MB): 109, nisbat 0.04, qo'shimcha xarajatlar (%): -46, og'ir ko'chirish hisoblagichi: 37, joriy kesh DataBlock (%): 22 < orqa bosim
quvilgan (MB): 798, nisbat 0.24, qoʻshimcha xarajatlar (%): 299, ogʻir koʻchirish hisoblagichi: 38, joriy kesh DataBlock (%): 20
quvilgan (MB): 798, nisbat 0.29, qoʻshimcha xarajatlar (%): 299, ogʻir koʻchirish hisoblagichi: 39, joriy kesh DataBlock (%): 18
quvilgan (MB): 570, nisbat 0.27, qoʻshimcha xarajatlar (%): 185, ogʻir koʻchirish hisoblagichi: 40, joriy kesh DataBlock (%): 17
quvilgan (MB): 456, nisbat 0.22, qoʻshimcha xarajatlar (%): 128, ogʻir koʻchirish hisoblagichi: 41, joriy kesh DataBlock (%): 16
quvilgan (MB): 342, nisbat 0.16, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 42, joriy kesh DataBlock (%): 16
quvilgan (MB): 342, nisbat 0.11, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 43, joriy kesh DataBlock (%): 16
quvilgan (MB): 228, nisbat 0.09, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 44, joriy kesh DataBlock (%): 16
quvilgan (MB): 228, nisbat 0.07, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 45, joriy kesh DataBlock (%): 16
quvilgan (MB): 228, nisbat 0.05, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 46, joriy kesh DataBlock (%): 16
quvilgan (MB): 222, nisbat 0.04, qoʻshimcha xarajatlar (%): 11, ogʻir koʻchirish hisoblagichi: 47, joriy kesh DataBlock (%): 16
evakuatsiya qilingan (MB): 104, nisbat 0.03, qo'shimcha xarajatlar (%): -48, og'ir ko'chirish hisoblagichi: 47, joriy kesh DataBlock (%): 21 < uzilishlar oladi
quvilgan (MB): 684, nisbat 0.2, qoʻshimcha xarajatlar (%): 242, ogʻir koʻchirish hisoblagichi: 48, joriy kesh DataBlock (%): 19
quvilgan (MB): 570, nisbat 0.23, qoʻshimcha xarajatlar (%): 185, ogʻir koʻchirish hisoblagichi: 49, joriy kesh DataBlock (%): 18
quvilgan (MB): 342, nisbat 0.22, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 50, joriy kesh DataBlock (%): 18
quvilgan (MB): 228, nisbat 0.21, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 51, joriy kesh DataBlock (%): 18
quvilgan (MB): 228, nisbat 0.2, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 52, joriy kesh DataBlock (%): 18
quvilgan (MB): 228, nisbat 0.18, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 53, joriy kesh DataBlock (%): 18
quvilgan (MB): 228, nisbat 0.16, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 54, joriy kesh DataBlock (%): 18
quvilgan (MB): 228, nisbat 0.14, qoʻshimcha xarajatlar (%): 14, ogʻir koʻchirish hisoblagichi: 55, joriy kesh DataBlock (%): 18
evakuatsiya qilingan (MB): 112, nisbat 0.14, qo'shimcha xarajatlar (%): -44, og'ir ko'chirish hisoblagichi: 55, joriy kesh DataBlock (%): 23 < orqa bosim
quvilgan (MB): 456, nisbat 0.26, qoʻshimcha xarajatlar (%): 128, ogʻir koʻchirish hisoblagichi: 56, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.31, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 57, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 58, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 59, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 60, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 61, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 62, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 63, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.32, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 64, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 65, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 66, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.32, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 67, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 68, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.32, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 69, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.32, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 70, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 71, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 72, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 73, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 74, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 75, joriy kesh DataBlock (%): 22
quvilgan (MB): 342, nisbat 0.33, qoʻshimcha xarajatlar (%): 71, ogʻir koʻchirish hisoblagichi: 76, joriy kesh DataBlock (%): 22
evakuatsiya qilingan (MB): 21, nisbat 0.33, qo'shimcha xarajatlar (%): -90, og'ir ko'chirish hisoblagichi: 76, joriy kesh DataBlock (%): 32
evakuatsiya qilingan (MB): 0, nisbat 0.0, qo'shimcha xarajatlar (%): -100, og'ir ko'chirish hisoblagichi: 0, joriy kesh DataBlock (%): 100
evakuatsiya qilingan (MB): 0, nisbat 0.0, qo'shimcha xarajatlar (%): -100, og'ir ko'chirish hisoblagichi: 0, joriy kesh DataBlock (%): 100

Skanerlar bir xil jarayonni ikkita kesh bo'limi o'rtasidagi munosabatlar grafigi ko'rinishida ko'rsatish uchun kerak edi - bitta (bu erda hech qachon so'ralmagan bloklar) va ko'p (bu erda kamida bir marta "so'ralgan" ma'lumotlar saqlanadi):

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Va nihoyat, parametrlarning ishlashi grafik ko'rinishida qanday ko'rinadi. Taqqoslash uchun, boshida kesh butunlay o'chirilgan, keyin HBase keshlash va optimallashtirish ishining boshlanishini 5 daqiqaga kechiktirish bilan ishga tushirildi (30 evakuatsiya davri).

To'liq kodni Pull Request-da topish mumkin HBASE 23887 github-da.

Biroq, sekundiga 300 ming o'qish bu shartlar ostida ushbu uskunada erishish mumkin bo'lgan narsa emas. Gap shundaki, HDFS orqali ma'lumotlarga kirish kerak bo'lganda, tarmoq o'zaro ta'siridan qochib, ma'lumotlarga to'g'ridan-to'g'ri kirish imkonini beruvchi ShortCircuitCache (keyingi o'rinlarda SSC) mexanizmi qo'llaniladi.

Profiling shuni ko'rsatdiki, bu mexanizm katta daromad keltirsa-da, u ham bir nuqtada to'siq bo'lib qoladi, chunki deyarli barcha og'ir operatsiyalar qulf ichida sodir bo'ladi, bu esa ko'pincha blokirovka qilishga olib keladi.

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Buni tushunib, biz mustaqil SSClar majmuasini yaratish orqali muammoni chetlab o'tish mumkinligini tushundik:

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

Va keyin ular bilan ishlang, oxirgi ofset raqamidagi kesishmalar bundan mustasno:

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

Endi siz sinovni boshlashingiz mumkin. Buning uchun biz HDFS dan fayllarni oddiy ko'p tarmoqli dastur bilan o'qiymiz. Parametrlarni o'rnating:

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

Va shunchaki fayllarni o'qing:

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

Ushbu kod alohida oqimlarda bajariladi va biz bir vaqtning o'zida o'qiladigan fayllar sonini (10 dan 200 gacha - gorizontal o'q) va keshlar sonini (1 dan 10 gacha - grafik) ko'paytiramiz. Vertikal o'q faqat bitta kesh mavjud bo'lgan holatga nisbatan SSC ning ortishi natijasida yuzaga keladigan tezlanishni ko'rsatadi.

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Grafikni qanday o'qish kerak: Bitta kesh bilan 100 KB bloklarda 64 ming o'qish uchun bajarish vaqti 78 soniyani talab qiladi. 5 kesh bilan esa 16 soniya davom etadi. Bular. ~5 marta tezlashuv mavjud. Grafikdan ko'rinib turibdiki, kam sonli parallel o'qishlar uchun ta'sir unchalik sezilmaydi, u 50 dan ortiq o'qilgan iplar mavjud bo'lganda sezilarli rol o'ynay boshlaydi.Shuningdek, SSC sonini 6 tadan ko'paytirish ham seziladi. va undan yuqorisi sezilarli darajada kichikroq ishlash o'sishini beradi.

Eslatma 1: sinov natijalari juda o'zgaruvchan bo'lganligi sababli (pastga qarang), 3 ta yugurish o'tkazildi va natijada olingan qiymatlar o'rtacha baholandi.

Eslatma 2: Tasodifiy kirishni sozlashdan unumdorlik bir xil bo'ladi, garchi kirishning o'zi biroz sekinroq.

Biroq, HBase-dan farqli o'laroq, bu tezlashtirish har doim ham bepul emasligini aniqlashtirish kerak. Bu erda biz protsessorning qulflarga osib qo'yish o'rniga, ko'proq ishlash qobiliyatini "ochamiz".

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Bu erda, umuman olganda, keshlar sonining ko'payishi protsessordan foydalanishning taxminan proportsional o'sishiga olib kelishini kuzatishingiz mumkin. Biroq, bir oz ko'proq qozongan kombinatsiyalar mavjud.

Misol uchun, SSC = 3 sozlamalarini batafsil ko'rib chiqaylik. Diapazonda ishlashning o'sishi taxminan 3.3 marta. Quyida uchta alohida yugurish natijalari keltirilgan.

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Protsessor iste'moli taxminan 2.8 baravar oshadi. Farqi unchalik katta emas, lekin kichkina Greta allaqachon xursand va maktabga borish va dars olishga vaqt topishi mumkin.

Shunday qilib, bu HDFS ga ommaviy kirishdan foydalanadigan har qanday vosita uchun ijobiy ta'sir ko'rsatadi (masalan, Spark va boshqalar), agar dastur kodi engil bo'lsa (ya'ni, vilka HDFS mijoz tomonida bo'lsa) va protsessorning bepul quvvati mavjud bo'lsa. . Tekshirish uchun keling, HBase-dan o'qish uchun BlockCache optimallashtirish va SSC sozlashidan birgalikda foydalanish qanday ta'sir ko'rsatishini sinab ko'raylik.

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Ko'rinib turibdiki, bunday sharoitlarda ta'sir nozik testlardagi kabi katta emas (hech qanday ishlov berishsiz o'qish), lekin bu erda qo'shimcha 80K ni siqib chiqarish mumkin. Ikkala optimallashtirish birgalikda 4x gacha tezlikni ta'minlaydi.

Ushbu optimallashtirish uchun PR ham amalga oshirildi [HDFS-15202], u birlashtirilgan va bu funksiya kelgusi versiyalarda mavjud bo'ladi.

Va nihoyat, shunga o'xshash keng ustunli ma'lumotlar bazasi Cassandra va HBase ning o'qish samaradorligini solishtirish qiziq edi.

Buning uchun biz ikkita xostdan (jami 800 ta mavzu) standart YCSB yuk sinovi yordam dasturining namunalarini ishga tushirdik. Server tomonida - 4 ta xostda RegionServer va Cassandra ning 4 ta nusxasi (mijozlar ishlaydiganlar emas, ularning ta'siridan qochish uchun). O'qishlar o'lcham jadvallaridan olingan:

HBase - HDFS-da 300 GB (100 GB sof ma'lumot)

Kassandra - 250 GB (replikatsiya omili = 3)

Bular. hajmi taxminan bir xil edi (HBase-da biroz ko'proq).

HBase parametrlari:

dfs.client.short.circuit.num = 5 (HDFS mijozni optimallashtirish)

hbase.lru.cache.heavy.eviction.count.limit = 30 - bu yamoq 30 quvilganidan keyin ishlay boshlaydi (~5 daqiqa)

hbase.lru.cache.heavy.eviction.mb.size.limit = 300 — keshlash va chiqarishning maqsadli hajmi

YCSB jurnallari tahlil qilindi va Excel grafiklariga kompilyatsiya qilindi:

HBase-dan o'qish tezligini 3 barobarga va HDFS-dan 5 baravargacha oshirish

Ko'rib turganingizdek, ushbu optimallashtirishlar ushbu ma'lumotlar bazalarining ish faoliyatini ushbu sharoitlarda taqqoslash va soniyada 450 ming o'qishga erishish imkonini beradi.

Umid qilamizki, bu ma'lumot unumdorlik uchun qiziqarli kurash paytida kimgadir foydali bo'ladi.

Manba: www.habr.com

a Izoh qo'shish