أرسلت بواسطة دينيس تسيبلاكوف ، مهندس حلول ، DataArtفي DataArt ، أعمل بطريقتين. في البداية ، أساعد الأشخاص على إصلاح الأنظمة التي تم كسرها بطريقة أو بأخرى ولأسباب متعددة. في الثانية ، أنا أساعد في تصميم أنظمة جديدة حتى لا تنكسر في المستقبل ، أو أكثر واقعية ، كان كسرها أكثر صعوبة.
إذا كنت لا تفعل شيئًا جديدًا بشكل أساسي ، على سبيل المثال ، أول محرك بحث على الإنترنت في العالم أو ذكاء اصطناعي للتحكم في إطلاق الصواريخ النووية ، فإن تصميم نظام جيد أمر بسيط للغاية. يكفي أن تأخذ في الاعتبار جميع المتطلبات ، والنظر في تصميم أنظمة مماثلة والقيام بنفس الشيء ، دون ارتكاب أي أخطاء خطيرة. يبدو الأمر وكأنه تبسيط مفرط للمشكلة ، ولكن دعنا نتذكر أنه في الفناء هو عام 2019 ، وهناك "وصفات قياسية" لتصميم النظام لكل شيء تقريبًا. يمكن لرجال الأعمال معالجة المهام الفنية المعقدة - على سبيل المثال ، معالجة ملفات PDF غير المتجانسة وإزالة جداول المصروفات منها - ولكن نادراً ما تكون بنية النظام أصلية للغاية. الشيء الرئيسي هنا هو عدم ارتكاب خطأ في تحديد النظام الذي نقوم ببنائه ، وعدم تفويت اختيار التقنيات.
تحدث الأخطاء النموذجية بانتظام في الفقرة الأخيرة ، والتي سأناقش بعضها في مقال.
ما هي صعوبة اختيار كومة التقنية؟ إن إضافة أي تقنية للمشروع يجعل الأمر أكثر صعوبة ويجلب بعض القيود. وفقًا لذلك ، يجب إضافة أداة جديدة (إطار عمل ، مكتبة) فقط عندما تكون هذه الأداة مفيدة أكثر من ضارة. في المحادثات مع أعضاء الفريق حول إضافة المكتبات والأطر ، غالبًا ما استخدم الحيل التالية مازحا: "إذا كنت ترغب في إضافة تبعية جديدة إلى المشروع ، يمكنك وضع علبة بيرة للفريق. إذا كنت تعتقد أن هذا الاعتماد على مربع من البيرة لا يستحق كل هذا العناء ، لا تضيف.
لنفترض أننا ننشئ تطبيقًا معينًا ، على سبيل المثال ، في Java ونضيف مكتبة TimeMagus إلى المشروع لمعالجة التواريخ (مثال على ذلك). المكتبة ممتازة ، فهي توفر لنا العديد من الميزات غير المتوفرة في مكتبة الفئة القياسية. كيف يمكن أن يكون هذا القرار ضارًا؟ لنلقِ نظرة على السيناريوهات المحتملة:
- لا يعرف جميع المطورين مكتبة غير قياسية ، فستكون عتبة الدخول للمطورين الجدد أعلى. تزيد فرصة قيام مطور جديد بخطأ ما عند معالجة تاريخ باستخدام مكتبة غير معروفة.
- حجم التوزيع يتزايد. عندما يمكن أن يرتفع حجم التطبيق المتوسط على Spring Boot بسهولة إلى 100 ميغابايت ، فإن هذا لا يعني بأي حال من الأحوال تافهًا. رأيت حالات ، من أجل طريقة واحدة ، تم سحب مكتبة بحجم 30 ميغابايت في مجموعة التوزيع. لقد برّروها بهذه الطريقة: "لقد استخدمت هذه المكتبة في مشروع سابق ، وهناك طريقة ملائمة هناك."
- بناءً على المكتبة ، قد يزيد وقت البدء بشكل كبير.
- يمكن لمطور المكتبة التخلي عن بنات أفكاره ، ثم ستبدأ المكتبة في التعارض مع الإصدار الجديد من Java ، أو سيتم اكتشاف خلل فيه (بسبب ، على سبيل المثال ، تغيير المناطق الزمنية) ، ولن يتم إصدار أي تصحيح.
- سيتعارض ترخيص المكتبة في مرحلة ما مع ترخيص منتجك (هل تقوم بفحص التراخيص لجميع المنتجات التي تستخدمها؟).
- Jar hell - تحتاج مكتبة TimeMagus إلى أحدث إصدار من مكتبة SuperCollections ، ثم بعد بضعة أشهر تحتاج إلى توصيل المكتبة للتكامل مع واجهة برمجة تطبيقات لجهة خارجية ، والتي لا تعمل مع أحدث إصدار من SuperCollections ، وتعمل فقط مع الإصدار 2.x. لا يمكنك توصيل API. لا توجد مكتبة أخرى للعمل مع واجهة برمجة التطبيقات هذه.
من ناحية أخرى ، توفر لنا المكتبة القياسية أدوات ملائمة لمعالجة التواريخ ، وإذا كنت لا تحتاج إلى الاحتفاظ ، على سبيل المثال ، بتقويم غريب أو حساب عدد الأيام من اليوم إلى "اليوم الثاني من القمر الجديد الثالث في السنة السابقة من النسر المتصاعد" ، فقد يكون الأمر يستحق الامتناع عن استخدام مكتبة طرف ثالث. حتى لو كان رائعًا تمامًا وعلى نطاق المشروع ، فسيوفر لك ما يصل إلى 50 سطرًا من التعليمات البرمجية.
المثال المدروس بسيط للغاية ، وأعتقد أنه من السهل اتخاذ قرار. ولكن هناك عددًا من التقنيات واسعة الانتشار ، من قبل آذان الجميع ، واستخدامها واضح ، مما يجعل الخيار أكثر صعوبة - فهي توفر مزايا جدية للمطور. لكن هذا ليس بالضرورة أن يكون مناسبة لسحبهم إلى مشروعك. دعونا ننظر في بعض منهم.
عامل الميناء
قبل ظهور هذه التقنية الرائعة حقًا ، عند نشر الأنظمة ، كان هناك الكثير من المشكلات غير السارة والمعقدة المتعلقة بتعارض الإصدار والتبعيات الغامضة. يسمح لك Docker بتجميع لقطة لحالة النظام ، وطرحها في الإنتاج وتشغيلها هناك. وهذا يسمح بتجنب النزاعات المذكورة ، وهو أمر رائع بالطبع.
في السابق ، تم ذلك بطريقة وحشية ، ولم يتم حل بعض المهام على الإطلاق. على سبيل المثال ، لديك تطبيق PHP يستخدم مكتبة ImageMagick للعمل مع الصور ، كما يحتاج التطبيق الخاص بك إلى إعدادات php.ini محددة ، ويتم استضافة التطبيق نفسه باستخدام Apache httpd. ولكن هناك مشكلة: يتم تنفيذ بعض الإجراءات الروتينية عن طريق تشغيل البرامج النصية Python من cron ، والمكتبة المستخدمة من قبل هذه البرامج النصية تتعارض مع إصدارات المكتبة المستخدمة في التطبيق الخاص بك. يسمح لك Docker بحزم تطبيقك بالكامل ، إلى جانب الإعدادات والمكتبات وخادم HTTP ، في حاوية واحدة تقدم الطلبات على المنفذ 80 ، والإجراءات في حاوية أخرى. ستعمل جميعها معًا تمامًا ، ويمكنك نسيان تعارض المكتبات.
هل يجب استخدام Docker لحزم كل تطبيق؟ رأيي: لا ، لا يستحق كل هذا العناء. تُظهر الصورة تركيبة نموذجية للتطبيق المثبت في AWS. تشير المستطيلات هنا إلى طبقات العزل التي لدينا.

