تحسين الأداء لمجموعات Apache Kafka HDInsight

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

نظرة عامة على الهندسة

تُستخدم مواضيع Kafka لتنظيم السجلات. ينتج المنتجون سجلات، ويستهلكها المستهلكون. ويُرسل المنتجون سجلات إلى سماسرة Kafka الذين يخزنون البيانات بعد ذلك. كل عقدة عامل في مجموعة HDInsight الخاص بك هي وسيط Kafka.

مواضيع قسم السجلات عبر الوسطاء. عند استهلاك السجلات، يمكنك استخدام ما يصل إلى مستهلك واحد لكل قسم لتحقيق المعالجة المتوازية للبيانات.

يُستخدم النسخ المتماثل لتكرار الأقسام عبر العقد. يحمي هذا القسم من انقطاع العقدة (الوسيط). يتم تعيين قسم واحد بين مجموعة النسخ المتماثلة على أنه قائد القسم. يتم توجيه حركة مرور المنتج إلى قائد كل عقدة، وذلك باستخدام الدولة التي تديرها ZooKeeper.

تحديد السيناريو الخاص بك

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

  • معدل النقل العالي، زمن الانتقال المنخفض. يتطلب هذا السيناريو كلا من معدل النقل العالي، زمن الانتقال المنخفض (~ 100 مللي ثانية). أحد الأمثلة على هذا النوع من التطبيقات هو مراقبة توفر الخدمة.
  • معدل النقل العالي، زمن الانتقال العالي. يتطلب هذا السيناريو معدل نقل عالية (حوالي 1.5 غيغابايت في الثانية) ولكن يمكنه تحمل زمن انتقال أعلى (< 250 مللي ثانية). أحد الأمثلة على هذا النوع من التطبيقات هو استيعاب بيانات تتبع الاستخدام للعمليات في الوقت شبه الحقيقي مثل تطبيقات الكشف عن الأمان والتطفل.
  • مُعدل النقل المنخفض، زمن الانتقال المنخفض. يتطلب هذا السيناريو وقت استجابة منخفضاً (< 10 مللي ثانية) للمعالجة في الوقت الحقيقي، ولكن يمكنه تحمل انخفاض المعدل نقل. أحد الأمثلة على هذا النوع من التطبيقات هو التدقيق الإملائي والنحوي عبر الإنترنت.

تكوينات المُنتِج فقط

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

حجم الدفعة

يقوم منتجو Apache Kafka بتجميع مجموعات من الرسائل (تسمى الدفعات) التي تُرسل كوحدة ليتم تخزينها في قسم تخزين واحد. حجم الدفعة يعني عدد وحدات البايت التي يجب أن تكون موجودة قبل إرسال هذه المجموعة. يمكن أن تعمل batch.sizeزيادة المعلمة على زيادة معدل النقل لأنه يقلل من حمل المعالجة من طلبات IO وشبكة الاتصال. تحت الحمل الخفيف، قد يزيد حجم الدفعة المتزايدة من زمن إرسال Kafka حيث ينتظر المنتج أن تكون الدفعة جاهزة. تحت تحميل كثيف، من المستحسن زيادة حجم الدفعة لتحسين معدل النقل وزمن الانتقال.

إقرارات المُنتِج المطلوبة

يحدد التكوين المطلوب للمنتج acks عدد الاعترافات المطلوبة من قِبل قائد القسم قبل اعتبار طلب الكتابة مكتملاً. يؤثر هذا الإعداد على موثوقية البيانات ويأخذ قيم 0، 1 أو -1. قيمة -1 يَعني أنه يجب تلقي إعلام من كافة النسخ المتماثلة قبل اكتمال الكتابة. يوفر الإعداد acks = -1 ضمانات أقوى ضد فقدان البيانات، ولكنه يؤدي أيضًا إلى زمن انتقال أعلى ومعدل نقل أقل. إذا كانت متطلبات التطبيق تتطلب معدل نقل أعلى، جرب الإعداد acks = 0 أو acks = 1. ضَع في اعتبارك أن عدم الاعتراف بجميع النسخ المتماثلة يمكن أن يقلل من موثوقية البيانات.

الضغط

يمكن تكوين منتج Kafka لضغط الرسائل قبل إرسالها إلى الوسطاء. compression.typeيُحدد الإعداد برنامج ترميز الضغط ليتم استخدامه. برامج ترميز الضغط المعتمدة هي "gzip" و "snappy" و "lz4". يُعد الضغط مفيدًا ويجب أخذه في الاعتبار إذا كان هناك قيود على سعة القرص.

