خرطوشة Tarantool: مشاركة Lua Backend في ثلاثة خطوط


في Mail.ru Group ، لدينا Tarantool ، خادم تطبيقات قائم على Lua وقاعدة بيانات موحدة. إنه سريع وأنيق ، لكن موارد خادم واحد محدودة دائمًا. التحجيم العمودي هو أيضا ليس الدواء الشافي. هذا هو السبب في أن Tarantool لديه بعض الأدوات للتحجيم الأفقي ، أو الوحدة vshard [1] . يتيح لك نشر البيانات عبر خوادم متعددة ، ولكن عليك أن تتعرف عليها لفترة من الوقت لتكوينها والتربص على منطق العمل.

خبر سار: حصلنا على حصتنا من المطبات (على سبيل المثال ، [2] ، [3] ) وقمنا بإنشاء إطار عمل آخر ، مما يسهل بشكل كبير حل هذه المشكلة.

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

إذن ما المشكلة بالضبط؟


لدينا تارانتول و vshard - ماذا نريد أكثر؟

أولاً ، إنها مسألة راحة. تم تكوين Vshard في جداول Lua. ولكن لكي يعمل نظام موزع من عدة عمليات Tarantool بشكل صحيح ، يجب أن يكون التكوين كما هو في كل مكان. لن يرغب أحد في القيام بذلك يدويًا ، لذا يتم استخدام جميع أنواع البرامج النصية والبصرية وأنظمة النشر.

تدير Cartridge نفسها تكوين vshard استنادًا إلى التكوين الموزع الخاص بها . في الواقع ، إنه ملف YAML بسيط ، ويتم تخزين نسخته على كل مثيل من Tarantool. بمعنى آخر ، يراقب الإطار تكوينه بحيث يكون هو نفسه في كل مكان.

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

لقد حللنا هذه المشكلات مرارًا وتكرارًا ، وفي مرحلة ما ، تمكنا من تطوير نهج من أجل تبسيط العمل مع التطبيق طوال دورة حياته الكاملة: الإنشاء ، التطوير ، الاختبار ، CI / CD ، الصيانة.

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

الملامح الرئيسية لخرطوشة Tarantool:

  • تزامن الكتلة الآلي.
  • توسيع وظائف التطبيق مع أدوار جديدة ؛
  • قالب التطبيق لتطوير ونشر.
  • المدمج في تقاسم التلقائي.
  • التكامل مع الإطار الأخير.
  • إدارة الكتلة باستخدام WebUI و API ؛
  • أدوات التغليف والنشر.

مرحبا العالم!


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

$ tarantoolctl rocks install cartridge-cli $ export PATH=$PWD/.rocks/bin/:$PATH 

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

 $ cartridge create --name myapp 

وهنا ما حصلنا عليه:

 myapp/ ├── .git/ ├── .gitignore ├── app/roles/custom.lua ├── deps.sh ├── init.lua ├── myapp-scm-1.rockspec ├── test │ ├── helper │ │ ├── integration.lua │ │ └── unit.lua │ ├── helper.lua │ ├── integration/api_test.lua │ └── unit/sample_test.lua └── tmp/ 

هذا مستودع بوابة مزود بـ "Hello، World!" التطبيق. دعنا نحاول تشغيله بعد تثبيت التبعيات (بما في ذلك الإطار نفسه):

 $ tarantoolctl rocks make $ ./init.lua --http-port 8080 

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

تطوير التطبيقات


تخيل أننا نصمم نظامًا يجب أن يتلقى البيانات وحفظه وإنشاء تقرير مرة واحدة يوميًا.


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


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


ليس هناك معنى كبير في الحفاظ على vshard-router والعبارة في حالات منفصلة. لماذا نذهب عبر الشبكة مرة أخرى ، إذا كانت هذه هي بالفعل مسؤولية جهاز التوجيه؟ يجب أن تعمل ضمن نفس العملية ، أي يجب تهيئة كل من البوابة و vshard.router.cfg في نفس العملية ، والتفاعل محليًا.

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


وعندما يتعلق الأمر بالنشر إلى التدريج أو الإنتاج ، فإننا نقوم بتعيين مجموعة منفصلة من الأدوار لكل عملية Tarantool اعتمادًا على إمكانيات الأجهزة الأساسية:


إدارة الطوبولوجيا


يجب علينا أيضًا تخزين معلومات حول الأدوار الجارية في مكان ما. و "مكان ما" يعني التكوين الموزع المذكور أعلاه. الشيء الأكثر أهمية هنا هو طوبولوجيا الكتلة. هنا يمكنك أن ترى 3 مجموعات النسخ المتماثل من 5 عمليات Tarantool:


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

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


