أنماط معمارية مريحة

يا هبر!

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

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

التحجيم الأفقي

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

على سبيل المثال، سآخذ تخزينًا سحابيًا مجردًا للملفات، أي نوع من التناظرية لـ OwnCloud وOneDrive وما إلى ذلك.

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

أنماط معمارية مريحة
الفرق بين الطريقتين: في القياس الرأسي، نحن على استعداد لزيادة سعة العقد، وفي القياس الأفقي، نحن على استعداد لإضافة عقد جديدة لتوزيع الحمل.

CQRS

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

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

  1. أرسل العميل طلبًا إلى الخادم.
  2. بدأ الخادم عملية معالجة طويلة.
  3. استجاب الخادم للعميل بالنتيجة.

تخيل أنه في النقطة 2 حدث انقطاع في الاتصال (أو تمت إعادة الاتصال بالشبكة، أو انتقل المستخدم إلى صفحة أخرى، مما أدى إلى قطع الاتصال). في هذه الحالة، سيكون من الصعب على الخادم إرسال استجابة للمستخدم بمعلومات حول ما تمت معالجته بالضبط. باستخدام CQRS، سيكون التسلسل مختلفًا قليلاً:

  1. لقد اشترك العميل في التحديثات.
  2. أرسل العميل طلبًا إلى الخادم.
  3. أجاب الخادم "تم قبول الطلب".
  4. ورد الخادم بنتيجة عبر القناة من النقطة "1".

أنماط معمارية مريحة

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

ومن المثير للاهتمام أن رمز معالجة الرسائل الواردة يصبح هو نفسه (وليس 100%) بالنسبة للأحداث التي تأثرت بالعميل نفسه، وبالنسبة للأحداث الأخرى، بما في ذلك الأحداث الواردة من عملاء آخرين.

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

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

مصادر الحدث

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

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

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

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

أنماط معمارية مريحة

الميزات الهامة لهذا النهج:

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

اسمحوا لي أن أذكرك أننا ندرس حالة تخزين الملفات عبر الإنترنت. في هذه الحالة، سيبدو النظام كما يلي:

أنماط معمارية مريحة

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

وبالنسبة لمستخدمين، سيبدو المخطط كما يلي (يتم الإشارة إلى الخدمات المخصصة لمستخدمين مختلفين بألوان مختلفة):

أنماط معمارية مريحة

المكافآت من هذا المزيج:

  • يتم فصل خدمات معالجة المعلومات. كما يتم فصل قوائم الانتظار. إذا كنا بحاجة إلى زيادة إنتاجية النظام، فسنحتاج فقط إلى تشغيل المزيد من الخدمات على المزيد من الخوادم.
  • عندما نتلقى معلومات من مستخدم، لا يتعين علينا الانتظار حتى يتم حفظ البيانات بالكامل. بل على العكس، يكفي أن نجيب بـ«حسناً»، ثم نبدأ العمل تدريجياً. في الوقت نفسه، تعمل قائمة الانتظار على تنعيم القمم، نظرًا لأن إضافة كائن جديد يكون سريعًا، ولا يتعين على المستخدم انتظار المرور الكامل خلال الدورة بأكملها.
  • على سبيل المثال، أضفت خدمة إلغاء البيانات المكررة التي تحاول دمج الملفات المتطابقة. إذا كان يعمل لفترة طويلة في 1٪ من الحالات، فمن غير المرجح أن يلاحظه العميل (انظر أعلاه)، وهو زائد كبير، لأننا لم نعد نطلب السرعة والموثوقية بنسبة XNUMX٪.

ومع ذلك، فإن العيوب واضحة على الفور:

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

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

نتيجة ل:

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

عملية التجزئة

كما هو موضح أعلاه، لا يوجد اتساق قوي في أنظمة تحديد مصادر الأحداث. هذا يعني أنه يمكننا استخدام عدة مخازن دون أي مزامنة بينها. ونحن نقترب من مهمتنا، يمكننا:

  • فصل الملفات حسب النوع. على سبيل المثال، يمكن فك تشفير الصور/مقاطع الفيديو واختيار تنسيق أكثر كفاءة.
  • حسابات منفصلة حسب البلد. ونظرًا للعديد من القوانين، قد يكون هذا مطلوبًا، لكن هذا المخطط المعماري يوفر مثل هذا الاحتمال تلقائيًا.

أنماط معمارية مريحة

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

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

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

وبالتالي، واستمرارًا لمثالنا الخاص بتخزين الملفات عبر الإنترنت، فإن هذه البنية تمنحنا بالفعل عددًا من المكافآت:

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

استضافة المحتوى الثابت