أكبر مستطيل هو الجهاز المادي. التالي هو نظام تشغيل الجهاز الفعلي. ثم - المحاكي الأمازون الظاهري ، ثم نظام تشغيل الجهاز الظاهري ، ثم حاوية الإرساء ، يليه نظام تشغيل الحاوية ، JVM ، ثم حاوية Servlet (إذا كان تطبيق ويب) ، ورمز التطبيق الخاص بك موجود بداخله بالفعل. وهذا هو ، نرى بالفعل طبقات قليلة من العزل.
سيبدو الموقف أسوأ إذا نظرنا إلى اختصار JVM. JVM هو ، على نحو غريب ، جهاز Java Virtual Machine ، وهذا في الواقع ، لدينا دائمًا جهاز افتراضي واحد على الأقل في Java. إن إضافة حاوية Docker إضافية ، أولاً ، غالبًا لا تعطي هذه الميزة الملحوظة ، لأن JVM نفسها تعزلنا جيدًا عن البيئة الخارجية ، وثانياً ، لا تخلو من التكلفة.
أخذت شخصيات من دراسة IBM ، إن لم تكن مخطئة ، قبل عامين. باختصار ، إذا كنا نتحدث عن عمليات القرص أو استخدام المعالج أو الوصول إلى الذاكرة ، فإن Docker يكاد لا يضيف حمولة (حرفيًا جزءًا بسيطًا من النسبة المئوية) ، ولكن إذا كنا نتحدث عن زمن انتقال الشبكة ، فإن التأخير ملحوظ للغاية. إنها ليست عملاقة ، ولكن بناءً على التطبيق الذي لديك ، قد يفاجئك غير سارة.