يمتلك برنامج من بين اثنين من برامج ضغط الوسائط وفكها شائعة الاستخدام، gzip، snappy و، gzip نسبة ضغط أعلى، ما يؤدي إلى انخفاض استخدام القرص على حساب تحميل وحدة المعالجة المركزية أعلى. snappyيوفر برنامج ضغط الوسائط وفكها ضغطًا أقل مع حمل أقل لـ CPU. يمكنك أن تقرر استخدام أي برنامج ضغط وسائط وفكها على أساس القرص وسيط أو المنتج قيود CPU. gzip يُمكن ضغط البيانات بمعدل خمس مرات أعلى من snappy.

يؤدي ضغط البيانات إلى زيادة عدد السجلات التي يمكن تخزينها على قرص. كما قد يزيد من النفقات العامة لـ CPU في الحالات التي يكون فيها عدم التطابق بين تنسيقات الضغط المستخدمة من قِبل المنتج والوسيط. كما يجب ضغط البيانات قبل الإرسال ثم إلغاء ضغطها قبل المعالجة.

إِعدادات الوسيط

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

عدد الأقراص

تحتوي أقراص التخزين على IOPS محدودة (عمليات الإدخال/الإخراج في الثانية) وقراءة/كتابة بايت في الثانية. عند إنشاء أقسام جديدة، يخزن Kafka كل قسم جديد على القرص مع أقل عدد من الأقسام الموجودة لتحقيق التوازن بينها عبر الأقراص المتاحة. على الرغم من إستراتيجية التخزين، عند معالجة مئات النسخ المتماثلة لقسم على كل قرص، يمكن لـ Kafka بسهولة استيعاب معدل النقل إلى القرص المتاح. المفاضلة هنا بين معدل النقل والتكلفة. إذا كان التطبيق يتطلب معدل نقل أكبر، قم بإنشاء كتلة مع أقراص مُدارة أكثر لكل وسيط. لا يدعم HDInsight حاليًا إضافة أقراص مُدارة إلى كتلة قيد التشغيل. لمزيدٍ من المعلومات حول كيفية تكوين عدد الأقراص المُدارة، انظر تكوين التخزين وقابلية التوسع لـ Apache Kafka على HDInsight. فِهم الآثار المترتبة على تكلفة زيادة مساحة التخزين للعقد في الكتلة الخاصة بك.

عدد الموضوعات والأقسام

يكتب منتجو Kafka الموضوعات. يقرأ مستهلكو Kafka من الموضوعات. يرتبط الموضوع بسجل، وهو عبارة عن بنية بيانات على القرص. يُلحق Kafka السجلات من المنتج (المنتجين) بنهاية سجل الموضوع. يَتكون سجل الموضوعات من العديد من الأقسام التي تنتشر على ملفات متعددة. هذه الملفات، بدورها، تنتشر عبر عدة عقد نظام مجموعة Kafka. يقرأ المستهلكون من مواضيع Kafka في إيقاعهم ويمكنهم اختيار موقفهم (موازنة) في سجل الموضوع.

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

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

بالنسبة إلى مجموعات Apache Kafka 2.1 و2.4 وكما هو مشار إليه من قبل في HDInsight، نوصيك بالحصول على 2000 قسم كحد أقصى لكل وسيط، بما في ذلك النسخ المتماثلة. زيادة عدد الأقسام لكل وسيط تقلل معدل النقل وقد تتسبب أيضًا في عدم توفر الموضوع. لمزيدٍ من المعلومات حول دعم قسم Kafka، انظر منشور مدونة Apache Kafka الرسمي حول زيادة عدد الأقسام المدعومة في الإصدار 1.1.0. للحصول على تفاصيل حول تعديل الموضوعات، انظر Apache Kafka: تعديل الموضوعات.

عدد النسخ المتماثلة

يُؤدي عامل النسخ المتماثل الأعلى إلى طلبات إضافية بين قائد القسم والمتابعين. وبالتالي، يستهلك عامل النسخ المتماثل الأعلى المزيد من الأقراص وCPU للتعامل مع الطلبات الإضافية، ما يؤدي إلى زيادة زمن انتقال الكتابة وتقليل معدل النقل.

نوصي باستخدام النسخ المتماثل 3x على الأقل لـ Kafka فيAzure HDInsight. تحتوي معظم مناطق Azure على ثلاثة مجالات خطأ، ولكن في المناطق التي تحتوي على مجالي خطأ فقط، يلزم على المستخدمين استخدام النسخ المتماثل 4x.

لمزيدٍ من المعلومات حول النسخ المتماثل، انظر Apache Kafka: النسخ المتماثل و Apache Kafka: زيادة عامل النسخ المتماثل.

تكوينات المستهلك

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

عدد المستهلكين

من الممارسات الجيدة أن يكون عدد الأقسام مساوياً لعدد المستهلكين. إذا كان عدد المستهلكين أقل من عدد الأقسام، فإن عددا قليلا من المستهلكين يقرأ من أقسام متعددة، ما يزيد من زمن انتقال المستهلك.

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