قد تبدو هذه النقطة واضحة تمامًا، لكنها لا تزال ضرورية لتطبيق محمّل قياسي إلى حد ما. جوهرها بسيط: لا يتم توزيع كل المحتوى الثابت من نفس الخادم الذي يوجد به التطبيق، ولكن من محتويات خاصة مخصصة لهذا العمل. ونتيجة لذلك، تكون هذه العمليات أسرع (يخدم nginx الشرطي الملفات بشكل أسرع وأقل تكلفة من خادم Java). بالإضافة إلى بنية CDN (شبكة توصيل المحتوى) يتيح لنا وضع ملفاتنا بالقرب من المستخدمين النهائيين، مما له تأثير إيجابي على سهولة العمل مع الخدمة.

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

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

  • يصدر الخادم عنوان URL للتنزيل. يمكن أن يكون على شكل file_id + key، حيث يكون المفتاح عبارة عن توقيع رقمي صغير يمنح الحق في الوصول إلى المورد في اليوم التالي.
  • تتم معالجة توزيع الملف بواسطة nginx بسيط مع الخيارات التالية:
    • التخزين المؤقت للمحتوى. وبما أن هذه الخدمة يمكن وضعها على خادم منفصل، فقد تركنا لأنفسنا احتياطيًا للمستقبل مع القدرة على تخزين جميع أحدث الملفات التي تم تنزيلها على القرص.
    • التحقق من المفتاح في وقت إنشاء الاتصال
  • اختياري: معالجة المحتوى المتدفق. على سبيل المثال، إذا قمنا بضغط جميع الملفات في الخدمة، فيمكننا فك الضغط مباشرة في هذه الوحدة. ونتيجة لذلك: تتم عمليات الإدخال/الإخراج في المكان الذي تنتمي إليه. سيخصص برنامج الأرشفة في Java بسهولة الكثير من الذاكرة الإضافية، ومع ذلك، قد تكون إعادة كتابة الخدمة باستخدام منطق الأعمال إلى Rust / C ++ الشرطي غير فعالة أيضًا. في حالتنا، يتم استخدام عمليات (أو حتى خدمات) مختلفة، وبالتالي من الممكن فصل منطق الأعمال وعمليات الإدخال/الإخراج بشكل فعال.

أنماط معمارية مريحة

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

كمثال آخر (للدمج): إذا كنت قد عملت مع Jenkins/TeamCity، فأنت تعلم أن كلا الحلين مكتوبان بلغة Java. كلاهما عبارة عن عمليات Java تتعامل مع كل من تنسيق البناء وإدارة المحتوى. على وجه الخصوص، كلاهما لديه مهام مثل "نقل ملف/مجلد من الخادم". على سبيل المثال: إصدار القطع الأثرية، ونقل الكود المصدري (عندما لا يقوم الوكيل بتنزيل الكود مباشرة من المستودع، ولكن الخادم يقوم بذلك نيابة عنه)، والوصول إلى السجلات. تختلف كل هذه المهام في الحمل على الإدخال/الإخراج. وهذا هو، اتضح أن الخادم المسؤول عن منطق الأعمال المعقد، في نفس الوقت، يجب أن يكون قادرًا على دفع تدفقات البيانات الكبيرة بشكل فعال من خلال نفسه. والأمر الأكثر إثارة للاهتمام هو أنه يمكن تفويض مثل هذه العملية إلى نفس nginx وفقًا لنفس المخطط تمامًا (باستثناء أنه يجب إضافة مفتاح البيانات إلى الطلب).

ومع ذلك، إذا عدنا إلى نظامنا، فسنحصل على مخطط مماثل:

أنماط معمارية مريحة

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

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

اختتام

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

لكن الأهم من ذلك هو أن كل هذه الأنماط أصبحت سهلة التطبيق للغاية في التطبيقات الحديثة (إذا كانت مناسبة بالطبع). توفر السحابة المشاركة والقياس الأفقي في وقت واحد، وهو أمر أسهل بكثير من طلب خوادم مخصصة مختلفة في مراكز بيانات مختلفة بنفسك. لقد أصبح CQRS أسهل بكثير، وذلك فقط بسبب تطور المكتبات مثل RX. منذ حوالي 10 سنوات، كان بإمكان موقع ويب نادر أن يدعم هذا الأمر. من السهل أيضًا إعداد تحديد مصادر الأحداث بفضل الحاويات الجاهزة مع Apache Kafka. قبل 10 سنوات، كان من الممكن أن يكون هذا ابتكارًا، أما الآن فقد أصبح أمرًا شائعًا. وبالمثل، مع استضافة المحتوى الثابت: نظرًا للتقنيات الأكثر ملاءمة (بما في ذلك وجود وثائق مفصلة وقاعدة بيانات كبيرة من الإجابات)، أصبح هذا النهج أكثر بساطة.

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

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

المصدر: www.habr.com

إضافة تعليق