بالإضافة إلى ذلك ، Docker يستهلك مساحة إضافية على القرص ، ويشغل جزءًا من الذاكرة ، ويضيف وقت بدء التشغيل. جميع النقاط الثلاث غير حاسمة بالنسبة لمعظم الأنظمة - عادة ما يكون هناك الكثير من مساحة القرص والذاكرة. وقت الإطلاق ، كقاعدة عامة ، ليس أيضًا مشكلة حرجة ، الشيء الرئيسي هو أن التطبيق يبدأ. ولكن لا تزال هناك حالات قد تنفد فيها الذاكرة ، وكان إجمالي وقت بدء تشغيل النظام ، الذي يتكون من عشرين خدمة تابعة ، كبيرًا بالفعل. بالإضافة إلى ذلك ، يؤثر هذا على تكلفة الاستضافة. وإذا كنت منخرطًا في أي تداول عالي التردد ، فإن Docker بشكل قاطع لا يناسبك. في الحالة العامة ، من الأفضل عدم إرساء أي تطبيق حساس لتأخير الشبكة يصل إلى 250 إلى 500 مللي ثانية.
أيضًا ، مع عامل الإرساء ، يكون تحليل المشكلات في بروتوكولات الشبكة معقدًا بشكل ملحوظ ، ولا يتزايد التأخير فحسب ، بل تختلف جميع الأوقات.
عندما دوكر هناك حاجة حقا؟
عندما يكون لدينا إصدارات مختلفة من JRE ، سيكون من الجيد سحب JRE على طول. هناك أوقات تحتاج فيها إلى تشغيل إصدار معين من Java (وليس "أحدث Java 8" ، ولكن هناك شيء أكثر تحديدًا). في هذه الحالة ، من الجيد حزم JRE مع التطبيق وتشغيله كحاوية. من حيث المبدأ ، من الواضح أنه يمكن وضع إصدارات مختلفة من Java على النظام المستهدف بسبب JAVA_HOME ، وما إلى ذلك. ولكن Docker بهذا المعنى أكثر ملاءمة ، لأنك تعرف الإصدار الدقيق من JRE ، كل شيء معبأ مع JRE آخر لن يبدأ التطبيق عن طريق الصدفة .
Docker ضروري أيضًا إذا كان لديك تبعيات على بعض المكتبات الثنائية ، على سبيل المثال ، لمعالجة الصور. في هذه الحالة ، قد يكون من الجيد تجميع جميع المكتبات اللازمة مع تطبيق Java نفسه.
تشير الحالة التالية إلى نظام مركب مركب من مختلف الخدمات المكتوبة بلغات مختلفة. لديك قطعة على Node.js ، جزء في Java ، مكتبة في Go ، بالإضافة إلى نوع من التعلم الآلي في Python. يجب ضبط هذه الحديقة بأكملها بعناية وبعناية لتعليم عناصرها رؤية بعضهم البعض. التبعيات ، والمسارات ، وعناوين IP - كل هذا يجب أن يتم رسمه ورفعه بعناية في الإنتاج. بالطبع ، في هذه الحالة ، سوف تساعدك Docker كثيرًا. علاوة على ذلك ، فإن القيام بذلك دون مساعدته أمر مؤلم.
يمكن أن يوفر Docker بعض الراحة عندما تحتاج إلى تحديد العديد من المعلمات المختلفة في سطر الأوامر لبدء التطبيق. من ناحية أخرى ، فإن نصوص bash تفعل هذا بشكل جيد للغاية ، وغالبًا من سطر واحد. تقرر أي واحد لاستخدام أفضل.
آخر ما يتبادر إلى الذهن في الحال هو الموقف عند استخدام Kubernetes ، على سبيل المثال ، وتحتاج إلى تنفيذ تزامن للنظام ، أي رفع عدد معين من الخدمات المجهرية المختلفة التي تتسع تلقائيًا وفقًا لقواعد معينة.
في جميع الحالات الأخرى ، يكون Spring Boot كافياً لتعبئة كل شيء في ملف مرطب واحد. و ، من حيث المبدأ ، فإن جرة النابضة هي استعارة جيدة لحاوية Docker. هذا ، بالطبع ، ليس هو نفس الشيء ، ولكن من حيث سهولة النشر ، فهي متشابهة حقًا.
Kubernetes
ماذا لو استخدمنا Kubernetes؟ بادئ ذي بدء ، تتيح لك هذه التقنية نشر عدد كبير من الخدمات المصغرة على أجهزة مختلفة ، وإدارتها ، وإجراء الفحص التلقائي ، إلخ. ومع ذلك ، هناك العديد من التطبيقات التي تسمح لك بالتحكم في تزامن ، على سبيل المثال ، Puppet ، و CF engine ، و SaltStack ، وغيرها. Kubernetes بحد ذاته أمر جيد بالتأكيد ، لكنه يمكن أن يضيف نفقات كبيرة ، ليست كل مشروع جاهزًا للعيش معها.
الأداة المفضلة لدي هي Ansible ، إلى جانب Terraform حيث تريدها. Ansible هو أداة خفيفة الوزن الإعلاني إلى حد ما. لا يتطلب تثبيت عوامل خاصة ولديه بناء جملة مفهوم لملفات التكوين. إذا كنت معتادًا على إنشاء Docker ، فسترى مقاطع متداخلة على الفور. وإذا كنت تستخدم Ansible ، فليست هناك حاجة إلى ما قبل rezerez - يمكنك نشر أنظمة باستخدام وسائل أكثر كلاسيكية.
من الواضح أن هذه كلها تقنيات مختلفة ، لكن هناك مجموعة من المهام يمكن تبديلها. ويتطلب النهج الضميري في التصميم إجراء تحليل للتكنولوجيا الأكثر ملاءمة للنظام الجاري تطويره. وكيف سيكون من الأفضل مطابقتها في غضون بضع سنوات.
إذا كان عدد الخدمات المختلفة على نظامك صغيرًا وتكوينها بسيطًا نسبيًا ، على سبيل المثال ، لديك ملف جرة واحد فقط ، ولا ترى أي نمو مفاجئ في التعقيد ، يمكنك على الأرجح الاستفادة من آليات النشر التقليدية.
هذا يثير السؤال ، "الانتظار ، كيف هو ملف جرة واحدة؟". يجب أن يتكون النظام من أكبر عدد ممكن من الخدمات الذرية الذرية! دعونا نرى من وماذا ينبغي للنظام مع microservices.
خدمات Microservices
أولاً وقبل كل شيء ، تسمح الخدمات الميكروية بتحقيق قدر أكبر من المرونة وقابلية التوسع ، وتسمح بإصدار نسخ مرنة للأجزاء الفردية من النظام. لنفترض أن لدينا نوعًا من التطبيقات التي كانت قيد الإنتاج لسنوات عديدة. تتطور الوظيفة ، لكن لا يمكننا تطويرها إلى ما لا نهاية. على سبيل المثال
لدينا تطبيق في Spring Boot 1 و Java 8. مجموعة رائعة ومستقرة. لكن العام 2019 ، وسواء أحببنا ذلك أم لا ، نحتاج إلى الانتقال نحو Spring Boot 2 و Java 12. حتى الانتقال البسيط نسبياً لنظام كبير إلى الإصدار الجديد من Spring Boot يمكن أن يكون شاقًا للغاية ، ولكن حول القفز فوق الهاوية من Java 8 إلى Java 12 لا اريد التحدث هذا ، من الناحية النظرية ، كل شيء بسيط: نحن نهاجر ، ونصحح المشاكل التي نشأت ، ونختبر كل شيء ونعمل عليه في الإنتاج. في الممارسة العملية ، قد يعني هذا عدة أشهر من العمل لا تجلب وظائف جديدة إلى العمل. الانتقال قليلاً إلى Java 12 ، كما تعلم ، لا يعمل أيضًا. هنا العمارة microservice يمكن أن تساعدنا.
يمكننا تخصيص مجموعة مدمجة من وظائف تطبيقنا في خدمة منفصلة ، وترحيل هذه المجموعة من الوظائف إلى رزمة فنية جديدة ، ونضعها في الإنتاج في وقت قصير نسبيًا. كرر قطعة العملية قطعة حتى تستنفد التقنيات القديمة تمامًا.
أيضًا ، يمكن أن توفر الخدمات الميكروية عزلًا للخطأ ، عندما لا يفسد أحد المكونات الساقطة النظام بالكامل.
تتيح لنا Microservices امتلاك حزمة تقنية مرنة ، أي عدم كتابة كل شيء بشكل متجانس بلغة واحدة وإصدار واحد ، وإذا لزم الأمر ، استخدم مجموعة تقنية مختلفة للمكونات الفردية. بالطبع ، من الأفضل استخدام مكدس تقني موحد ، لكن هذا ليس ممكنًا دائمًا ، وفي هذه الحالة ، يمكن أن تساعد الخدمات الميكروية.
تتيح Microservices أيضًا وسيلة تقنية لحل عدد من المشكلات الإدارية. على سبيل المثال ، عندما يتكون فريقك الكبير من مجموعات منفصلة تعمل في شركات مختلفة (الجلوس في مناطق زمنية مختلفة وتحدث لغات مختلفة). تساعد Microservices في عزل هذا التنوع التنظيمي عن طريق المكونات التي سيتم تطويرها بشكل منفصل. ستبقى مشاكل جزء واحد من الفريق داخل خدمة واحدة ، ولن تنتشر في جميع أنحاء التطبيق بأكمله.
لكن الخدمات الميكروية ليست هي الطريقة الوحيدة لحل هذه المشكلات. من الغريب أنه قبل عقود قليلة ، جاء نصفهم إلى صفوف ، وبعد ذلك بقليل - مكونات ونمط انقلاب التحكم.
إذا نظرنا إلى Spring ، فسنرى أنها في الحقيقة بنية خدمات ميكروية داخل عملية Java. يمكننا أن نعلن عن مكون ، والذي ، في جوهره ، هو خدمة. لدينا القدرة على إجراء بحث من خلالAutowired ، وهناك أدوات لإدارة دورة حياة المكون والقدرة على تكوين المكونات بشكل منفصل من عشرات المصادر المختلفة. من حيث المبدأ ، نحصل على كل ما لدينا تقريبًا مع خدمات microservices - فقط داخل عملية واحدة ، مما يقلل التكاليف بشكل كبير. فئة Java العادية هي نفس عقد واجهة برمجة التطبيقات الذي يسمح لك أيضًا بعزل تفاصيل التنفيذ.
بالمعنى الدقيق للكلمة ، في عالم Java ، تشبه الخدمات الميكروية إلى حد كبير OSGi - فهناك نسخة طبق الأصل تقريبًا من كل ما هو موجود في microservices ، باستثناء ، بالإضافة إلى إمكانية استخدام لغات برمجة مختلفة وتنفيذ التعليمات البرمجية على خوادم مختلفة. ولكن حتى مع الحفاظ على إمكانيات فئات Java ، لدينا أداة قوية إلى حد ما لحل عدد كبير من مشكلات العزل.
حتى في السيناريو "الإداري" مع عزل الفريق ، يمكننا إنشاء مستودع منفصل يحتوي على وحدة Java منفصلة مع عقد خارجي واضح ومجموعة من الاختبارات. هذا سوف يقلل بشكل كبير من قدرة فريق على تعقيد حياة فريق آخر عن غير قصد.

