
عندما قمت بتطبيق واجهة المستخدم الخاصة
بموازنة التحميل لسحابة خاصة افتراضية ، كان علي مواجهة صعوبات كبيرة. قادني هذا إلى التفكير في دور الواجهة الأمامية ، والتي أريد مشاركتها في المقام الأول. ثم قم بتبرير أفكارهم باستخدام مثال مهمة محددة.
برأيي أن حل المشكلة قد تم إبداعه تمامًا ، وكان علي أن أبحث عنه في إطار محدود للغاية ، لذلك أعتقد أنه يمكن أن يكون مثيرًا للاهتمام.
دور الواجهة الأمامية
يجب أن أقول على الفور أنني لا أدعي الحقيقة وأثير قضية مثيرة للجدل. أشعر بالاكتئاب نوعًا ما من سخرية الواجهة الأمامية وشبكة الويب بشكل خاص ، كشيء لا معنى له. ومما يزيد من الإحباط أنه في بعض الأحيان يحدث هذا بشكل معقول. الآن كانت الموضة نائمة بالفعل ، ولكن كان هناك وقت كان فيه الجميع يركض مع الأطر والنماذج وغيرها من الكيانات ، قائلا بصوت عال أن كل هذا مهم للغاية وضروري للغاية ، وبالمقابل حصلوا على مفارقة أن الواجهة الأمامية تتعامل مع إخراج النماذج و معالجة النقرات على الأزرار ، والتي يمكن القيام بها "على الركبة".
الآن ، يبدو أن كل شيء قد عاد إلى حد ما إلى طبيعته. لا أحد يريد أن يتحدث عن كل إصدار بسيط من الإطار التالي. قليل من الناس يبحثون عن الأداة أو المنهج المثالي ، بسبب زيادة الوعي بفائدتهم. لكن حتى هذا ، على سبيل المثال ، لا يتعارض مع توبيخ الإلكترون والتطبيقات التي يتم عليها ذلك بشكل غير معقول. أعتقد أن هذا يرجع إلى عدم فهم المهمة التي يتم حلها بواسطة الواجهة الأمامية.
الواجهة الأمامية ليست مجرد وسيلة لعرض المعلومات التي توفرها الواجهة الخلفية ، وليست مجرد وسيلة لمعالجة إجراءات المستخدم. الواجهة الأمامية هي شيء أكثر من ذلك ، شيء تجريدي ، وإذا أعطيته تعريفًا بسيطًا وواضحًا ، فسيتم فقد المعنى حتماً.
الواجهة الأمامية في بعض "الإطار". على سبيل المثال ، من الناحية الفنية ، فهو يقع بين واجهة برمجة التطبيقات التي توفرها الواجهة الخلفية وواجهة برمجة التطبيقات التي توفرها مرافق الإدخال / الإخراج. من حيث المهام ، فمن بين مهام واجهة المستخدم التي يحلها UX والمهام التي يحلها الجزء الخلفي. وبالتالي ، يتم الحصول على التخصص الأمامي الضيق إلى حد ما ، وهو تخصص للطبقة. هذا لا يعني أنه لا يمكن لمقدمي الواجهة الأمامية التأثير على مناطق خارج تخصصهم ، ولكن في الوقت الذي يكون فيه هذا التأثير مستحيلًا ، تنشأ مهمة الواجهة الأمامية الحقيقية.
يمكن التعبير عن هذه المشكلة من خلال التناقض. واجهة المستخدم غير مطلوبة لتتوافق مع نماذج البيانات وسلوك الواجهة الخلفية. نماذج السلوك والبيانات للخلفية غير مطلوبة لتناسب مهام واجهة المستخدم. ثم مهمة الواجهة الأمامية هي القضاء على هذا التناقض. كلما زاد التباين بين مهام الواجهة وواجهة المستخدم ، زاد دور الواجهة الأمامية. ولكي أوضح ما أتحدث عنه ، سأقدم مثالاً على هذا التناقض ، لسبب ما ، اتضح أنه مهم.
بيان المشكلة
إن نظام OpenStack LBaaS ، في رأيي ، عبارة عن مجموعة برامجيات للأدوات اللازمة لموازنة الحمل بين الخوادم. من المهم بالنسبة لي أن يعتمد تنفيذها على عوامل موضوعية ، على الشاشة المادية. لهذا السبب ، هناك بعض الخصائص المميزة في واجهة برمجة التطبيقات وفي طرق التفاعل مع واجهة برمجة التطبيقات هذه.
عند تطوير واجهة مستخدم ، فإن الاهتمام الرئيسي ليس هو الميزات التقنية للواجهة الخلفية ، ولكن قدراتها الأساسية. يتم إنشاء الواجهة للمستخدم ، ويحتاج المستخدم إلى واجهة لإدارة معلمات الموازنة ، ولا يحتاج المستخدم إلى الغوص في الميزات الداخلية لتطبيق الواجهة الخلفية.
يتم تطوير الواجهة الخلفية للجزء الأكبر من المجتمع ، ومن الممكن التأثير على تطوره بكميات محدودة للغاية. واحدة من الميزات الرئيسية بالنسبة لي هي أن مطوري الواجهة الخلفية مستعدون للتضحية براحة وبساطة عناصر التحكم من أجل الأداء ، وهذا له ما يبرره تمامًا ، لأنه مسألة موازنة التحميل.
هناك نقطة أخرى خفية ، وأريد أن أوجزها على الفور ، مع تحذير بعض الأسئلة. من الواضح أنه في OpenStack وواجهة برمجة التطبيقات الخاصة به لم يتقارب الضوء. يمكنك دائمًا تطوير مجموعة من الأدوات الخاصة بك أو "طبقة" ستعمل مع واجهة برمجة تطبيقات OpenStack ، مما ينتج عنه واجهة برمجة التطبيقات الخاصة به والتي تكون مناسبة لمهام المستخدم. السؤال الوحيد هو النفعية. إذا كانت الأدوات المتاحة مبدئيًا تسمح لك بتنفيذ واجهة المستخدم كما هو مقصود ، فهل من المنطقي إنتاج كيانات؟
الجواب على هذا السؤال متعدد الأوجه ، وبالنسبة للأعمال التجارية ، فسوف يعتمد على المطورين وتوظيفهم وكفاءتهم ومسائل المسؤولية والدعم وما إلى ذلك. في حالتنا ، كان من الأنسب حل بعض المهام على الواجهة الأمامية.
ميزات OpenStack LBaaS
أريد فقط تحديد تلك الميزات التي كان لها تأثير قوي على الواجهة الأمامية. إن الأسئلة التي تظهر حول سبب ظهور هذه الميزات أو ما تعتمد عليه هي بالفعل خارج نطاق هذه المقالة.
أنا أعمل مع وثائق جاهزة ويجب أن أقبل ميزاته. يمكن لأولئك المهتمين بماهية OpenStack Octavia من الداخل الاطلاع على
الوثائق الرسمية . Octavia هو اسم مجموعة من الأدوات المصممة لموازنة الحمل في نظام OpenStack البيئي.
الميزة الأولى التي واجهتها أثناء التطوير هي العدد الكبير من النماذج والعلاقات اللازمة لعرض حالة الموازن. تصف
واجهة برمجة تطبيقات Octavia 12 نموذجًا ، ولكن لا يلزم سوى 7 نماذج من جانب العميل ، فهذه النماذج لها اتصالات ، غالبًا ما تكون غير طبيعية ، وتظهر الصورة أدناه مخططًا تقريبيًا:
لا يبدو الرقم "Seven" مثيرًا للإعجاب ، ولكن في الواقع ، لضمان التشغيل الكامل للواجهة ، في وقت كتابة هذا النص ، كان علي استخدام 16 نموذجًا للبيانات وحوالي 30 علاقة بينها. نظرًا لأن Octavia هو مجرد موازن ، فإنه يتطلب وحدات OpenStack الأخرى للعمل. وكل هذا مطلوب لصفحتين فقط في واجهة المستخدم.
الميزات الثانية والثالثة هي اوكتافيا
غير متزامن والمعاملات. تحتوي نماذج البيانات على حقل
حالة يعكس حالة العمليات المنفذة على كائن ما.
تحدث عملية قراءة كائن بشكل متزامن وليس له قيود. لكن عمليات إنشاء وتحديث وحذف قد تستغرق وقتًا غير محدد. ويرجع هذا بالتحديد إلى حقيقة أن نماذج البيانات لها معنى مادي تقريبًا.
بعد إرسال طلب الإنشاء ، يمكننا أن نعرف أن السجل قد ظهر ، ويمكننا قراءته ، ولكن حتى يتم الانتهاء من عملية الإنشاء ، لا يمكننا إجراء أي عمليات أخرى على هذا السجل. أي محاولة من هذا القبيل سوف ينتج عنها خطأ. لا يمكن بدء عملية تغيير كائن إلا عندما يكون الكائن في حالة
ACTIVE ؛ يمكنك إرسال كائن للحذف في
حالتي ACTIVE و
ERROR .
يمكن أن تأتي هذه الحالات عبر WebSockets ، مما يسهل معالجتها إلى حد كبير ، لكن المعاملات تشكل مشكلة أكبر بكثير. عند إجراء تغييرات على أي كائن ، ستشارك جميع الطرز ذات الصلة أيضًا في المعاملة. على سبيل المثال ، عند إجراء تغييرات على "
عضو" ، سيتم حظر "
التجمع" و "
المستمع" و "
Loadbalancer" . هذا ما يبدو عليه من حيث الأحداث المستلمة على مآخذ الويب:
- الأحداث الأربعة الأولى هي نقل الكائنات إلى حالة PENDING_UPDATE : يحتوي الحقل الهدف على اسم طراز الكائن المشترك في المعاملة ؛
- الحدث الخامس مجرد نسخة مكررة (لا أعرف ما هو متصل به) ؛
- الأربعة الأخيرة هي عودة إلى حالة ACTIVE . في هذه الحالة ، هذه عملية تغيير الوزن ، وتستغرق أقل من ثانية ، ولكن في بعض الأحيان يستغرق الكثير من الوقت.
يمكنك أيضًا أن ترى في لقطة الشاشة أن ترتيب الأحداث لا يجب أن يكون صارمًا. وبالتالي ، اتضح أنه من أجل الشروع في أي عملية ، من الضروري معرفة حالة الكائن نفسه فحسب ، بل معرفة حالات جميع التبعيات التي ستشارك أيضًا في المعاملة.
ميزات واجهة المستخدم
الآن تخيل نفسك في مكان المستخدم الذي يحتاج إلى معرفة مكان ما لتحقيق التوازن بين خادمين:
- من الضروري إنشاء مستمع يتم فيه تحديد خوارزمية الموازنة.
- إنشاء تجمع.
- تعيين تجمع للمستمع.
- إضافة روابط إلى منافذ متوازنة إلى التجمع.
في كل مرة يكون من الضروري الانتظار لاستكمال العملية ، والتي تعتمد على جميع الكائنات التي تم إنشاؤها مسبقًا.
كما أظهرت دراسة داخلية ، من وجهة نظر المستخدم العادي ، لا يوجد سوى إدراك تقريبي بأن الموازن يجب أن يكون له نقطة دخول ، ويجب أن تكون هناك نقاط خروج ومعلمات التوازن المطلوب تنفيذها: الخوارزمية ، والوزن وغيرها. لا يتعين على المستخدم معرفة ماهية OpenStack.
لا أعرف مدى تعقيد الواجهة بالنسبة للإدراك ، حيث يجب على المستخدم نفسه اتباع جميع الميزات التقنية للواجهة الخلفية الموضحة أعلاه. بالنسبة إلى وحدة التحكم ، قد يكون ذلك مسموحًا به ، حيث أن استخدامه ينطوي على مستوى عالٍ من الانغماس في التكنولوجيا ، ولكن بالنسبة إلى الويب ، تكون هذه الواجهة مروعة.
على الويب ، يتوقع المستخدم ملء نموذج واحد واضح ومنطقي ، اضغط على زر واحد ، والانتظار وكل شيء سوف يعمل. ربما يمكن مناقشة ذلك ، لكنني أقترح التركيز على الميزات التي تؤثر على تنفيذ الواجهة الأمامية.
تم تصميم الواجهة بطريقة تتضمن الاستخدام المتتالي للعمليات: قد يتضمن إجراء واحد في الواجهة عدة عمليات. لا تعني الواجهة أن المستخدم يمكنه تنفيذ إجراءات غير ممكنة حاليًا ، لكن الواجهة تفترض أن المستخدم يجب أن يفهم سبب ذلك. الواجهة عبارة عن مجموعة واحدة ، وبالتالي ، يمكن لعناصرها الفردية استخدام المعلومات من مختلف الكيانات التابعة ، بما في ذلك المعلومات الوصفية.
إذا أخذنا في الاعتبار أن هناك بعض ميزات الواجهة غير الفريدة للموازن ، مثل رموز التبديل والأكورديونات وعلامات التبويب وقائمة السياق ونفترض أن مبادئ التشغيل الخاصة بهم واضحة مبدئيًا ، فإنني أفكر لمستخدم يعرف موازنة التحميل ، وليس سيكون من الصعب جدًا قراءة معظم الواجهة أعلاه وإجراء افتراض حول كيفية إدارتها. ولكن لتسليط الضوء على أي أجزاء من الواجهة مخبأة وراء نماذج الموازن ، لم يعد المستمع ، التجمع ، العضو والكيانات الأخرى المهمة الأكثر وضوحًا.
حل التناقضات
آمل أن أتمكن من إظهار أن ميزات الواجهة الخلفية لا تتناسب مع الواجهة بشكل جيد ، وأن هذه الميزات لا يمكن دائمًا التخلص منها بواسطة الواجهة الخلفية. بالإضافة إلى ذلك ، لا تتناسب ميزات الواجهة جيدًا مع الواجهة الخلفية ، كما لا يمكن التخلص منها دائمًا دون تعقيد الواجهة. كل من هذه المجالات يحل مشاكله الخاصة. تتمثل مسؤولية الواجهة الأمامية في حل المشكلات لضمان المستوى اللازم من التفاعل بين الواجهة والواجهة الخلفية.
في ممارستي ، هرعت على الفور إلى حمام السباحة برأسي ، دون الاهتمام ، أو حتى لا أحاول معرفة تلك الميزات الأعلى ، لكنني كنت محظوظًا أو ساعدت التجربة (وتم اختيار المتجه الصحيح). لقد لاحظت مرارًا وتكرارًا بنفسي أنه عند استخدام واجهة أو مكتبة لجهة خارجية ، من المفيد للغاية أن تتعرف على الوثائق مقدمًا: كلما كان ذلك أكثر تفصيلًا. غالبًا ما تكون الوثائق متشابهة مع بعضها البعض ، حيث لا يزال الأشخاص يعتمدون على تجربة أشخاص آخرين ، لكن هناك وصفًا لميزات كل نظام على حدة ، وهو موجود في التفاصيل.
إذا كنت قد قضيت في البداية بضع ساعات إضافية في دراسة الوثائق ، بدلاً من سحب المعلومات الضرورية بالكلمات الرئيسية ، فكرت في المشكلات التي يجب مواجهتها ، وقد يكون لهذه المعرفة تأثير على بنية المشروع من المراحل المبكرة للغاية. العودة إلى القضاء على الأخطاء التي ارتكبت في البداية أمر محبط للغاية. وبدون سياق كامل ، في بعض الأحيان عليك العودة عدة مرات.
كخيار ، يمكنك ثني السطر الخاص بك ، وإنشاء رموز أكثر وأكثر تدريجيًا "مع لدغة" ، ولكن كلما زاد حجم كومة الشفرة هذه ، زاد عدد النقاط في النهاية. عند تصميم الهيكل ، بالطبع ، لا ينبغي للمرء أن يغوص عميقًا ، ويأخذ في الاعتبار جميع الخيارات الممكنة والمستحيلة ، وقضاء وقتًا طويلاً عليها ، من المهم إيجاد توازن. لكن التعارف المفصل أكثر أو أقل مع الوثائق غالبًا ما يكون استثمارًا مفيدًا للغاية وليس كم كبير جدًا من الوقت.
ومع ذلك ، فمنذ البداية ، بعد أن رأيت عددًا كبيرًا من الطرز المتضمنة ، أدركت أنه سيكون من الضروري إنشاء تخطيط لحالة الواجهة الخلفية للعميل مع الحفاظ على جميع الاتصالات. بعد أن تمكنت من عرض كافة المعلومات الضرورية على العميل ، مع جميع الاتصالات وما إلى ذلك ، كان من الضروري تنظيم قائمة انتظار مهمة.
يتم تحديث البيانات بشكل غير متزامن ، ويتم تحديد توفر العمليات من خلال مجموعة متنوعة من الشروط ، وعندما تكون هناك حاجة إلى عمليات متتالية ، لا يمكن الاستغناء عن قائمة انتظار في مثل هذه الظروف. ربما ، باختصار ، هذه هي البنية الكاملة للحل الخاص بي: التخزين مع انعكاس الحالة الخلفية وقائمة الانتظار المهمة.
هندسة الحلول
نظرًا للعدد غير المحدود من النماذج والعلاقات ، فقد وضعت قابلية التوسع في بنية المستودع عن طريق القيام بذلك باستخدام مصنع يقوم بإرجاع وصف تعريفي لمجموعات المستودع. المجموعة لديها خدمة ، فئة نموذج بسيط مع CRUD. قد يكون من الممكن تقديم وصف للارتباطات الموجودة في النموذج ، كما هو الحال ، على سبيل المثال ، في RoR أو في العمود الفقري القديم الجيد ، ولكن هذا سيتطلب تغييرًا كبيرًا في الكود. لذلك ، يقع وصف العلاقات بجوار الفئة النموذجية:
في المجموع ، حصلت على نوعين من الاتصالات: واحد إلى واحد ، واحد لكثير. ويمكن أيضا أن يوصف ردود الفعل. بالإضافة إلى النوع ، تتم الإشارة إلى مجموعة التبعيات ، والحقل الذي يتم إرفاق التبعية التي تم العثور عليها والحقل الذي تتم من خلاله قراءة معرف الكائن التابع (في حالة اتصال واحد إلى كثير ، تتم قراءة قائمة المعرفات). إذا كانت حالة كائن ما للاتصال أكثر تعقيدًا من الارتباطات البسيطة بالكائنات ، فيمكنك في المصنع وصف وظيفة اختبار كائنين ، والتي ستحدد نتائجها وجود الاتصال. يبدو كل شيء "دراجة" قليلاً ، لكنه يعمل بدون تبعيات غير ضرورية وبالضبط كما ينبغي.
يحتوي المستودع على وحدة نمطية لانتظار إضافة وحذف مورد ، وهو في جوهره يقوم بمعالجة الأحداث لمرة واحدة من خلال التحقق المشروط وبواجهة promis. عند الاشتراك ، يتم تمرير نوع الحدث (إضافة وحذف) ، وظيفة الاختبار ، والمعالج. عند حدوث حدث معين ونتيجة اختبار إيجابية ، يتم تنفيذ المعالج ، وبعد ذلك يتوقف التتبع. قد يحدث حدث عند الاشتراك بشكل متزامن.
إن استخدام مثل هذا النمط جعل من الممكن تلقائيًا تثبيت العلاقات المعقدة بشكل تعسفي بين النماذج ، والقيام بذلك في مكان واحد. هذا المكان اتصلت تعقب. عند إضافة كائن إلى المخزون ، يبدأ في تتبع علاقاته. تسمح لك وحدة الانتظار بالرد على الأحداث والتحقق من وجود اتصال بين الكائن المراقبة والكائن الموجود في وحدة التخزين. إذا كان الكائن موجودًا بالفعل في المستودع ، فإن وحدة الانتظار تستدعي المعالج فورًا.
يسمح لك جهاز التخزين هذا بوصف أي عدد من المجموعات والعلاقات بينهما. عند إضافة وحذف كائنات ، يقوم المتجر تلقائيًا بوضع أو إعادة تعيين الخصائص مع محتويات الكائنات التابعة. تتمثل مزايا هذا النهج في أن جميع العلاقات موصوفة بشكل صريح ، ويتم مراقبتها وتحديثها بواسطة نظام واحد ؛ سلبيات - في تعقيد التنفيذ والتصحيح.
بشكل عام ، يكون هذا المستودع بسيطًا جدًا وقد فعلت ذلك بنفسي ، لأنه سيكون من الصعب للغاية دمج حل جاهز في قاعدة تعليمات برمجية موجودة بالفعل ، ولكن سيكون من الأصعب ربط قائمة انتظار مهمة بحل جاهز.
جميع المهام ، مثل المجموعات ، لها وصف تعريفي ويتم إنشاؤها بواسطة المصنع. يمكن أن تحتوي المهام في الوصف على شروط بدء التشغيل وقائمة بالمهام التي ستحتاج إلى إضافتها إلى قائمة الانتظار بعد اكتمال القائمة الحالية.
يوضح المثال أعلاه مهمة إنشاء تجمع. في التبعيات ، تتم الإشارة إلى الموازن والمستمع ، بشكل افتراضي ، يتم إجراء فحص للحالة
النشطة . تم تأمين كائن الموازن ، لأن معالجة المهام في قائمة الانتظار يمكن أن تحدث بشكل متزامن ، يسمح لك القفل بتجنب التعارضات في وقت إرسال طلب التنفيذ ، لكن الحالة لم تتغير ، لكن من المفترض أنها ستتغير. بدلاً من
PARENT ، إذا تم إنشاء التجمع كنتيجة لتسلسل المهام ، فسيتم استبدال
المعرف تلقائيًا.
بعد إنشاء تجمع ، ستتم إضافة المهام إلى قائمة الانتظار لإنشاء شاشة توفر وإنشاء جميع أعضاء هذا التجمع. الإخراج هو هيكل يمكن تحويله بالكامل إلى JSON. يتم ذلك لتتمكن من استعادة قائمة الانتظار في حالة الفشل.
قائمة الانتظار ، بناءً على وصف المهمة ، تراقب بشكل مستقل جميع التغييرات في المستودع وتتحقق من الشروط التي يجب الوفاء بها لتشغيل المهمة. كما قلت سابقًا ، تأتي الحالات عبر مآخذ الويب ، ومن السهل جدًا إنشاء الأحداث اللازمة لقائمة الانتظار ، ولكن إذا لزم الأمر ، فلن تكون هناك مشكلة في إرفاق آلية لتحديث بيانات المؤقت (تم وضع هذا في الأصل في البنية ، حيث أن مآخذ الويب كانت موجودة لأسباب مختلفة قد لا تعمل مستقرة جدا). بعد اكتمال المهمة ، تقوم قائمة الانتظار تلقائيًا بإبلاغ المستودع عن الحاجة إلى تحديث الارتباطات في الكائنات المحددة.
استنتاج
أدت الحاجة إلى قابلية التوسع إلى نهج تعريفي. أدت الحاجة إلى عرض النماذج والعلاقات بينهما إلى مستودع واحد. أدت الحاجة إلى معالجة الكائنات التابعة إلى قائمة الانتظار.
قد لا يكون الجمع بين هذه الاحتياجات أسهل مهمة فيما يتعلق بالتنفيذ (ولكن هذه مشكلة منفصلة). ولكن فيما يتعلق بالهندسة المعمارية ، فإن الحل بسيط للغاية ويسمح لك بالقضاء على جميع التناقضات بين مهام الواجهة الخلفية وواجهة المستخدم ، لتأسيس تفاعلها ووضع الأساس لميزات أخرى محتملة لأي من الأطراف.
من جانب
لوحة التحكم Selectel
، تكون عملية الموازنة بسيطة ومباشرة ، حيث تتيح لعملاء
الخدمة عدم إنفاق الموارد على التنفيذ المستقل للموازن ، مع الحفاظ على القدرة على التحكم في حركة المرور بمرونة.
جرب موازننا في العمل الآن واكتب رأيك في التعليقات.