التوسع عند الطلب: كيف تتعامل السيرفرليس مع طفرات حركة المرور بسهولة

التوسع عند الطلب: كيف تتعامل السيرفرليس مع طفرات حركة المرور بسهولة

في المقال السابق، ناقشنا نموذجين من نماذج العمليات للسيرفرليس: التشغيل حتى الاكتمال (run-to-completion) والعمليات طويلة الأمد (long-running processes). الفرق الرئيسي بين هذين النموذجين يكمن في ما إذا كانت دالة المثيل تنتهي فورًا بعد التنفيذ. بالإضافة إلى ذلك، استكشفنا سيناريوهين: تنسيق البيانات (data orchestration) وتنسيق الخدمات (service orchestration).

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

لفهم هذا بالكامل، نحتاج إلى تقديم مفهوم حاسم في تطور بنية التطبيقات المعقدة على الإنترنت: التوسع (scaling)، وهو محور هذه المقالة.

تخيل أن 200 مستخدم يصلون في نفس الوقت إلى صفحة index.html الرئيسية لتطبيق ويب قمت بتطويره محليًا. ماذا يحدث لمثيل خادم الويب المحلي لديك؟

دعنا نصف حالة جهاز الكمبيوتر الخاص بك. أولاً، يتم إنشاء 200 اتصال TCP/IP بين العملاء وجهاز الكمبيوتر الخاص بك، وهو ما قد يواجه صعوبة في التعامل معه. ثم، يقوم جميع العملاء البالغ عددهم 200 ببدء طلبات HTTP “GET/” في نفس الوقت. تنشئ العملية الرئيسية لخادم الويب الخاص بك عددًا من العمليات الفرعية يساوي “عدد أنوية وحدة المعالجة المركزية -1” بشكل متزامن للتعامل مع هذه الطلبات. لاحظ أننا نطرح واحدًا من عدد أنوية وحدة المعالجة المركزية لترك نواة واحدة للعملية الرئيسية.

على سبيل المثال، تقوم وحدة معالجة مركزية بأربعة أنوية بإنشاء ثلاث عمليات فرعية للتعامل مع ثلاثة طلبات عملاء بشكل متزامن، بينما يتم وضع الطلبات المتبقية في قائمة انتظار. تبدأ العمليات الفرعية في معالجة طلبات “GET/”، وتطابق قواعد التوجيه، وتدخل وظيفة التحكم المقابلة، وتعيد index.html إلى العملاء. بمجرد أن ترسل إحدى العمليات الفرعية ملف index.html، تقوم العملية الرئيسية بإعادة تدويرها وتنشئ عملية جديدة للتعامل مع الطلب التالي حتى تتم معالجة جميع الطلبات.

بفهم هذا، يصبح السؤال التالي بسيطًا. كيف نحسن سرعة معالجة قائمة انتظار العملاء لدينا؟

التوسع الرأسي مقابل التوسع الأفقي

الحل الواضح هو زيادة عدد أنوية وحدة المعالجة المركزية. يمكننا تحقيق ذلك من خلال ترقية تكوين جهاز واحد، على سبيل المثال من 4 أنوية إلى 8 أنوية، مما ينتج عنه 7 عمليات فرعية متزامنة.

بالإضافة إلى زيادة أنوية وحدة المعالجة المركزية مباشرة، يمكننا إضافة المزيد من الأجهزة (كل منها بأربعة أنوية). من خلال توزيع 500 عميل على كل جهاز من الجهازين، يمكننا أيضًا زيادة عدد العمليات الفرعية المتزامنة إلى 6.

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

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

الحالة (Stateful) مقابل اللا حالة (Stateless)

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

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

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

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

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

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

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

دعنا نفكر في نهج بديل لاستمرار البيانات. لماذا يجب علينا الاتصال بقاعدة البيانات بأنفسنا؟ عمليات CRUD (إنشاء، قراءة، تحديث، حذف) الخاصة بنا على البيانات تتضمن بشكل أساسي قيام العمليات الفرعية بإعادة استخدام اتصال TCP الذي أنشأته العملية الرئيسية، وإرسال جمل قاعدة البيانات، واسترجاع البيانات. تخيل لو كان بإمكاننا إرسال تعليمات إلى قاعدة البيانات باستخدام طلبات HTTP مثل POST وDELETE وPUT وGET. ألن يمكننا ذلك من الاستفادة من مفاهيم تنسيق البيانات وتنسيق الخدمات من الدرس السابق؟

ما هو BaaS

في الواقع، كل هذا التمهيد يقودنا إلى بطل اليوم: تحويل الخدمات إلى BaaS (BaaSification). عمليات واجهة البيانات POST وDELETE وPUT وGET تتوافق مع طرق HTTP الدلالية لواجهات برمجة تطبيقات RESTful. بأخذ MySQL كمثال، POST يتوافق مع أمر CREATE، DELETE مع DELETE، PUT مع UPDATE، وGET مع SELECT. هذا التوافق الدلالي الفردي يسمح لنا بترجمة عمليات MySQL بشكل طبيعي إلى عمليات RESTful API.

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

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

ملخص

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

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

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

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

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

Novita AI هي منصة سحابية شاملة تمكن طموحاتك في الذكاء الاصطناعي. واجهات برمجة تطبيقات متكاملة، سيرفرليس، مثيل GPU — الأدوات الفعالة من حيث التكلفة التي تحتاجها. تخلص من البنية التحتية، ابدأ مجانًا، واجعل رؤيتك للذكاء الاصطناعي حقيقة.

قراءة موصى بها

الكشف عن الثورة: استكشاف عالم الحوسبة السيرفرليس

تحليل السيرفرليس، بدءًا من نماذج البيانات