كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

يعد الأداء العالي أحد المتطلبات الأساسية عند العمل مع البيانات الضخمة. في قسم تحميل البيانات في سبيربنك، نقوم بضخ جميع المعاملات تقريبًا إلى سحابة البيانات المستندة إلى Hadoop وبالتالي نتعامل مع تدفقات كبيرة حقًا من المعلومات. بطبيعة الحال، نحن نبحث دائما عن طرق لتحسين الأداء، والآن نريد أن نخبرك كيف تمكنا من تصحيح RegionServer HBase وعميل HDFS، بفضل ما تمكنا من زيادة سرعة عمليات القراءة بشكل كبير.
كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

ومع ذلك، قبل الانتقال إلى جوهر التحسينات، فإن الأمر يستحق الحديث عن القيود التي، من حيث المبدأ، لا يمكن التحايل عليها إذا كنت تجلس على محرك الأقراص الثابتة.

لماذا لا تتوافق قراءات محرك الأقراص الصلبة والوصول العشوائي السريع
كما تعلم، تقوم HBase، والعديد من قواعد البيانات الأخرى، بتخزين البيانات في كتل يبلغ حجمها عدة عشرات من الكيلوبايتات. افتراضيا هو حوالي 64 كيلو بايت. تخيل الآن أننا بحاجة إلى الحصول على 100 بايت فقط ونطلب من HBase أن يمنحنا هذه البيانات باستخدام مفتاح معين. نظرًا لأن حجم الكتلة في HFiles هو 64 كيلو بايت، فسيكون الطلب أكبر بمقدار 640 مرة (دقيقة واحدة فقط!) من اللازم.

بعد ذلك، نظرًا لأن الطلب سيمر عبر HDFS وآلية التخزين المؤقت للبيانات التعريفية الخاصة به ShortCircuitCache (والذي يسمح بالوصول المباشر إلى الملفات)، وهذا يؤدي إلى قراءة 1 ميغابايت بالفعل من القرص. ومع ذلك، يمكن تعديل ذلك باستخدام المعلمة dfs.client.read.shortcircuit.buffer.size وفي كثير من الحالات يكون من المنطقي تقليل هذه القيمة، على سبيل المثال إلى 126 كيلو بايت.

لنفترض أننا نفعل ذلك، ولكن بالإضافة إلى ذلك، عندما نبدأ في قراءة البيانات من خلال Java API، مثل وظائف مثل FileChannel.read ونطلب من نظام التشغيل قراءة الكمية المحددة من البيانات، فإنه يقرأ "فقط في حالة" مرتين أكثر ، أي. 2 كيلو بايت في حالتنا. وذلك لأن Java ليس لديها طريقة سهلة لتعيين علامة FADV_RANDOM لمنع هذا السلوك.

ونتيجة لذلك، للحصول على 100 بايت، تتم قراءة 2600 مرة أكثر تحت الغطاء. يبدو أن الحل واضح، فلنقل حجم الكتلة إلى كيلو بايت، ونضبط العلم المذكور ونحصل على تسريع تنويري كبير. لكن المشكلة هي أنه من خلال تقليل حجم الكتلة بمقدار مرتين، فإننا أيضًا نقوم بتقليل عدد البايتات المقروءة لكل وحدة زمنية بمقدار مرتين.

يمكن الحصول على بعض المكاسب من تعيين علامة FADV_RANDOM، ولكن فقط باستخدام مؤشرات ترابط عالية وبحجم كتلة يبلغ 128 كيلو بايت، ولكن هذا بحد أقصى بضع عشرات بالمائة:

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

تم إجراء الاختبارات على 100 ملف، حجم كل منها 1 جيجابايت وموجودة على 10 محركات أقراص ثابتة.

دعونا نحسب ما يمكننا، من حيث المبدأ، الاعتماد عليه بهذه السرعة:
لنفترض أننا نقرأ من 10 أقراص بسرعة 280 ميجابايت/ثانية، أي. 3 مليون مرة 100 بايت. لكن كما نتذكر فإن البيانات التي نحتاجها أقل بـ 2600 مرة مما نقرأه. وهكذا نقسم 3 ملايين على 2600 ونحصل على 1100 سجل في الثانية

الاكتئاب، أليس كذلك؟ هذه هي الطبيعة دخول عشوائي الوصول إلى البيانات الموجودة على القرص الصلب - بغض النظر عن حجم الكتلة. هذا هو الحد المادي للوصول العشوائي ولا يمكن لأي قاعدة بيانات الضغط أكثر في ظل هذه الظروف.