لقد سمعت مرارًا وتكرارًا أنه من المستحيل عزل تفاصيل التنفيذ بدون خدمات ميكروية. لكن يمكنني الإجابة أن صناعة البرمجيات بأكملها تتعلق فقط بعزل التطبيق. لهذا ، تم اختراع الروتين الفرعي أولاً (في الخمسينيات من القرن الماضي) ، ثم الوظائف والإجراءات والطبقات والخدمات الميكروية اللاحقة. لكن حقيقة أن الخدمات الميكروية في هذه السلسلة ظهرت أخيرًا لا تجعلها أعلى نقطة في التطور ولا تلزمنا دائمًا باللجوء إلى مساعدتهم.
عند استخدام خدمات microservices ، يجب على المرء أيضًا مراعاة أن المكالمات بينهما تستغرق بعض الوقت. هذا غالبًا ما يكون غير مهم ، لكنني رأيت حالة عندما يحتاج العميل إلى احتواء وقت استجابة النظام لمدة 3 ثوانٍ. لقد كان التزامًا تعاقديًا بالاتصال بنظام طرف ثالث. مرت سلسلة المكالمات عبر عدة عشرات من الخدمات الميكروية الذرية ، ولم يسمح الحمل العام لإجراء مكالمات HTTP بالانكماش خلال 3 ثوانٍ. بشكل عام ، يجب أن تفهم أن أي تقسيم للشفرة المتجانسة إلى عدد من الخدمات يؤثر حتماً على الأداء العام للنظام. فقط لأنه لا يمكن نقل البيانات بين العمليات والخوادم "مجانًا".
متى تحتاج الخدمات الصغيرة؟
في أي الحالات يحتاج التطبيق المترابط إلى تقسيم إلى عدة خدمات ميكروية؟ أولاً ، عندما يكون هناك استخدام غير متوازن للموارد في المجالات الوظيفية.
على سبيل المثال ، لدينا مجموعة من مكالمات واجهة برمجة التطبيقات التي تؤدي عمليات حسابية تتطلب الكثير من وقت المعالج. وهناك مجموعة من مكالمات API التي يتم تنفيذها بسرعة كبيرة ، ولكنها تتطلب بنية بيانات 64 غيغا بايت مرهقة لتخزينها في الذاكرة. بالنسبة للمجموعة الأولى ، نحتاج إلى مجموعة من الأجهزة التي تضم 32 معالجًا ، أما الجهاز الثاني فهو كافٍ (حسنًا ، دع هناك جهازان للتسامح مع الأعطال) مع ذاكرة تبلغ سعتها 64 جيجابايت. إذا كان لدينا تطبيق مترابط ، فسنحتاج إلى 64 جيجابايت من الذاكرة على كل جهاز ، مما يزيد من تكلفة كل جهاز. إذا كانت هذه الوظائف مقسمة إلى خدمتين منفصلتين ، فيمكننا توفير الموارد عن طريق تحسين الخادم لوظيفة معينة. قد يبدو تكوين الخادم كما يلي:

