في هذا البرنامج التعليمي، سوف تتعلم ما هي خدمات Java المصغرة، وكيفية تصميمها وإنشائها. ويغطي أيضًا أسئلة حول مكتبات خدمات Java الصغيرة وجدوى استخدام الخدمات الصغيرة. ترجمة وتكييف خدمات Java Microservices: دليل عملي .
خدمات جافا الدقيقة: الأساسيات
لفهم الخدمات الصغيرة، يجب عليك أولاً تحديد ما ليست عليه. أليست "متراصة" - مونوليث جافا: ما هي وما هي مزاياها أو عيوبها؟ما هو متراصة جافا؟
تخيل أنك تعمل في أحد البنوك أو شركة ناشئة في مجال التكنولوجيا المالية. أنت تزود المستخدمين بتطبيق جوال يمكنهم استخدامه لفتح حساب مصرفي جديد. في كود Java سيؤدي هذا إلى وجود فئة تحكم. بشكل مبسط، يبدو الأمر كما يلي:@Controller
class BankController {
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
riskCheck(form);
openBankAccount(form);
// etc..
}
}
تحتاج إلى وحدة التحكم من أجل:
- تم تأكيد استمارة التسجيل.
- التحقق من مخاطر عنوان المستخدم لتحديد ما إذا كان سيتم تزويده بحساب مصرفي.
- فتحت حسابا مصرفيا.
BankController
مع بقية مصادرك في ملفbank.jar أو ملفbank.war للنشر - وهو عبارة عن كتلة متراصة قديمة جيدة تحتوي على جميع التعليمات البرمجية اللازمة لتشغيل البنك الذي تتعامل معه. كتقدير تقريبي، سيتراوح الحجم الأولي لملف .jar (أو .war) من 1 إلى 100 ميغابايت. يمكنك الآن ببساطة تشغيل ملف .jar على الخادم الخاص بك... وهذا كل ما عليك فعله لنشر تطبيق Java الخاص بك. الصورة، المستطيل الأيسر العلوي: نشر بنك أحادي (حجري) java -jar Bank.jar (cp .war/.ear في خادم التطبيقات). المستطيل الأيمن: افتح المتصفح.
ما هي المشكلة مع متراصة جافا؟
لا يوجد شيء خاطئ بطبيعته مع كتل جافا. ومع ذلك، فقد أظهرت التجربة أنه إذا كان في مشروعك:- هناك العديد من المبرمجين/الفرق/الاستشاريين الذين يعملون...
- ...على نفس المنضدة تحت ضغط من العملاء بمتطلبات غامضة للغاية...
- في غضون بضع سنوات ...
كيفية تقليل حجم متراصة جافا؟
يطرح سؤال طبيعي: كيف نجعل المتراصة أصغر؟ في الوقت الحالي، يتم تشغيل Bank.jar الخاص بك على JVM واحد، وعملية واحدة على خادم واحد. لا أكثر ولا أقل. والآن قد تتبادر إلى ذهني فكرة منطقية: "ولكن يمكن للأقسام الأخرى في شركتي استخدام خدمة التحقق من المخاطر! لا يرتبط الأمر مباشرة بتطبيقي المصرفي المتجانس! ربما ينبغي قطعها من المتراصة ونشرها كمنتج منفصل؟ وهذا يعني، من الناحية الفنية، تشغيلها كعملية Java منفصلة.ما هي خدمة جافا الصغيرة؟
من الناحية العملية، تعني هذه العبارة أنه لن يتم الآن إجراء استدعاء الأسلوبriskCheck()
من BankController: سيتم نقل هذا الأسلوب أو مكون الفول مع جميع فئاته المساعدة إلى مشروع Maven أو Gradle الخاص به. وسيتم أيضًا نشره ووضعه تحت التحكم في الإصدار بشكل مستقل عن الكتلة المصرفية. ومع ذلك، فإن عملية الاستخراج بأكملها لا تحول وحدة RiskCheck الجديدة الخاصة بك إلى خدمة صغيرة في حد ذاتها، نظرًا لأن تعريف الخدمة الصغيرة مفتوح للتفسير. وهذا يؤدي إلى مناقشات متكررة داخل الفرق والشركات.
- هل 5-7 فصول في مشروع صغير أم ماذا؟
- 100 أو 1000 فصل... لا تزال صغيرة؟
- هل الخدمة المصغرة مرتبطة بشكل عام بعدد الفئات أم لا؟
- دعنا نطلق على جميع الخدمات المنشورة بشكل منفصل خدمات صغيرة، بغض النظر عن حجمها أو حدود المجال.
- دعونا نفكر في كيفية ترتيب الاتصالات بين الخدمات. تحتاج خدماتنا الصغيرة إلى طرق للتواصل مع بعضها البعض.
كيفية إنشاء اتصال بين خدمات Java الصغيرة؟
بشكل عام، هناك خياران - الاتصال المتزامن وغير المتزامن.الاتصال المتزامن: (HTTP)/REST
عادةً ما يحدث الاتصال المتزامن بين الخدمات الصغيرة عبر خدمات HTTP والخدمات المشابهة لـ REST والتي تقوم بإرجاع XML أو JSON. بالطبع، قد تكون هناك خيارات أخرى - خذ على الأقل Google Protocol Buffers . إذا كنت بحاجة إلى استجابة فورية، فمن الأفضل استخدام اتصال REST. في مثالنا، هذا هو بالضبط ما يجب القيام به، حيث أن التحقق من المخاطر مطلوب قبل فتح الحساب. إذا لم يكن هناك فحص للمخاطر، فلا يوجد حساب. سنناقش الأدوات أدناه، في قسم " ما المكتبات الأفضل لاستدعاءات Java REST المتزامنة ".المراسلة - الاتصال غير المتزامن
عادةً ما يتم تحقيق اتصال الخدمات الصغيرة غير المتزامن عن طريق تبادل الرسائل مع تطبيق JMS و/أو استخدام بروتوكول مثل AMQP . لقد كتبنا "عادة" هنا لسبب ما: لنفترض أنه لا يمكن الاستهانة بعدد عمليات تكامل البريد الإلكتروني/SMTP. استخدمه عندما لا تحتاج إلى استجابة فورية. على سبيل المثال، يقوم المستخدم بالنقر فوق الزر "اشتر الآن"، وأنت بدورك تريد إنشاء فاتورة. من المؤكد أنه لا ينبغي أن تحدث هذه العملية ضمن دورة الاستجابة لطلب الشراء الخاصة بالمستخدم. سنصف أدناه الأدوات الأفضل لمراسلة Java غير المتزامنة .مثال: استدعاء REST API في Java
لنفترض أننا اخترنا اتصالات الخدمات الصغيرة المتزامنة. في هذه الحالة، كود Java الخاص بنا (الذي قدمناه أعلاه) سيبدو على مستوى منخفض مثل هذا. (نعني بالمستوى المنخفض هنا حقيقة أنه بالنسبة لاتصالات الخدمات الصغيرة، يتم عادةً إنشاء مكتبات العملاء التي تجردك من مكالمات HTTP الفعلية).@Controller
class BankController {
@Autowired
private HttpClient httpClient;
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
httpClient.send(riskRequest, responseHandler());
setupAccount(form);
// etc..
}
}
بناءً على الكود، يصبح من الواضح أننا بحاجة الآن إلى نشر خدمتين Java (micro)، Bank وRiskCheck. ونتيجة لذلك، سيكون لدينا عمليتين JVM قيد التشغيل. هذا هو كل ما تحتاجه لتطوير مشروع Java microservices: ما عليك سوى إنشاء ونشر أجزاء أصغر (ملفات .jar أو .war) بدلاً من مجموعة واحدة متجانسة. لا تزال الإجابة على السؤال غير واضحة: كيف يمكننا تقسيم المونوليث إلى خدمات صغيرة؟ ما مدى صغر حجم هذه القطع وكيفية تحديد الحجم الصحيح؟ دعونا تحقق.
بنية الخدمات الدقيقة لجافا
ومن الناحية العملية، تقوم الشركات بتطوير مشاريع الخدمات الصغيرة بطرق مختلفة. يعتمد الأسلوب على ما إذا كنت تحاول تحويل وحدة متراصة موجودة إلى مشروع خدمات صغيرة أو بدء المشروع من الصفر.من متراصة إلى الخدمات الصغيرة
إحدى الأفكار الأكثر منطقية هي استخراج الخدمات الصغيرة من وحدة متراصة موجودة. لاحظ أن البادئة "micro" هنا لا تعني في الواقع أن الخدمات المستخرجة ستكون صغيرة حقًا؛ وهذا ليس هو الحال بالضرورة. دعونا ننظر إلى الخلفية النظرية.الفكرة: تقسيم المونوليث إلى خدمات صغيرة
يمكن تطبيق نهج الخدمات الصغيرة على المشاريع القديمة. ولهذا السبب:- في أغلب الأحيان، يصعب الحفاظ على مثل هذه المشاريع أو تغييرها أو توسيعها.
- الجميع، من المطورين إلى الإدارة، يريدون التبسيط.
- لديك حدود مجال واضحة (نسبيًا)، مما يعني أنك تعرف بالضبط ما يجب أن يفعله برنامجك.
- لذلك، سيكون من المعقول فصل معالجة بيانات المستخدم (مثل الأسماء والعناوين وأرقام الهواتف) في خدمة صغيرة منفصلة "إدارة الحساب".
- أو "وحدة فحص المخاطر" المذكورة أعلاه والتي تتحقق من مستويات المخاطر لدى المستخدم ويمكن استخدامها من قبل العديد من المشاريع الأخرى أو حتى أقسام الشركة.
- أو وحدة الفواتير التي ترسل الفواتير بتنسيق PDF أو عن طريق البريد.
تنفيذ الفكرة: السماح لشخص آخر بتنفيذها
يبدو النهج الموصوف أعلاه رائعًا على الورق والرسوم البيانية المشابهة لـ UML. ومع ذلك، كل شيء ليس بهذه البساطة. يتطلب تنفيذها العملي إعدادًا فنيًا جادًا: فالفجوة بين فهمنا لما قد يكون من الجيد استخلاصه من قطعة متراصة وعملية الاستخراج نفسها هائلة. تصل معظم مشاريع المؤسسات إلى مرحلة يخشى فيها المطورون، على سبيل المثال، ترقية إصدار عمره 7 سنوات من Hibernate إلى إصدار أحدث. سيتم تحديث المكتبات معه، ولكن هناك خطر حقيقي من كسر شيء ما. إذن، يتعين على هؤلاء المطورين أنفسهم الآن البحث في التعليمات البرمجية القديمة ذات الحدود غير الواضحة لمعاملات قاعدة البيانات واستخراج خدمات دقيقة محددة جيدًا؟ في أغلب الأحيان، تكون هذه المشكلة معقدة للغاية ولا يمكن "حلها" على السبورة البيضاء أو في اجتماعات الهندسة المعمارية. على حد تعبير مطور تويتر @simonbrown: سأقول هذا مرارًا وتكرارًا... إذا لم يتمكن الأشخاص من بناء وحدات متراصة بشكل صحيح، فلن تساعد الخدمات الصغيرة. سيمون براونمشروع من الصفر يعتمد على بنية الخدمات الصغيرة
بالنسبة لمشاريع Java الجديدة، تبدو العناصر الثلاثة المرقمة من الجزء السابق مختلفة قليلاً:- عليك أن تبدأ بسجل نظيف، لذلك ليس هناك "أمتعة" يجب الحفاظ عليها.
- يرغب المطورون في إبقاء الأمور بسيطة في المستقبل.
- المشكلة: لديك صورة أكثر غموضًا عن حدود النطاق: فأنت لا تعرف ما الذي من المفترض أن يفعله برنامجك فعليًا (تلميح: Agile ;))
بنية الخدمات الدقيقة التقنية
يبدو أن النقطة الأولى هي الأكثر وضوحًا بالنسبة للمطورين، ولكن هناك أيضًا من لا يشجعونها بشدة. يوصي هادي الحريري بإعادة هيكلة "Extract Microservice" في IntelliJ. وعلى الرغم من أن المثال التالي مبسط للغاية، إلا أن التطبيقات التي تمت ملاحظتها في المشاريع الحقيقية، للأسف، لا تبتعد عنه كثيرًا. قبل الخدمات المصغرة@Service
class UserService {
public void register(User user) {
String email = user.getEmail();
String username = email.substring(0, email.indexOf("@"));
// ...
}
}
مع سلسلة فرعية Java microservice
@Service
class UserService {
@Autowired
private HttpClient client;
public void register(User user) {
String email = user.getEmail();
//теперь вызываем substring microservice via http
String username = httpClient.send(substringRequest(email), responseHandler());
// ...
}
}
لذا، فأنت تقوم بشكل أساسي بتغليف استدعاء أسلوب Java في استدعاء HTTP، دون سبب واضح للقيام بذلك. ومع ذلك، أحد الأسباب هو: الافتقار إلى الخبرة ومحاولة فرض نهج خدمات Java الصغيرة. التوصية: لا تفعل هذا.
بنية الخدمات الصغيرة الموجهة نحو سير العمل
الطريقة الشائعة التالية هي تقسيم خدمات Java الصغيرة إلى وحدات تعتمد على سير العمل. مثال من الحياة الواقعية: في ألمانيا، عندما تذهب إلى طبيب (عام)، يجب عليه تسجيل زيارتك في نظام إدارة علاقات العملاء الطبي الخاص به. للحصول على دفعة من التأمين، سيرسل بيانات حول علاجك (وعلاج المرضى الآخرين) إلى الوسيط عبر XML. سوف ينظر الوسيط إلى ملف XML هذا و(مبسط):- سيتم التحقق من استلام ملف XML الصحيح.
- سيتم التحقق من معقولية الإجراءات: على سبيل المثال، يبدو الطفل البالغ من العمر عام واحد، الذي تلقى ثلاث إجراءات لتنظيف الأسنان في يوم واحد من طبيب أمراض النساء، مشبوهًا إلى حد ما.
- سيتم دمج XML مع بعض البيانات البيروقراطية الأخرى.
- سيتم إرسال ملف XML إلى شركة التأمين لبدء الدفعات.
- وسيتم إرسال النتيجة إلى الطبيب، مع تزويده برسالة "النجاح" أو "الرجاء إعادة إرسال هذا التسجيل بمجرد أن يصبح منطقيًا".
- هل من الضروري نشر ستة تطبيقات لمعالجة ملف XML واحد؟
- هل هذه الخدمات الصغيرة مستقلة حقًا عن بعضها البعض؟ هل يمكن نشرها بشكل مستقل عن بعضها البعض؟ مع إصدارات مختلفة ومخططات API؟
- ماذا تفعل خدمة مصداقية المعلومات الصغيرة إذا لم تعمل خدمة التحقق الصغيرة؟ هل النظام لا يزال يعمل؟
- هل تشترك هذه الخدمات الصغيرة في نفس قاعدة البيانات (تحتاج بالتأكيد إلى بعض البيانات المشتركة في جداول قاعدة البيانات)، أم أن لكل منها بياناتها الخاصة؟
- … وأكثر بكثير.
- لا تحتاج إلى نشر تطبيق واحد فقط، بل ستة على الأقل.
- قد تحتاج أيضًا إلى نشر قواعد بيانات متعددة، اعتمادًا على المدى الذي تريد الوصول إليه في بنية الخدمات الصغيرة.
- تحتاج إلى التأكد من أن كل نظام متصل بالإنترنت ويعمل بشكل صحيح.
- أنت بحاجة إلى التأكد من أن مكالماتك بين الخدمات الصغيرة مرنة حقًا (راجع كيفية جعل خدمة Java الصغيرة مرنة؟).
- وكل شيء آخر يتضمنه هذا الإعداد - بدءًا من إعدادات التطوير المحلي وحتى اختبار التكامل.
- إذا لم تكن Netflix (هناك احتمالات أنك لست Netflix)...
- إلا إذا كانت لديك مهارات عمل قوية للغاية حيث تفتح بيئة التطوير ويتسبب في حدوث فوضى تؤدي إلى التخلص من قاعدة بيانات الإنتاج الخاصة بك والتي يمكن استعادتها بسهولة في 5 ثوانٍ.
- أو أنك تشعر وكأنك @monzo وترغب في تجربة 1500 خدمة صغيرة فقط لأنك تستطيع ذلك.
GO TO FULL VERSION