فكيف تحقق قواعد البيانات سرعات أعلى بكثير؟ للإجابة على هذا السؤال دعونا ننظر إلى ما يحدث في الصورة التالية:

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

هنا نرى أنه في الدقائق القليلة الأولى تبلغ السرعة حوالي ألف سجل في الثانية. ومع ذلك، علاوة على ذلك، نظرًا لحقيقة أنه تتم قراءة أكثر بكثير مما هو مطلوب، تنتهي البيانات في المخزن المؤقت/التخزين المؤقت لنظام التشغيل (لينكس) وتزداد السرعة إلى 60 ألفًا في الثانية.

وبالتالي، سنتعامل أيضًا مع تسريع الوصول فقط إلى البيانات الموجودة في ذاكرة التخزين المؤقت لنظام التشغيل أو الموجودة في أجهزة تخزين SSD/NVMe ذات سرعة وصول مماثلة.

في حالتنا، سنجري اختبارات على منصة مكونة من 4 خوادم، كل منها مكلف على النحو التالي:

وحدة المعالجة المركزية: Xeon E5-2680 v4 @ 2.40GHz 64 thread.
الذاكرة: 730 جيجابايت.
إصدار جافا: 1.8.0_111

وهنا النقطة الأساسية هي كمية البيانات التي يجب قراءتها في الجداول. الحقيقة هي أنه إذا قرأت البيانات من جدول تم وضعه بالكامل في ذاكرة التخزين المؤقت لـ HBase، فلن تتمكن حتى من القراءة من ذاكرة التخزين المؤقت/التخزين لنظام التشغيل. لأن HBase يخصص بشكل افتراضي 40% من الذاكرة لبنية تسمى BlockCache. هذا في الأساس ConcurrentHashMap، حيث المفتاح هو اسم الملف + إزاحة الكتلة، والقيمة هي البيانات الفعلية في هذه الإزاحة.

وهكذا، عند القراءة فقط من هذا الهيكل، فإننا نرى سرعة ممتازة، مثل مليون طلب في الثانية. لكن لنتخيل أننا لا نستطيع تخصيص مئات الجيجابايت من الذاكرة لاحتياجات قاعدة البيانات فقط، لأن هناك الكثير من الأشياء المفيدة الأخرى التي تعمل على هذه الخوادم.

على سبيل المثال، في حالتنا، يبلغ حجم BlockCache على RS واحد حوالي 12 جيجابايت. لقد هبطنا اثنين من RS على عقدة واحدة، أي. تم تخصيص 96 جيجابايت لـ BlockCache على جميع العقد. وهناك بيانات أكثر عدة مرات، على سبيل المثال، فليكن 4 جداول، كل منها 130 منطقة، حيث يبلغ حجم الملفات 800 ميجابايت، مضغوطة بواسطة FAST_DIFF، أي. إجمالي 410 جيجابايت (هذه بيانات خالصة، أي دون مراعاة عامل النسخ).

وبالتالي، فإن BlockCache يمثل حوالي 23% فقط من إجمالي حجم البيانات وهذا أقرب بكثير إلى الظروف الحقيقية لما يسمى BigData. وهذا هو المكان الذي تبدأ فيه المتعة - لأنه من الواضح أنه كلما قل عدد مرات النقر على ذاكرة التخزين المؤقت، كان الأداء أسوأ. بعد كل شيء، إذا فاتتك، فسيتعين عليك القيام بالكثير من العمل - أي. انتقل إلى استدعاء وظائف النظام. ومع ذلك، لا يمكن تجنب ذلك، لذلك دعونا نلقي نظرة على جانب مختلف تمامًا - ماذا يحدث للبيانات الموجودة داخل ذاكرة التخزين المؤقت؟

لنبسط الموقف ونفترض أن لدينا ذاكرة تخزين مؤقت تناسب كائنًا واحدًا فقط. فيما يلي مثال لما سيحدث عندما نحاول العمل بحجم بيانات أكبر بثلاث مرات من ذاكرة التخزين المؤقت، سيتعين علينا:

1. ضع الكتلة 1 في ذاكرة التخزين المؤقت
2. قم بإزالة الكتلة 1 من ذاكرة التخزين المؤقت
3. ضع الكتلة 2 في ذاكرة التخزين المؤقت
4. قم بإزالة الكتلة 2 من ذاكرة التخزين المؤقت
5. ضع الكتلة 3 في ذاكرة التخزين المؤقت