تجنب إعادة التوازن للمستهلك بشكل متكرر

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

يعتبر المستهلكون على قيد الحياة إذا كان بإمكانهم إرسال نبضات قلب إلى وسيط في session.timeout.ms. وإلا، يعتبر المستهلك ميتا أو فاشلا. يؤدي هذا التأخير إلى إعادة توازن المستهلك. خفض المستهلك session.timeout.ms، أسرع يمكننا اكتشاف تلك الإخفاقات.

إذا كان session.timeout.ms منخفضاً جداً، فقد يواجه المستهلك عمليات إعادة توازن متكررة غير ضرورية، بسبب سيناريوهات مثل عندما تستغرق مجموعة من الرسائل وقتاً أطول للمعالجة أو عندما يستغرق إيقاف JVM GC المؤقت وقتاً طويلاً. إذا كان لديك مستهلك يقضي الكثير من الوقت في معالجة الرسائل، فيمكنك معالجة هذا إما عن طريق زيادة الحد الأقصى لمقدار الوقت الذي يمكن أن يكون فيه المستهلك خاملاً قبل جلب المزيد من السجلات باستخدام max.poll.interval.ms أو عن طريق تقليل الحد الأقصى لحجم الدُفعات عاد مع معلمة التكوين max.poll.records.

الدفعات

مثل المنتجين، يمكننا إضافة تجميع للمستهلكين. يمكن تكوين مقدار البيانات التي يمكن للمستهلكين الحصول عليها في كل طلب جلب عن طريق تغيير التكوين fetch.min.bytes. تحدد هذه المعلمة الحد الأدنى من وحدات البايت المتوقعة من استجابة إحضار المستهلك. تؤدي زيادة هذه القيمة إلى تقليل عدد طلبات الإحضار المقدمة إلى الوسيط، وبالتالي تقليل النفقات الإضافية. بشكل افتراضي، هذه القيمة هي 1. وبالمثل، هناك تكوين آخر fetch.max.wait.ms. إذا لم يكن طلب الإحضار يحتوي على رسائل كافية وفقا لحجم fetch.min.bytes، فإنه ينتظر حتى انتهاء وقت الانتظار استنادا إلى هذا التكوين fetch.max.wait.ms.

إشعار

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

ضبط نظام التشغيل Linux مع حمل العمل الثقيل

خرائط الذاكرة

يحدد vm.max_map_count الحد الأقصى لعدد mmap الذي يمكن أن تحتويه العملية. بشكل افتراضي، في HDInsight Apache Kafka نظام المجموعة Linux VM، القيمة هي 65535.

في Apache Kafka، يتطلب كل مقطع سجل زوجا من ملفات الفهرس/timeindex، ويستهلك كل ملف من هذه الملفات مماب واحد. بمعنى آخر، يستخدم كل مقطع سجل ممتين. وبالتالي، إذا كان كل قسم يستضيف مقطع سجل واحد، فإنه يتطلب الحد الأدنى من 2 mmap. يختلف عدد مقاطع السجل لكل قسم وفقاً لحجم المقطع وكثافة التحميل ونهج الاستبقاء وفترة التدوير ويميل عموماً إلى أن يكون أكثر من قسم. Mmap value = 2*((partition size)/(segment size))*(partitions)

إذا تجاوزت قيمة mmap المطلوبة vm.max_map_count، فسيقوم الوسيط برفع استثناء "فشل الخريطة".

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

# command to find number of index files:
find . -name '*index' | wc -l

# command to view vm.max_map_count for a process:
cat /proc/[kafka-pid]/maps | wc -l

# command to set the limit of vm.max_map_count:
sysctl -w vm.max_map_count=<new_mmap_value>

# This will make sure value remains, even after vm is rebooted:
echo 'vm.max_map_count=<new_mmap_value>' >> /etc/sysctl.conf
sysctl -p

إشعار

كن حذراً بشأن ضبط هذا على مستوى عالٍ جداً لأنه يشغل ذاكرة على الجهاز الظاهري. يتم تحديد مقدار الذاكرة المسموح باستخدامها بواسطة JVM على خرائط الذاكرة من خلال الإعداد MaxDirectMemory. القيمة الافتراضية هي 64 ميغابايت. من الممكن أن يتم الوصول إلى هذا. يمكنك زيادة هذه القيمة عن طريق إضافة -XX:MaxDirectMemorySize=amount of memory used في إعدادات JVM من خلال Ambari. كن على دراية بحجم الذاكرة المستخدمة على العقدة وإذا كان هناك ذاكرة وصول عشوائي متوفرة كافية لدعم ذلك.

الخطوات التالية