هناك حاجة إلى خدمات Microservices وإذا كنا بحاجة إلى توسيع نطاق بعض المجالات الوظيفية الضيقة على محمل الجد. على سبيل المثال ، تسمى مائة من أساليب واجهة برمجة التطبيقات (API) مائة مرة في الثانية ، على سبيل المثال ، تسمى أربعة من أساليب API بـ 10 آلاف مرة في الثانية. غالبًا ما لا يكون توسيع نطاق النظام برمته ضروريًا ، أي أنه يمكننا بالطبع مضاعفة جميع الطرق المائة في العديد من الخوادم ، لكن هذا ، كقاعدة عامة ، أكثر تكلفة بشكل ملحوظ وأكثر تعقيدًا من توسيع نطاق مجموعة ضيقة من الطرق. يمكننا فصل هذه المكالمات الأربعة في خدمة منفصلة وتوسيع نطاقها فقط لعدد كبير من الخوادم.
من الواضح أيضًا أننا قد نحتاج إلى خدمة مجهرية إذا كتبنا منطقة وظيفية منفصلة ، على سبيل المثال ، في بيثون. لأن بعض المكتبات (على سبيل المثال ، للتعلم الآلي) تبين أنها متوفرة فقط في بيثون ، ونريد فصلها في خدمة منفصلة. من المنطقي أيضًا تقديم خدمة مجهرية إذا كان جزء من النظام عرضة للفشل. من الجيد ، بطبيعة الحال ، كتابة التعليمات البرمجية بحيث لا تكون هناك إخفاقات من حيث المبدأ ، ولكن يمكن أن تكون الأسباب خارجية. ولا أحد في مأمن من أخطائهم. في هذه الحالة ، يمكن عزل الخلل داخل عملية منفصلة.
إذا كان التطبيق الخاص بك لا يحتوي على أي مما سبق ولم يكن متوقعًا في المستقبل المنظور ، على الأرجح ، فإن التطبيق المترابط يناسبك. الشيء الوحيد - أوصي بكتابته حتى لا تعتمد المجالات الوظيفية غير المرتبطة ببعضها البعض في الكود. لذلك ، إذا لزم الأمر ، يمكن فصل المناطق الوظيفية غير المرتبطة ببعضها البعض. ومع ذلك ، تعتبر هذه دائمًا توصية جيدة ، مما يؤدي إلى زيادة الاتساق الداخلي ويعلمك صياغة العقود النموذجية بعناية.
هندسة رد الفعل والبرمجة التفاعلية
النهج التفاعلي هو شيء جديد نسبيا. يمكن اعتبار لحظة ظهوره عام 2014 ، عندما تم نشر
بيان التفاعل . بعد عامين من نشر البيان ، كان معروفًا للجميع. هذا هو النهج الثوري حقا لتصميم النظام. , , , , .

, . , , : « , !?» , , , , «». , 100% , , .
— , — . .
? , .
- , - . - -, , HTTP-. , . , . , , , .
? , HTTP- , ( callback) ( ) . , - ( , HTTP-) .
— . . . . 3 Ghz , , . . . , Java-, HTTP- — 5-10%. , , , , 100 50 $/ — $500 . , , .
, ? .
, . , , , , , , . , , . .
- . , JDBC ( . ADA, R2DBC, ). 90 % , . — HTTP- , . , .

?
, , , ( ) . — - , . , , , HTTP.
, , , , , , .
. , « , » , , , . , , , 10 11 , , , .
الخاتمة
, . , , , .