تم الانتهاء من 5 إجراءات! ومع ذلك، لا يمكن وصف هذا الوضع بأنه طبيعي، في الواقع، نحن نجبر HBase على القيام بمجموعة من الأعمال عديمة الفائدة تمامًا. فهو يقرأ البيانات باستمرار من ذاكرة التخزين المؤقت لنظام التشغيل، ويضعها في BlockCache، ثم يتخلص منها على الفور تقريبًا بسبب وصول جزء جديد من البيانات. تُظهر الرسوم المتحركة في بداية المنشور جوهر المشكلة - يخرج جامع القمامة عن نطاقه، والجو يزداد سخونة، وتشعر غريتا الصغيرة في السويد البعيدة والساخنة بالانزعاج. ونحن، العاملين في مجال تكنولوجيا المعلومات، لا نحب حقًا أن يشعر الأطفال بالحزن، لذلك نبدأ في التفكير فيما يمكننا فعله حيال ذلك.

ماذا لو لم تضع كل الكتل في ذاكرة التخزين المؤقت، بل وضعت نسبة معينة منها فقط، حتى لا تفيض ذاكرة التخزين المؤقت؟ لنبدأ بإضافة بضعة أسطر من التعليمات البرمجية إلى بداية وظيفة وضع البيانات في BlockCache:

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

النقطة هنا هي ما يلي: الإزاحة هي موضع الكتلة في الملف ويتم توزيع أرقامها الأخيرة بشكل عشوائي ومتساوي من 00 إلى 99. لذلك، سنتخطى فقط تلك التي تقع ضمن النطاق الذي نحتاجه.

على سبيل المثال، قم بتعيين ذاكرة التخزين المؤقت DataBlockPercent = 20 وشاهد ما سيحدث:

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

والنتيجة واضحة. في الرسوم البيانية أدناه، يصبح من الواضح سبب حدوث مثل هذا التسارع - فنحن نحفظ الكثير من موارد GC دون القيام بالعمل العبث المتمثل في وضع البيانات في ذاكرة التخزين المؤقت فقط لإلقائها على الفور في هجرة كلاب المريخ:

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

وفي الوقت نفسه، يزداد استخدام وحدة المعالجة المركزية، ولكنه أقل بكثير من الإنتاجية:

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

ومن الجدير بالذكر أيضًا أن الكتل المخزنة في BlockCache مختلفة. معظمها، حوالي 95%، هي البيانات نفسها. والباقي عبارة عن بيانات وصفية، مثل مرشحات Bloom أو LEAF_INDEX و إلخ. هذه البيانات ليست كافية، ولكنها مفيدة للغاية، لأنه قبل الوصول إلى البيانات مباشرة، يلجأ HBase إلى التعريف لفهم ما إذا كان من الضروري البحث هنا بشكل أكبر، وإذا كان الأمر كذلك، أين تقع الكتلة محل الاهتمام بالضبط.

لذلك، في الكود نرى حالة الاختيار buf.getBlockType().isData() وبفضل هذا التعريف، سنتركه في ذاكرة التخزين المؤقت على أي حال.

الآن دعونا نزيد الحمل ونشدد الميزة قليلًا دفعة واحدة. في الاختبار الأول، جعلنا نسبة القطع = 20 وكان BlockCache غير مستغل بشكل كافٍ. الآن دعنا نضبطه على 23% ونضيف 100 موضوع كل 5 دقائق لنرى عند أي نقطة يحدث التشبع:

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

نرى هنا أن النسخة الأصلية تصل على الفور تقريبًا إلى السقف بحوالي 100 ألف طلب في الثانية. في حين أن التصحيح يعطي تسارعًا يصل إلى 300 ألف. في الوقت نفسه، من الواضح أن المزيد من التسريع لم يعد "مجانيًا"، كما أن استخدام وحدة المعالجة المركزية يتزايد أيضًا.

ومع ذلك، هذا ليس حلاً أنيقًا للغاية، نظرًا لأننا لا نعرف مسبقًا النسبة المئوية للكتل التي يجب تخزينها مؤقتًا، فهذا يعتمد على ملف تعريف التحميل. ولذلك تم تطبيق آلية لضبط هذه المعلمة تلقائياً تبعاً لنشاط عمليات القراءة.

تمت إضافة ثلاثة خيارات للتحكم في ذلك:

