مرحبا يا هبر!
تدل الممارسة على أنه مع استمرار
أهمية نموذج الخدمة المجهرية ، لا يوجد نقص في
التفسيرات والانتقادات بل وحتى
الكشف . لذلك ، بالعودة إلى منشوراتنا المترجمة ، قررنا أن نتحدث على وجه التحديد عن الخدمات
الصغيرة ، أو بالأحرى النظر في إجابة مفصلة عن السؤال المطروح في عنوان المقال.
ظهر مصطلح "microservices" لأول مرة في الفترة 2011/2012. منذ ذلك الحين ، من دون خدمات ميكروية في بيئة تكنولوجيا المعلومات ، في أي مكان تقريبًا. ومع ذلك ، بعد العديد من السنوات ، تمكنا من فهم صحيح ما هي الخدمات المجهرية؟
أولاً ، دعونا نلقي نظرة على بعض التعاريف:
Microservices هي طريقة لتطوير البرمجيات (...) ، والتي بموجبها يتم هيكلة التطبيق كمجموعة من الخدمات المزدوجة . في بنية microservice ، الخدمات مفصلة للغاية ، والبروتوكولات المستخدمة خفيفة الوزن . تتمثل فائدة تحليل التطبيق في خدمات فردية أصغر في تحسين النموذجية . في هذا النموذج ، يكون التطبيق أسهل للفهم والتطوير والاختبار ويصبح التطبيق نفسه أكثر مقاومة لتآكل البنية. من خلال هذا النهج في الهندسة المعمارية ، تتم عملية التطوير بالتوازي ، وتتاح للفرق الصغيرة المستقلة الفرصة لتطوير الخدمات التي يتحملون المسؤولية عنها ونشرها وتوسيع نطاقها . أيضًا مع هذا النهج ، يمكن تطبيق إعادة البناء المستمر على بنية كل خدمة. تم تصميم تصميمات Microservice أيضًا للتسليم المستمر والنشر المستمر .
en.wikipedia.org/wiki/Microservices
إليك مقطع آخر من مارتن فاولر:
مصطلح "Microservice architecture" تم ترسيخه بقوة في السنوات القليلة الماضية لوصف طريقة معينة لتصميم مثل هذه التطبيقات ، كل منها عبارة عن مجموعة من الخدمات المنشورة بشكل مستقل . على الرغم من عدم وجود تعريف دقيق لهذا النمط المعماري ، إلا أن هناك عددًا من الخصائص العامة المتعلقة بتنظيم التطبيق حول إمكاناته التجارية ، والنشر الآلي ، وجمع المعلومات على الأجهزة الطرفية ، والإدارة اللامركزية للغات والبيانات .
martinfowler.com/articles/microservices.html
ربما لاحظت أن التشابه الرئيسي بين هاتين الصيغتين هو استقلالية الخدمات والخيارات. الآن ، دعونا نحاول الإجابة على بعض الأسئلة ومحاولة معرفة ما إذا كان النظام الذي تقوم بتطبيقه فعليًا يحتوي على أساس microservice!
هل يسمح لك نظامك بإعادة تشغيل الخدمات بشكل مستقل؟أو هل تحتاج إلى إعادة تشغيل الخدمات بترتيب معين؟ يمكن إملاء هذا السلوك بواسطة أنظمة كتلة محددة حيث تتصل العقدة بالعقدة الأولية ، على سبيل المثال ، في كتلة Akka ، إذا لم يتم التعامل معها بشكل صحيح. قد ترتبط الحالات الأخرى بالوصلات الطويلة أو المقابس التي لا يمكن فتحها إلا على جانب واحد. تذكر أن التواصل يجب أن يظل بسيطًا وخفيف الوزن. حتى أفضل إذا كان غير متزامن تماما وقائم على الرسائل. كل القيود التي تتسبب في اعتماد الخدمات على بعضها البعض على المدى الطويل يمكن أن تتحول إلى صعوبات في الدعم. يمكن أن تؤدي المشكلات التي تحدث في إحدى الخدمات إلى حدوث مشكلات في جميع الخدمات الأخرى التي تعتمد عليها ، والتي قد تؤدي في يوم ما إلى فشل عالمي خطير.
يمكنك نشر الخدمات بشكل مستقل؟هناك حالات يجب أن يحدث فيها إطلاق ونشر جميع الخدمات في النظام في وقت واحد. هذه العملية تستغرق عدة أيام. بالطبع ، في هذه الحالة ، تكون إمكانات إدخال النشر المستمر محدودة ، تحدث حالات تأخير ، وتزداد الاستجابة سوءًا. يستغرق الأمر الكثير من الوقت للتعامل مع الأخطاء العاجلة ، وذلك ببساطة بسبب التكاليف المرتبطة بعملية النشر. عندما تنشغل الفرق المختلفة بدعم الخدمات المختلفة ، فإن أي تبعية للنشر يمكن أن تمنع الفرق الأخرى من نشر خدماتها ، مما يؤدي إلى تعليق العمل وتقليل فعاليته.
هل يمكن أن يترتب على التعديل ضرورة إجراء تعديلات متزامنة على خدمات أخرى؟يمكن للمرء أن يتخيل العديد من الأسباب التي أدت إلى هذا السلوك. بادئ ذي بدء ، هذه هي تغييرات API. يحدث أن يكفي إضافة حقل جديد إلى طلب API حتى يتم قطع التوافق بين الخدمات. ومع ذلك ، هناك حلول للمساعدة في التعامل مع هذه الحالات:
- ربما تريد الاحتفاظ بالتوافق الخلفي الإلزامي لجميع التغييرات التي تم إجراؤها على واجهة برمجة التطبيقات ؛ أي كلما تم إجراء تغيير أساسي ، تتم إضافة إصدار جديد من واجهة برمجة التطبيقات. هذا لا يعني أنك ستحتاج دائمًا إلى دعم العديد من إصدارات API ؛ ستحتاج إليها فقط للفترة حتى اكتمال الترحيل. يمكنك ببساطة التحدث إلى فرق أخرى والتأكد من أن الجميع قد أكمل عملية الترحيل ، أو تشغيل المقاييس للحكم على ما إذا كانت واجهة برمجة تطبيقات معينة ما زالت قيد الاستخدام.
- يمكنك أيضًا مراعاة هذا الخيار: نشر العديد من إصدارات التطبيق في آن واحد ، والسماح للخدمات الأخرى بالتبديل إلى أحدث إصدار ، ثم تعطيل الإصدار القديم.
- حاول أيضًا استخدام التنسيقات التي تدعم تطور الدوائر ، على سبيل المثال ، Avro ، حيث قد لا يتم انتهاك عند إضافة توافق حقل جديد. عندما تكون قيمة الحقل مفقودة ، يمكن استخدام القيمة الافتراضية.
سبب آخر للنشر المتزامن هو استخدام التعليمات البرمجية المشتركة من قبل خدمات مختلفة. اعتمادًا على كيفية إنشاء عملية الإصدار في الجزء المشترك من الكود ، قد يتطلب أي تغيير التحديث في جميع الخدمات.
هل يؤدي تغيير قاعدة البيانات إلى تغيير في العديد من الخدمات؟نعم ، التواصل من خلال قاعدة بيانات هو مضاد معروف. في مثل هذه الحالة ، من الضروري تحديث المخطط وتغيير شفرة العديد من الخدمات المصغرة في وقت واحد. من الأفضل التأكد من أن خدمة واحدة فقط هي المسؤولة عن إدارة الدائرة. في هذه الحالة ، يصبح الحفاظ على قاعدة البيانات أسهل بكثير (أي إجراء تحديثاتها) وتنفيذ الإصدارات. إذا كنت بالفعل في موقف مع استخدام قاعدة البيانات المشتركة ، فحاول الحد من عدد عمليات الكتابة بحيث تعمل خدمة أخرى فقط للاستهلاك.
هل يمكنك تحديث تبعية أو إصدار Java في خدمة واحدة؟من الناحية النظرية ، ينبغي أن يكون دائما ممكن ، أليس كذلك؟ لكن في الحقيقة لا. هناك العديد من الأمثلة على المكتبات "المشتركة" أو المشروعات التي تحتوي على تعريفات لكافة التبعيات المستخدمة في النظام. الهدف من نموذج الخدمات الميكروية هو التأكد من أن كل واحد منهم هو كيان مستقل ، علاوة على ذلك ، لا يجب حتى كتابة خدمات ميكروية مختلفة بنفس الكومة التكنولوجية. عند بدء مشروع جديد ، يجب أن تكون قادرًا على أن تقرر بنفسك التكنولوجيا الأفضل له. أي ربط سوف يسبب مشاكل جديدة. في مرحلة ما ، قد تحتاج إلى الترقية إلى Scala أو JDK ، لكن بالطبع لا ترغب في القيام بذلك على الفور في النظام بأكمله. في نظام يتم فيه ملاحظة مستوى التفاصيل بشكل صحيح ، يمكنك تحديث خدمة فردية ونشرها واختبارها ومراقبتها لعدة أيام أو أسابيع ، وبعد ذلك ، إذا كان كل شيء على ما يرام ، يمكنك إجراء تحديثات في بقية النظام. ومع ذلك ، عند وجود آليات موحدة أو غيرها من آليات التوحيد القوية ، تكون هذه الإمكانيات محدودة للغاية.
هل يجبرك إطار العمل أو المكتبة التي اخترتها على الاختيار في الخدمات الأخرى؟بعض المكتبات الغازية للغاية. عندما تقرر دمجها مع أنظمة خارجية ، فقد يتضح فجأة أن اختيارك ليس رائعًا عندما تقوم بتنفيذ خدمة جديدة في حزمة تكنولوجية مختلفة. قد تكون التكاليف المرتبطة بدمجها بنفس روح بقية الخدمات ببساطة غير محتملة.
لنفترض ، على سبيل المثال ، أن لديك العديد من الخدمات المكتوبة في
NodeJS التي تستخدم
JSON: API بنشاط. بعد ذلك ، تريد تنفيذ خدمة جديدة على Scala ويبدو أنه لا توجد مكتبة عملاء مناسبة (قبل بضع سنوات كانت لدينا حالة مماثلة ، ولكن الآن تحسن الوضع في هذا المجال بشكل طفيف).
هل فشل خدمة واحدة يسبب فشل النظام بأكمله؟لنفترض أن التواصل في نظامك متزامن تمامًا. تقدم إحدى الخدمات طلبًا إلى خدمة أخرى وتنتظر ردًا منه. إذا فشلت الخدمة الأولى ، فلن تتمكن الخدمة الثانية من العمل على الإطلاق. إذا كان هذا هو الوضع في نظامك ، فحاول تنفيذ الاتصالات القائمة على الرسائل غير المتزامنة فيه. قد يكون من الأصعب قليلاً محاكاة جميع العمليات ، ولكن هذا النهج يجعل من الممكن تخفيف آثار الإخفاقات.
في الحالات التي يكون فيها هذا غير ممكن ، يمكنك محاولة الحد مؤقتًا من مجموعة ميزات التطبيق. على سبيل المثال ، في صفحة المتجر على الإنترنت تعرض معلومات حول المنتج وتعليقات عليه ، علاوة على ذلك ، تأتي معلومات المنتج والمراجعات من مصدرين مختلفين. إذا لم تنجح خدمة المراجعات microservice ، فلا يزال بإمكانك عرض صفحة المنتج عن طريق إخبار المستخدم ببساطة بأن نظام المراجعة غير متاح مؤقتًا.
هل هناك أي مكون مشترك على نظامك؟هل لديك كود مشترك؟ التكوين؟ أي شيء؟ نعم ، هذا سؤال غير تافه. يعتقد المدافعون عن نظافة الخدمات الصغيرة أنه من الأفضل عدم السماح للكيانات المشتركة في النظام على الإطلاق! من الأفضل فقط النسخ من الشفرة المقسمة. في الممارسة العملية ، يُعد من المقبول في بعض الأحيان امتلاك عدة
مكتبات مشتركة ، لكن مع قيود صارمة. ربما ستكون مكتبات تحتوي على ملفات
proto
أجل
مخازن بروتوكول أو كائنات POJO عادية فقط. من الأفضل تجنب التبعيات في هذه المكتبات. كان لدينا حالة حيث مكتبة عميل بسيط تسببت في تعارضات التبعية في نظام كبير. في مرحلة ما ، بدأ يبدو أن أقدم عناصر التطبيق كانت تستخدم مكتبة HTTP القديمة ، والتي لا يمكن تحديثها. لحسن الحظ ، يمكن تجنب هذه المواقف باستخدام إعادة تسمية التبعيات في عملية الإنشاء (تظليل التبعية) ، ولكن كن حذرًا للغاية.
الضرر الناجم عن التماسك المفرط للخدمات أكثر ضرراً بكثير من المشاكل الناجمة عن تكرار الكود.
سام نيومان ، ابتكار خدمات ميكروية
النتائجليس من السهل تنفيذ النظام المثالي المستند إلى الخدمات الدقيقة. يميل الناس إلى "قطع الزوايا" ، وإدخال روابط وثيقة في النظام التي تنشأ بسبب الكود المشترك ، وفي مرحلة ما يتحول مثل هذا النظام في الممارسة العملية إلى متراصة موزعة. يحدث هذا غالبًا في حالة بدء استخدام الخدمات المصغرة بالفعل في بداية المشروع ، عندما لا يزال موضوع الدراسة غير مدروس جيدًا ، وليس لديك خلفية صلبة جاهزة في DevOps. من الأفضل أن نبدأ بمجموعة
متجانسة منظمة ، حيث تكون جميع مجالات المسؤولية معروفة تمامًا ، ويمكن فصلها بسهولة عن بعضها البعض. ومع ذلك ، من البداية ، يجب أن تتأكد من أن نظامك مصمم
بشكل نظيف وأن منظمة الحزمة تتبع بعناية ، مما سيوفر لك فيما بعد ترحيل رمز سهل إلى خدمات جديدة (على سبيل المثال ، يمكن أن تكون حزمة "المستوى الأعلى تقريبًا" أساسًا لخدمة microservice جديدة) .
ArchUnit يمكن أن تساعد في تحليل التبعيات التي تنشأ بين الحزم.
(...) يجب ألا تبدأ على الفور العمل في مشروع جديد مع إدخال خدمات microservices ، حتى لو كنت متأكدًا من أن تطبيقك سيكون كبيرًا بدرجة كافية بحيث تبرر الخدمات الصغيرة نفسها.
martinfowler.com/bliki/MonolithFirst.html
تذكر ، يجب أن تبسط الخدمات الصغيرة كلاً من التطوير والدعم! كل ما تحتاجه هو خدمات مقترنة بشكل فضفاض ، يمكن نشر كل واحدة منها بشكل مستقل عن الآخرين.