دور دورة حياة


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

 function init() function validate_config() function apply_config() function stop() 

كل دور لديه وظيفة init . يطلق عليه مرة واحدة: إما عند تمكين الدور ، أو عند إعادة تشغيل Tarantool. من السهل هنا ، على سبيل المثال ، تهيئة box.space.create ، أو يمكن لجدولة تشغيل بعض الألياف الخلفية التي من شأنها إكمال المهمة على فترات منتظمة.

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

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

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

يمكن أن تتفاعل الأدوار مع بعضها البعض. لقد اعتدنا على كتابة استدعاءات دالة Lua ، لكن العملية قد لا يكون لها الدور الضروري. لتسهيل الوصول إلى الشبكة ، نستخدم وحدة نمطية إضافية تسمى rpc (استدعاء الإجراء عن بُعد) ، والتي بنيت على أساس وحدة Tarantool net.box القياسية. يمكن أن يكون هذا مفيدًا ، على سبيل المثال ، إذا كانت البوابة تريد أن تطلب من المجدول مباشرة أداء المهمة الآن ، وليس في يوم واحد.

نقطة أخرى مهمة هي ضمان التسامح مع الخطأ. تستخدم الخرطوشة بروتوكول SWIM [4] لمراقبة الصحة. باختصار ، تتبادل العمليات "شائعات" مع بعضها البعض عبر UDP ، أي أن كل عملية تخبر جيرانها بآخر الأخبار ، وأنها تستجيب. إذا لم يكن هناك جواب فجأة ، فإن Tarantool تشك في أن هناك خطأ ما ، وبعد فترة ، تعلن الوفاة وترسل هذه الرسالة إلى الجميع.


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


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

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

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

أدوات النشر


وعدت أن أوضح لك كيف يمكن لـ Cartridge أن تساعد في نشر التطبيقات. لتسهيل الحياة ، ينشئ الإطار حزم RPM:

 $ cartridge pack rpm myapp # will create ./myapp-0.1.0-1.rpm $ sudo yum install ./myapp-0.1.0-1.rpm 

تحتوي الحزمة المثبتة على كل ما تحتاجه تقريبًا: كلاً من التطبيق وتبعيات Lua المثبتة. يأتي Tarantool أيضًا إلى الخادم كاعتماد على حزمة RPM ، كما أن خدمتنا جاهزة للإطلاق. يتم كل ذلك باستخدام systemd ، لكن أولاً ، يجب أن نقوم ببعض التكوين ، على الأقل تحديد URI لكل عملية. ثلاثة سيكون كافيا على سبيل المثال لدينا.

 $ sudo tee /etc/tarantool/conf.d/demo.yml <<CONFIG myapp.router: {"advertise_uri": "localhost:3301", "http_port": 8080} myapp.storage_A: {"advertise_uri": "localhost:3302", "http_enabled": False} myapp.storage_B: {"advertise_uri": "localhost:3303", "http_enabled": False} CONFIG 

هناك جانب مهم يجب مراعاته: بدلاً من تحديد منفذ البروتوكول الثنائي فقط ، نحدد العنوان العام للعملية بأكملها ، بما في ذلك اسم المضيف. نقوم بذلك لأن العقد الكتلة يجب أن تعرف كيفية الاتصال مع بعضها البعض. قد يكون استخدام عنوان 0.0.0.0 بمثابة advertise_uri فكرة سيئة ، لأنه يجب أن يكون عنوان IP خارجي ، وليس ربط مأخذ توصيل. لا شيء يعمل بدونها ، لذا لن تسمح "الكارتريدج" للعقدة باستخدام الإعلان الخاطئ.

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

 $ sudo systemctl start myapp@router $ sudo systemctl start myapp@storage_A $ sudo systemctl start myapp@storage_B 

لقد حددنا منفذ HTTP لواجهة الويب Cartridge في التكوين: 8080. دعنا نذهب إلى هناك ونلقي نظرة:


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

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


النتائج


ماذا عن النتائج؟ يرجى اختبار واستخدام وترك الملاحظات ، وإنشاء تذاكر على جيثب.

مراجع


[1] Tarantool »2.2» مرجع »مرجع الصخور» وحدة vshard
[2] كيف قمنا بتطبيق جوهر أعمال الاستثمار الخاصة ببنك ألفا على أساس Tarantool
[3] بنية إعداد فواتير الجيل التالي: الانتقال إلى Tarantool
[4] SWIM - بروتوكول بناء الكتلة
[5] جيثب - تارانتول / خرطوشة CLI
[6] جيثب - تارانتول / خرطوشة

Source: https://habr.com/ru/post/ar470812/


All Articles