Apache Ignite هندسة المعاملات

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



جانبا المطلوب: Apache Ignite Cluster



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







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







كيف تعمل المعاملات في Apache Ignite



تفرض بنية الكتلة في Apache Ignite مطلبًا معينًا على آلية المعاملة: اتساق البيانات في بيئة موزعة. هذا يعني أنه يجب تغيير البيانات الموجودة على العقد المختلفة بشكل كلي من حيث مبادئ ACID . هناك عدد من البروتوكولات المتاحة للقيام بما تريد. يستخدم Apache Ignite خوارزمية التزام من مرحلتين تتكون من مرحلتين:



  • إعداد؛
  • ارتكب؛


لاحظ أنه بناءً على مستوى عزل المعاملة وآلية أخذ الأقفال وعدد من المعلمات الأخرى ، قد تتغير التفاصيل في المراحل.



دعونا نرى كيف تتم كلتا المرحلتين باستخدام المعاملة التالية كمثال:



Transaction tx = client.transactions().txStart(PESSIMISTIC, READ_COMMITTED);
client.cache(DEFAULT_CACHE_NAME).put(1, 1);
tx.commit();


مرحلة التحضير



  1. — (near node Apache Ignite) — prepare- , primary- , .
  2. primary- Prepare- backup-, , . backup- .
  3. backup- Acknowledge- primary-, , , , .




Commit



بعد تلقي رسائل تأكيد من جميع العقد التي تحتوي على أقسام أساسية ، ترسل عقدة منسق المعاملة رسالة Commit ، كما هو موضح في الشكل أدناه.







تعتبر المعاملة مكتملة في اللحظة التي يتلقى فيها منسق المعاملة جميع رسائل الإقرار.



من النظرية إلى التطبيق



للنظر في منطق المعاملة ، دعنا ننتقل إلى التتبع.



لتمكين التتبع في Apache Ignite ، اتبع الخطوات التالية:
  • ignite-opencensus OpenCensusTracingSpi tracingSpi :

    <bean class="org.apache.ignite.configuration.IgniteConfiguration">
        <property name="tracingSpi">
            <bean class="org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi"/>
        </property>
    </bean>
    






    IgniteConfiguration cfg = new IgniteConfiguration();
    
    cfg.setTracingSpi(
        new org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi());
    


  • :



    JVM_OPTS="-DIGNITE_ENABLE_EXPERIMENTAL_COMMAND=true" ./control.sh --tracing-configuration set --scope TX --sampling-rate 1
    






    ignite.tracingConfiguration().set(
                new TracingConfigurationCoordinates.Builder(Scope.TX).build(),
                new TracingConfigurationParameters.Builder().
                        withSamplingRate(SAMPLING_RATE_ALWAYS).build());
    


    :



    • API
      JVM_OPTS="-DIGNITE_ENABLE_EXPERIMENTAL_COMMAND=true"
    • sampling-rate , , . , .
    • , SPI, . , , .


  • PESSIMISTIC, SERIALIZABLE .



    Transaction tx = client.transactions().txStart(PESSIMISTIC, SERIALIZABLE);
    client.cache(DEFAULT_CACHE_NAME).put(1, 1);
    tx.commit();




دعنا ننتقل إلى GridGain Control Center (نظرة عامة مفصلة عن الأداة) ونلقي نظرة على شجرة الامتداد الناتجة: في الرسم التوضيحي ، يمكننا أن نرى أن نطاق جذر المعاملة ، الذي تم إنشاؤه في بداية المعاملات (). TxStart call ، يولد مجموعتي امتداد مشروطتين:











  1. بدأت آلة التقاط القفل بواسطة عملية put ():

    1. transactions.near.enlist.write
    2. transactions.colocated.lock.map
  2. transactions.commit, tx.commit(), , , — prepare finish Apache Ignite (finish- commit- ).


دعنا الآن نلقي نظرة فاحصة على مرحلة التحضير للمعاملة ، والتي تبدأ من عقدة منسق المعاملة (بالقرب من العقدة في مصطلحات Apache Ignite) ، والتي تنتج المعاملات.



بمجرد الوصول إلى القسم الأساسي ، يبدأ طلب التحضير في إنشاء المعاملات. بالعودة إلى القسم الأساسي ، والذي يرسل رسالة تأكيد إلى منسق المعاملة ، على طول الطريق لإنشاء امتداد tx.near.process.prepare.response. ستكون مرحلة الإنهاء في هذا المثال مشابهة لمرحلة الإعداد ، مما يحفظنا من الحاجة إلى تحليل مفصل.



بالنقر فوق أي من الامتدادات ، سنرى المعلومات الوصفية المقابلة:







لذلك ، على سبيل المثال ، بالنسبة إلى نطاق المعاملة الجذري ، نرى أنه تم إنشاؤه على عقدة العميل 0eefd.



يمكننا أيضًا زيادة دقة تتبع المعاملات من خلال تمكين تتبع بروتوكول الاتصال.



إعداد معلمات التتبع
JVM_OPTS="-DIGNITE_ENABLE_EXPERIMENTAL_COMMAND=true" ./control.sh --tracing-configuration set --scope TX --included-scopes Communication --sampling-rate 1 --included-scopes COMMUNICATION




       ignite.tracingConfiguration().set(
           new TracingConfigurationCoordinates.Builder(Scope.TX).build(),
           new TracingConfigurationParameters.Builder().
               withIncludedScopes(Collections.singleton(Scope.COMMUNICATION)).
               withSamplingRate(SAMPLING_RATE_ALWAYS).build())








الآن لدينا إمكانية الوصول إلى معلومات حول إرسال الرسائل عبر الشبكة بين العقد العنقودية ، والتي ، على سبيل المثال ، ستساعد في الإجابة على السؤال حول ما إذا كانت المشكلة المحتملة ناجمة عن الفروق الدقيقة في اتصال الشبكة. لن نتعمق في التفاصيل ، نلاحظ فقط أن مجموعة socket.write و socket.read هي المسؤولة عن الكتابة إلى المقبس وقراءة هذه الرسالة أو تلك ، على التوالي.



معالجة الاستثناءات واسترداد الأعطال



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



قلنا أعلاه أنه في سياق المعاملات في Apache Ignite ، يمكن تمييز ثلاثة أنواع من العقد:



  • منسق المعاملات (بالقرب من العقدة) ؛
  • العقدة الأساسية للمفتاح المقابل (العقدة الأولية) ؛
  • العقد ذات الأقسام الرئيسية الاحتياطية (العقد الاحتياطية) ؛


ومرحلتان من المعاملة نفسها:

  • إعداد؛
  • إنهاء؛


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



هبوط النسخ الاحتياطي في كل من مراحل التحضير والانتهاء



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







هبوط العقدة الأولية في مرحلة التحضير



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







سقوط العقدة الأساسية في مرحلة النهاية



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







سقوط منسق المعاملات



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







ملخص



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



All Articles