hbase.lru.cache.heavy.eviction.count.limit - يحدد عدد المرات التي يجب أن تتم فيها عملية إزالة البيانات من ذاكرة التخزين المؤقت قبل أن نبدأ في استخدام التحسين (أي تخطي الكتل). بشكل افتراضي، يساوي MAX_INT = 2147483647 ويعني في الواقع أن الميزة لن تبدأ أبدًا في العمل بهذه القيمة. لأن عملية الإخلاء تبدأ كل 5 - 10 ثواني (يعتمد ذلك على الحمولة) و 2147483647 * 10 / 60 / 60 / 24 / 365 = 680 سنة. ومع ذلك، يمكننا ضبط هذه المعلمة على 0 وجعل الميزة تعمل فورًا بعد الإطلاق.

ومع ذلك، هناك أيضًا حمولة في هذه المعلمة. إذا كان حملنا بحيث تتخلل القراءات قصيرة المدى (على سبيل المثال خلال النهار) والقراءات طويلة المدى (في الليل) باستمرار، فيمكننا التأكد من تشغيل الميزة فقط عندما تكون عمليات القراءة الطويلة قيد التقدم.

على سبيل المثال، نحن نعلم أن القراءات قصيرة المدى تستمر عادة حوالي دقيقة واحدة. ليست هناك حاجة للبدء في التخلص من الكتل، فلن يكون لدى ذاكرة التخزين المؤقت الوقت الكافي لتصبح قديمة ومن ثم يمكننا تعيين هذه المعلمة مساوية، على سبيل المثال، لـ 1. سيؤدي هذا إلى حقيقة أن التحسين سيبدأ العمل فقط عندما تكون هناك فترة طويلة- لقد بدأ مصطلح القراءة النشطة، أي. في 10 ثانية. وبالتالي، إذا كان لدينا قراءة قصيرة المدى، فسوف تدخل جميع الكتل في ذاكرة التخزين المؤقت وستكون متاحة (باستثناء تلك التي سيتم إزالتها بواسطة الخوارزمية القياسية). وعندما نقوم بقراءات طويلة المدى، يتم تشغيل الميزة وسيكون لدينا أداء أعلى بكثير.

hbase.lru.cache.heavy.eviction.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%

على العكس من ذلك، ستعمل الميزة على زيادة النسبة المئوية للكتل المخزنة مؤقتًا حتى يصبح الحمل الزائد موجبًا.

فيما يلي مثال لكيفية ظهور ذلك على البيانات الحقيقية. ليست هناك حاجة لمحاولة الوصول إلى 0%، فهذا مستحيل. إنه جيد جدًا عندما يكون حوالي 30 - 100٪، وهذا يساعد على تجنب الخروج المبكر من وضع التحسين أثناء الزيادات قصيرة المدى.

hbase.lru.cache.heavy.eviction.overhead.coefficiency - يحدد مدى السرعة التي نرغب بها في الحصول على النتيجة. إذا علمنا على وجه اليقين أن قراءاتنا طويلة في الغالب ولا نريد الانتظار، فيمكننا زيادة هذه النسبة والحصول على أداء عالي بشكل أسرع.

على سبيل المثال، قمنا بتعيين هذا المعامل = 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 (يُمكنها).

في السجلات أدناه نرى كيفية تشغيل الميزة وإعادة تعيين التجاوز إلى 14-71%. من وقت لآخر ينخفض ​​الحمل، مما يؤدي إلى تشغيل Backpressure وHBase وتخزين المزيد من الكتل مرة أخرى.

سجل خادم المنطقة
تم الإخلاء (ميجابايت): 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
الإخلاء (MB): 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
تم الإخلاء (MB): 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
الإخلاء (MB): 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 دورة إخلاء).

يمكن العثور على الكود الكامل في طلب السحب هباسي 23887 على جيثب.

ومع ذلك، فإن 300 ألف قراءة في الثانية ليس كل ما يمكن تحقيقه على هذا الجهاز في ظل هذه الظروف. الحقيقة هي أنه عندما تحتاج إلى الوصول إلى البيانات عبر HDFS، يتم استخدام آلية ShortCircuitCache (المشار إليها فيما يلي باسم SSC)، والتي تتيح لك الوصول إلى البيانات مباشرة، وتجنب تفاعلات الشبكة.

أظهر التنميط أنه على الرغم من أن هذه الآلية تعطي مكاسب كبيرة، إلا أنها تصبح أيضًا في مرحلة ما عنق الزجاجة، لأن جميع العمليات الثقيلة تقريبًا تحدث داخل القفل، مما يؤدي إلى الحظر في معظم الأوقات.

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

وبعد أن أدركنا ذلك، أدركنا أنه يمكن التحايل على المشكلة عن طريق إنشاء مجموعة من مراكز الخدمات المشتركة المستقلة:

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 قراءة للخيط، ومن الملاحظ أيضا أن زيادة عدد SSCs من 6 وما فوق يعطي زيادة في الأداء أصغر بكثير.

