ما هي خدمة الشبكة؟ هذا برنامج يقبل الطلبات الواردة عبر الشبكة ويعالجها ، وربما يعيد الردود.
هناك العديد من الجوانب التي تختلف فيها خدمات الشبكة عن بعضها البعض. في هذه المقالة ، أركز على كيفية التعامل مع الطلبات الواردة.
اختيار طريقة معالجة الطلب له عواقب بعيدة المدى. كيفية جعل خدمة الدردشة تحمل 100،000 الاتصالات في وقت واحد؟ ما الطريقة التي يجب اتباعها لاستخراج البيانات من مجموعة من الملفات سيئة التنظيم؟ الاختيار الخاطئ سيؤدي إلى تضييع الوقت والطاقة.
تتناول هذه المقالة طرقًا مثل مجموعة من العمليات / سلاسل العمليات ، والمعالجة الموجهة إلى الحدث ، ونمط نصف المزامنة / نصف المزامنة وغيرها الكثير. يتم إعطاء العديد من الأمثلة ، إيجابيات وسلبيات النهج ، يتم النظر في ميزاتها والتطبيقات.
مقدمة
موضوع أساليب معالجة الاستعلام ليس جديدًا ، انظر ، على سبيل المثال: واحد ، اثنان . ومع ذلك ، فإن معظم المقالات تعتبره جزئيًا فقط. تهدف هذه المقالة إلى سد الثغرات وتقديم عرض ثابت للقضية.
سيتم النظر في الطرق التالية:
- معالجة متسلسلة
- عملية الطلب
- تيار الطلب
- تجمع عملية / موضوع
- معالجة موجهة نحو الحدث (نمط المفاعل)
- نصف تزامن / نصف نمط متزامن
- تجهيز ناقل
تجدر الإشارة إلى أن الخدمة التي تعالج الطلبات ليست بالضرورة خدمة شبكة. قد تكون هذه خدمة تستقبل مهام جديدة من قاعدة بيانات أو قائمة انتظار المهام. في هذه المقالة ، تُقصد بخدمات الشبكة ، لكن عليك أن تفهم أن الطرق قيد النظر لها نطاق أوسع.
TL ؛ د
في نهاية المقال قائمة مع وصف موجز لكل نهج.
معالجة متسلسلة
يتكون التطبيق من سلسلة عمليات واحدة في عملية واحدة. تتم معالجة جميع الطلبات بالتتابع فقط. لا يوجد التوازي. إذا جاءت عدة طلبات للخدمة في نفس الوقت ، تتم معالجة أحدها ، يتم وضع الباقي في قائمة الانتظار.
بالإضافة إلى ذلك ، هذا النهج سهل التنفيذ. لا توجد أقفال والمنافسة على الموارد. ناقص واضح هو عدم القدرة على التوسع مع عدد كبير من العملاء.
عملية الطلب
يتكون التطبيق من عملية أساسية تقبل الطلبات وسير العمل الواردة. لكل طلب جديد ، تنشئ العملية الرئيسية سير عمل يعالج الطلب. يعد القياس حسب عدد الطلبات بسيطًا: يحصل كل طلب على العملية الخاصة به.
لا يوجد شيء معقد في هذه الهندسة المعمارية ، لكن لديها المشاكل القيود :
- تستهلك هذه العملية الكثير من الموارد.
حاول إنشاء 10000 اتصال متزامن مع PostgreSQL RDBMS وانظر إلى النتيجة. - لا تحتوي العمليات على ذاكرة مشتركة (افتراضي). إذا كنت بحاجة إلى الوصول إلى البيانات المشتركة أو ذاكرة التخزين المؤقت المشتركة ، فسيتعين عليك تعيين ذاكرة مشتركة (استدعاء linux mmap أو munmap) أو استخدام وحدة تخزين خارجية (memcahed ، redis)
هذه المشاكل ليست بأي حال من الأحوال التوقف. سيوضح التالي كيف تتم إدارتها في PostgeSQL RDBMS.
إيجابيات هذه الهندسة المعمارية:
- لن يؤثر سقوط إحدى العمليات على العمليات الأخرى. على سبيل المثال ، لن يسقط خطأ معالجة حالة نادرة التطبيق بالكامل ، فسيعاني الطلب المعالج فقط
- تمايز حقوق الوصول على مستوى نظام التشغيل. نظرًا لأن العملية هي جوهر نظام التشغيل ، يمكنك استخدام آلياتها القياسية لتحديد حقوق الوصول إلى موارد نظام التشغيل
- يمكنك تغيير عملية التشغيل على الطاير. على سبيل المثال ، إذا تم استخدام برنامج نصي منفصل لمعالجة طلب ، ثم لاستبدال خوارزمية المعالجة ، يكفي تغيير البرنامج النصي. مثال سينظر أدناه.
- آلات متعددة النواة تستخدم بكفاءة
أمثلة:
- ينشئ PostgreSQL RDBMS عملية جديدة لكل اتصال جديد. يتم استخدام الذاكرة المشتركة للعمل مع البيانات العامة. يمكن لـ PostgreSQL معالجة استهلاك الموارد المرتفع للعمليات بعدة طرق مختلفة. إذا كان هناك عدد قليل من العملاء (موقف مخصص للمحللين) ، فلا توجد مشكلة من هذا القبيل. إذا كان هناك تطبيق واحد يصل إلى قاعدة البيانات ، يمكنك إنشاء تجمع اتصال قاعدة البيانات على مستوى التطبيق. إذا كان هناك العديد من التطبيقات ، يمكنك استخدام pgbouncer
- يستمع sshd للطلبات الواردة على المنفذ 22 والشوكة في كل اتصال. كل اتصال ssh هو تفرع من البرنامج الخفي sshd الذي يستقبل وينفذ أوامر المستخدم بالتسلسل. بفضل هذه البنية ، تستخدم موارد نظام التشغيل نفسه للتمييز بين حقوق الوصول
- مثال من ممارستنا الخاصة. هناك مجموعة من الملفات غير المهيكلة تحتاج إلى الحصول على بيانات التعريف منها. تقوم عملية الخدمة الرئيسية بتوزيع الملفات بين عمليات المعالج. كل عملية معالج هي برنامج نصي يأخذ مسار ملف كمعلمة. تحدث معالجة الملفات في عملية منفصلة ، وبالتالي ، بسبب خطأ في المعالجة ، لا تتعطل الخدمة بأكملها. لتحديث خوارزمية المعالجة ، يكفي تغيير البرامج النصية للمعالجة دون إيقاف الخدمة.
بشكل عام ، يجب أن أقول أن هذا النهج له مزاياه ، التي تحدد نطاقه ، لكن قابلية التوسع محدودة للغاية.
طلب تيار
هذا النهج يشبه إلى حد كبير النهج السابق. الفرق هو أن مؤشرات الترابط تستخدم بدلاً من العمليات. هذا يتيح لك استخدام الذاكرة المشتركة خارج الصندوق. ومع ذلك ، لا يمكن استخدام المزايا الأخرى للنهج السابق ، في حين أن استهلاك الموارد سيكون مرتفعًا أيضًا.
الايجابيات:
- من خارج منطقة الجزاء الذاكرة المشتركة
- سهولة التنفيذ
- الاستخدام الفعال لوحدات المعالجة المركزية متعددة النواة
سلبيات:
- دفق يستهلك الكثير من الموارد. في أنظمة التشغيل المشابهة لنظام التشغيل يونيكس ، يستهلك مؤشر الترابط عددًا تقريبًا من الموارد مثل عملية
مثال على استخدام MySQL. ولكن تجدر الإشارة إلى أن MySQL تستخدم مقاربة مختلطة ، لذلك سيتم مناقشة هذا المثال في القسم التالي.
تجمع العمليات / الخيط
تيارات (عمليات) إنشاء مكلفة وطويلة. حتى لا تضيع الموارد ، يمكنك استخدام نفس سلسلة الرسائل بشكل متكرر. بعد تحديد الحد الأقصى لعدد سلاسل العمليات بالإضافة إلى ذلك ، نحصل على مجموعة مؤشرات الترابط (العمليات). الآن يقبل مؤشر الترابط الرئيسي الطلبات الواردة ويضعها في قائمة انتظار. تأخذ مهام سير العمل طلبات من قائمة الانتظار ومعالجتها. يمكن اعتبار هذه الطريقة بمثابة التدرج الطبيعي للمعالجة المتسلسلة للطلبات: يمكن لكل مؤشر ترابط عامل معالجة التدفقات بالتتابع فقط ، وتجميعها يسمح لك بمعالجة الطلبات بالتوازي. إذا كان بإمكان كل تدفق التعامل مع 1000 دورة في الثانية ، فسوف يتعامل 5 تدفقات مع الحمل بالقرب من 5000 دورة في الثانية (مع مراعاة الحد الأدنى من المنافسة للموارد المشتركة).
يمكن إنشاء المسبح مقدما في بداية الخدمة أو تشكيله تدريجيا. استخدام تجمع الخيط أكثر شيوعًا يسمح لك بتطبيق الذاكرة المشتركة.
حجم تجمع مؤشر الترابط ليس من الضروري أن يكون محدودا. يمكن للخدمة استخدام سلاسل الرسائل المجانية من التجمع ، وإذا لم يكن هناك أي شيء ، يمكنك إنشاء سلسلة رسائل جديدة. بعد معالجة الطلب ، ينضم الخيط إلى التجمع وينتظر الطلب التالي. هذا الخيار هو مزيج من نهج مؤشر الترابط عند الطلب وتجمع مؤشر ترابط. سيتم إعطاء مثال أدناه.
الايجابيات:
- استخدام العديد من النوى وحدة المعالجة المركزية
- خفض التكلفة لإنشاء موضوع / عملية
سلبيات:
- قابلية التوسع في عدد العملاء المتزامنين. يتيح لنا استخدام التجمّع إعادة استخدام نفس الخيط عدة مرات دون تكاليف موارد إضافية ، إلا أنه لا يحل المشكلة الأساسية لعدد كبير من الموارد التي يستهلكها الخيط / العملية. سيفشل إنشاء خدمة دردشة يمكنها تحمل 100،000 اتصال متزامن باستخدام هذا النهج.
- يتم تقييد قابلية التوسع بواسطة الموارد المشتركة ، على سبيل المثال ، إذا كانت مؤشرات الترابط تستخدم الذاكرة المشتركة من خلال ضبط الوصول إليها باستخدام الإشارات / المزامير. هذا هو الحد من جميع النهج التي تستخدم الموارد المشتركة.
أمثلة:
- تطبيق Python يعمل مع uWSGI و nginx. تستقبل عملية uWSGI الرئيسية الطلبات الواردة من nginx وتوزعها بين عمليات بايثون للمترجم الفوري الذي يعالج الطلبات. يمكن كتابة التطبيق على أي إطار متوافق مع uWSGI - Django ، Flask ، إلخ.
- يستخدم MySQL مجموعة مؤشرات ترابط: تتم معالجة كل اتصال جديد بواسطة أحد مؤشرات الترابط المجانية من التجمع. إذا لم تكن هناك سلاسل رسائل مجانية ، فسيقوم MySQL بإنشاء سلسلة رسائل جديدة. يتم تحديد حجم تجمع مؤشرات الترابط المجانية والحد الأقصى لعدد مؤشرات الترابط (اتصالات) بواسطة الإعدادات.
ربما يكون هذا أحد أكثر الطرق شيوعًا لبناء خدمات الشبكة ، إن لم يكن الأكثر شيوعًا. يسمح لك بالتوسع بشكل جيد ، والوصول إلى عدد كبير من الطلبات. القيد الرئيسي لهذا النهج هو عدد اتصالات الشبكة التي تتم معالجتها في وقت واحد. في الواقع ، هذا النهج يعمل بشكل جيد فقط إذا كانت الطلبات قصيرة أو قليلة من العملاء.
معالجة موجهة نحو الحدث (نمط المفاعل)
نموذجان - متزامن وغير متزامن - منافسين أبديين لبعضهما البعض. حتى الآن ، تمت مناقشة النهج المتزامنة فقط ، ولكن سيكون من الخطأ تجاهل النهج غير المتزامن. معالجة الطلب الموجه نحو الحدث أو التفاعل هي طريقة يتم فيها تنفيذ كل عملية إدخال / إخراج بشكل غير متزامن ، وفي نهاية العملية ، يتم استدعاء معالج. وكقاعدة عامة ، تتكون معالجة كل طلب من العديد من المكالمات غير المتزامنة تليها تنفيذ المعالجات. في أي لحظة معينة ، ينفّذ أحد التطبيقات ذات الترابط المفرد رمز معالج واحد فقط ، لكن تنفيذ معالجات الطلبات المختلفة يتناوب مع بعضها البعض ، مما يسمح لك بمعالجة العديد من الطلبات المتوازية (في نفس الوقت) بشكل متزامن.
مناقشة كاملة لهذا النهج هو خارج نطاق هذه المقالة. لإلقاء نظرة أعمق يمكنك أن توصي مفاعل (مفاعل) ، ما هو سر NodeJS السرعة؟ ، داخل NGINX . نحن هنا نقتصر على النظر في إيجابيات وسلبيات هذا النهج.
الايجابيات:
- التحجيم الفعال بواسطة rps وعدد الاتصالات المتزامنة. يمكن للخدمة التفاعلية معالجة عدد كبير من الاتصالات في وقت واحد (عشرات الآلاف) إذا كانت معظم الاتصالات في انتظار اكتمال الإدخال / الإخراج
سلبيات:
- تعقيد التنمية. البرمجة بأسلوب غير متزامن أصعب من البرمجة المتزامنة. منطق معالجة الطلب أكثر تعقيدًا ، وتصحيح الأخطاء هو أيضًا أكثر صعوبة منه في التعليمات البرمجية المتزامنة.
- الأخطاء التي تؤدي إلى حظر الخدمة بأكملها. إذا لم تكن اللغة أو وقت التشغيل مصممًا في الأصل للمعالجة غير المتزامنة ، فإن أي عملية متزامنة واحدة يمكن أن تمنع الخدمة بأكملها ، مما يلغي إمكانية القياس.
- من الصعب توسيع نطاق وحدة المعالجة المركزية الأساسية. هذا النهج يفترض وجود مؤشر ترابط واحد في عملية واحدة ، لذلك لا يمكنك استخدام النوى وحدة المعالجة المركزية متعددة في نفس الوقت. تجدر الإشارة إلى أن هناك طرق للتغلب على هذا القيد.
- النتيجة الطبيعية للفقرة السابقة: هذا النهج لا يتناسب بشكل جيد مع الطلبات التي تتطلب وحدة المعالجة المركزية. عدد rps لهذا النهج يتناسب عكسيا مع عدد عمليات وحدة المعالجة المركزية المطلوبة لمعالجة كل طلب. الطلب على وحدة المعالجة المركزية طلبات ينفي مزايا هذا النهج.
أمثلة:
- يستخدم Node.js نمط مفاعل خارج المربع. لمزيد من التفاصيل ، راجع ما سر سر NodeJS؟
- nginx: تستخدم العمليات المنفذة لـ nginx نمط المفاعل لمعالجة الطلبات بالتوازي. انظر داخل NGINX لمزيد من التفاصيل.
- برنامج C / C ++ الذي يستخدم أدوات OS مباشرة (epoll على نظام التشغيل Linux ، IOCP على windows ، kqueue على FreeBSD) ، أو يستخدم إطار العمل (libev ، libevent ، libuv ، إلخ).
نصف تزامن / نصف متزامن
الاسم مأخوذ من POSA: أنماط للكائنات المتزامنة والشبكات . في الأصل ، يتم تفسير هذا النمط على نطاق واسع للغاية ، لكن لأغراض هذا المقال ، سوف أفهم هذا النمط بشكل أكثر ضيقًا إلى حد ما. يعد تزامن نصف / تزامن نصف طريقة معالجة طلب يستخدم تدفق تحكم خفيفة الوزن (مؤشر ترابط أخضر) لكل طلب. يتكون البرنامج من مؤشر ترابط واحد أو أكثر على مستوى نظام التشغيل ، ومع ذلك ، يدعم نظام تنفيذ البرنامج الخيوط الخضراء التي لا يرى نظام التشغيل ولا يستطيع التحكم بها.
بعض الأمثلة لجعل النظر أكثر تحديداً:
- الخدمة في لغة الذهاب. تدعم لغة Go العديد من مؤشرات ترابط التنفيذ خفيفة الوزن - goroutine. يستخدم البرنامج واحدًا أو أكثر من سلاسل عمليات OS ، ولكن يعمل المبرمج مع goroutines ، والتي يتم توزيعها بشفافية بين مؤشرات ترابط OS من أجل استخدام وحدات المعالجة المركزية متعددة النواة
- خدمة بايثون مع مكتبة جيفنت. تتيح مكتبة gevent للمبرمج استخدام خيوط خضراء على مستوى المكتبة. يتم تنفيذ البرنامج بأكمله في موضوع واحد OS.
في جوهرها ، تم تصميم هذا النهج للجمع بين الأداء العالي للنهج غير المتزامن مع بساطة برمجة التعليمات البرمجية المتزامنة.
باستخدام هذا النهج ، على الرغم من وهم التزامن ، فإن البرنامج سيعمل بشكل غير متزامن: سيتحكم نظام تنفيذ البرنامج في حلقة الحدث ، وستكون كل عملية "متزامنة" غير متزامنة بالفعل. عند استدعاء هذه العملية ، سيقوم نظام التنفيذ باستدعاء العملية غير المتزامنة باستخدام أدوات نظام التشغيل وتسجيل معالج إتمام العملية. عند اكتمال العملية غير المتزامنة ، سيقوم نظام التنفيذ باستدعاء معالج مسجل سابقًا ، والذي سيستمر في تنفيذ البرنامج عند استدعاء العملية "المتزامنة".
نتيجة لذلك ، يحتوي نهج نصف التزامن / نصف المزامنة على بعض المزايا وبعض عيوب النهج غير المتزامن. حجم المقال لا يسمح لنا بالنظر في هذا النهج بالتفصيل. للمهتمين ، أنصحك بقراءة الفصل الذي يحمل نفس الاسم في كتاب POSA: أنماط الكائنات المتزامنة والشبكة .
تقدم طريقة نصف التزامن نصف المزامنة نفسها كيانًا جديدًا "للتيار الأخضر" - تدفق تحكم خفيف الوزن على مستوى البرنامج أو نظام تنفيذ المكتبة. ما يجب القيام به مع خيوط خضراء هو اختيار مبرمج. يمكنه استخدام مجموعة من الخيوط الخضراء ، كما يمكنه إنشاء مؤشر ترابط أخضر جديد لكل طلب جديد. الفرق مقارنةً بخيوط / عمليات نظام التشغيل هو أن الخيوط الخضراء أرخص بكثير: فهي تستهلك ذاكرة RAM أقل بكثير ويتم إنشاؤها بشكل أسرع. يتيح لك هذا إنشاء عدد كبير من الخيوط الخضراء ، على سبيل المثال ، مئات الآلاف في لغة Go. مثل هذه الكمية الضخمة تبرر استخدام نهج التدفق عند الطلب الأخضر.
الايجابيات:
- إنه مقياس جيدًا في عدد الثواني وعدد الاتصالات المتزامنة
- الرمز أسهل في الكتابة والتصحيح مقارنةً بالطريقة غير المتزامنة
سلبيات:
- نظرًا لأن تنفيذ العمليات غير متزامن بالفعل ، فإن أخطاء البرمجة تكون ممكنة عندما تقوم إحدى العمليات المتزامنة الفردية بحظر العملية بأكملها. يظهر هذا بشكل خاص باللغات التي يتم فيها تطبيق هذا النهج عن طريق مكتبة ، على سبيل المثال بيثون.
- عتامة البرنامج. عند استخدام مؤشرات الترابط أو عمليات OS ، تكون خوارزمية تنفيذ البرنامج واضحة: كل مؤشر ترابط / عملية ينفذ عمليات في التسلسل الذي تتم كتابته به في التعليمات البرمجية. باستخدام نهج نصف التزامن / نصف المزامنة ، يمكن للعمليات التي تتم كتابتها بالتتابع في التعليمات البرمجية أن تتناوب بشكل غير متوقع مع العمليات التي تعالج الطلبات المتزامنة.
- غير مناسب لأنظمة الوقت الفعلي. تؤدي المعالجة غير المتزامنة للطلبات إلى تعقيد كبير في توفير الضمانات لوقت المعالجة لكل طلب فردي. هذا هو نتيجة للفقرة السابقة.
اعتمادًا على التطبيق ، يتم توسيع نطاق هذه المقاربة جيدًا عبر نوى وحدة المعالجة المركزية (Golang) أو لا يتم توسيع نطاقها على الإطلاق (Python).
يسمح لك هذا الأسلوب ، بالإضافة إلى غير المتزامن ، بمعالجة عدد كبير من الاتصالات المتزامنة. لكن برمجة خدمة باستخدام هذا النهج أسهل ، لأن رمز مكتوب بأسلوب متزامن.
تجهيز ناقل
كما يوحي الاسم ، في هذا النهج ، تتم معالجة الطلبات بواسطة خط أنابيب. تتكون عملية المعالجة من العديد من سلاسل عمليات OS مرتبة في سلسلة. كل مؤشر ترابط هو رابط في السلسلة ؛ وهو ينفذ مجموعة فرعية معينة من العمليات اللازمة لمعالجة الطلب. يمر كل طلب بالتتابع عبر كافة الروابط الموجودة في السلسلة ، بينما تقوم الارتباطات المختلفة في كل لحظة من الوقت بمعالجة الطلبات المختلفة.
الايجابيات:
- هذا النهج المقاييس بشكل جيد في روبية. لمزيد من الروابط في السلسلة ، تتم معالجة المزيد من الطلبات في الثانية الواحدة.
- يتيح لك استخدام سلاسل عمليات متعددة إمكانية توسيع نطاق وحدات المعالجة المركزية بشكل جيد.
سلبيات:
- ليست كل فئات الاستعلام مناسبة لهذا النهج. على سبيل المثال ، سيكون تنظيم الاقتراع الطويل باستخدام هذا النهج أمرًا صعبًا وغير مريح.
- تعقيد التنفيذ وتصحيح الأخطاء. فاز معالجة متسلسلة بحيث الإنتاجية عالية يمكن أن يكون صعبا. تصحيح البرنامج الذي تتم فيه معالجة كل طلب بالتسلسل في عدة مؤشرات ترابط متوازية أكثر صعوبة من معالجة متسلسلة.
أمثلة:
- تم وصف مثال مثير للاهتمام لمعالجة الناقل في تقرير التحميل العالي 2018 تطور بنية نظام التداول والمقاصة في بورصة موسكو
يتم استخدام خطوط الأنابيب على نطاق واسع ، ولكن في أغلب الأحيان تكون الارتباطات مكونات فردية في عمليات مستقلة تتبادل الرسائل ، على سبيل المثال ، من خلال قائمة انتظار الرسائل أو قاعدة البيانات.
ملخص
ملخص موجز للنهج التي تم النظر فيها:
- معالجة متزامنة.
طريقة بسيطة ، ولكنها محدودة للغاية في قابلية التوسع ، سواء في rps أو في عدد الاتصالات المتزامنة. أنها لا تسمح باستخدام النوى وحدة المعالجة المركزية متعددة في وقت واحد. - عملية جديدة لكل طلب.
. , . . ( , ). - .
, , . , . - /.
/. . rps . . . - - (reactor ).
rps . - , . CPU - Half sync/half async.
rps . CPU (Golang) (Python). , () . reactor , , reactor . - .
, . (, long polling ).
, .
: ? , ?
المراجع
- :
- - :
- :
- Half sync/half async:
- :
- :