ملاحظة 1: نظرًا لأن نتائج الاختبار متقلبة جدًا (انظر أدناه)، فقد تم إجراء 3 عمليات وتم حساب متوسط ​​القيم الناتجة.

ملاحظة 2: مكاسب الأداء من تكوين الوصول العشوائي هي نفسها، على الرغم من أن الوصول نفسه أبطأ قليلاً.

ومع ذلك، من الضروري توضيح أنه، على عكس HBase، فإن هذا التسريع ليس مجانيًا دائمًا. نحن هنا "نفتح" قدرة وحدة المعالجة المركزية على أداء المزيد من العمل، بدلاً من تعليقها على الأقفال.

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

هنا يمكنك ملاحظة أن الزيادة في عدد ذاكرات التخزين المؤقت تؤدي بشكل عام إلى زيادة متناسبة تقريبًا في استخدام وحدة المعالجة المركزية. ومع ذلك، هناك مجموعات أكثر فائزة قليلاً.

على سبيل المثال، دعونا نلقي نظرة فاحصة على الإعداد SSC = 3. تبلغ الزيادة في الأداء على النطاق حوالي 3.3 مرة. فيما يلي النتائج من جميع العمليات الثلاثة المنفصلة.

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

بينما يزيد استهلاك وحدة المعالجة المركزية بنحو 2.8 مرة. الفرق ليس كبيرًا جدًا، لكن غريتا الصغيرة سعيدة بالفعل وقد يكون لديها الوقت للذهاب إلى المدرسة وتلقي الدروس.

وبالتالي، سيكون لهذا تأثير إيجابي على أي أداة تستخدم الوصول المجمع إلى HDFS (على سبيل المثال Spark، وما إلى ذلك)، بشرط أن يكون رمز التطبيق خفيف الوزن (أي أن القابس موجود على جانب عميل HDFS) وأن تكون هناك طاقة مجانية لوحدة المعالجة المركزية . للتحقق، دعونا نختبر تأثير الاستخدام المشترك لتحسين BlockCache وضبط SSC للقراءة من HBase.

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

يمكن أن نرى أنه في ظل هذه الظروف، فإن التأثير ليس كبيرا كما هو الحال في الاختبارات المكررة (القراءة دون أي معالجة)، ولكن من الممكن تماما الضغط على 80 ألف إضافية هنا. يوفر كلا التحسينات معًا سرعة تصل إلى 4x.

تم إجراء العلاقات العامة أيضًا لهذا التحسين [HDFS-15202]، والتي تم دمجها وستكون هذه الوظيفة متاحة في الإصدارات المستقبلية.

وأخيرًا، كان من المثير للاهتمام مقارنة أداء القراءة لقاعدة بيانات مماثلة ذات أعمدة عريضة، Cassandra وHBase.

للقيام بذلك، أطلقنا مثيلات لأداة اختبار التحميل YCSB القياسية من مضيفين (إجمالي 800 سلسلة). على جانب الخادم - 4 مثيلات لـ RegionServer وCassandra على 4 مضيفين (ليست تلك التي يعمل فيها العملاء، لتجنب تأثيرهم). القراءات جاءت من جداول الحجم:

HBase - 300 جيجابايت على HDFS (100 جيجابايت من البيانات النقية)

كاساندرا - 250 جيجابايت (عامل النسخ = 3)

أولئك. كان الحجم هو نفسه تقريبًا (في HBase أكثر قليلاً).

معلمات HBase:

dfs.client.short.circuit.num = 5 (تحسين عميل HDFS)

hbase.lru.cache.heavy.eviction.count.limit = 30 - وهذا يعني أن التصحيح سيبدأ العمل بعد 30 عملية إخلاء (حوالي 5 دقائق)

hbase.lru.cache.heavy.eviction.mb.size.limit = 300 - الحجم المستهدف للتخزين المؤقت والإخلاء

تم تحليل سجلات YCSB وتجميعها في رسوم بيانية في Excel:

كيفية زيادة سرعة القراءة من HBase حتى 3 مرات ومن HDFS حتى 5 مرات

كما ترون، تتيح هذه التحسينات مقارنة أداء قواعد البيانات هذه في ظل هذه الظروف وتحقيق 450 ألف قراءة في الثانية.

نأمل أن تكون هذه المعلومات مفيدة لشخص ما خلال الصراع المثير من أجل الإنتاجية.

المصدر: www.habr.com

إضافة تعليق