خادم مقبس C++ - غير قادر على تشبع وحدة المعالجة المركزية

StackOverflow https://stackoverflow.com/questions/1234750

سؤال

لقد قمت بتطوير خادم HTTP صغير في C++، باستخدام Boost::asio، والآن أقوم باختباره مع العديد من العملاء ولم أتمكن من الاقتراب من تشبع وحدة المعالجة المركزية.أقوم بالاختبار على مثيل Amazon EC2، وأحصل على حوالي 50% من استخدام وحدة المعالجة المركزية الواحدة، و20% من وحدة المعالجة المركزية الأخرى، والاثنتين المتبقيتين في وضع الخمول (وفقًا لـ htop).

تفاصيل:

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

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

الأفكار التي كانت لدي:

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

المحلول

Boost::asio ليس صديقًا لسلسلة الرسائل كما كنت تأمل - يوجد قفل كبير حول رمز epoll في Boost/asio/detail/epoll_reactor.hpp مما يعني أنه يمكن لخيط واحد فقط الاتصال بنظام epoll الخاص بـ kernel في المرة الواحدة .وبالنسبة للطلبات الصغيرة جدًا، يُحدث هذا فرقًا كبيرًا (بمعنى أنك لن ترى سوى أداء خيط واحد تقريبًا).

لاحظ أن هذا يمثل قيدًا على كيفية استخدام Boost::asio لمرافق Linux kernel، وليس بالضرورة نواة Linux نفسها.يدعم epoll syscall سلاسل رسائل متعددة عند استخدام الأحداث التي يتم تشغيلها بواسطة الحافة، ولكن الحصول عليها بشكل صحيح (بدون قفل مفرط) قد يكون أمرًا صعبًا للغاية.

راجع للشغل، لقد قمت ببعض الأعمال في هذا المجال (الجمع بين حلقة حدث epoll متعددة العمليات التي يتم تشغيلها بواسطة الحافة مع الخيوط/الألياف المجدولة من قبل المستخدم) وجعلت بعض التعليمات البرمجية متاحة ضمن nginetd مشروع.

نصائح أخرى

بما أنك تستخدم EC2، فإن كل الرهانات ملغاة.

جرب ذلك باستخدام أجهزة حقيقية، ومن ثم قد تتمكن من رؤية ما يحدث.إن محاولة إجراء اختبار الأداء في الأجهزة الافتراضية أمر مستحيل في الأساس.

لم أتوصل بعد إلى ما هو مفيد لـ EC2، إذا اكتشف شخص ما ذلك، فيرجى إبلاغي به.

من تعليقاتك على استخدام الشبكة،
لا يبدو أن لديك الكثير من حركة الشبكة.

3 + 2.5 MiB/sec هو حول 50Mbps ball-park (مقارنة بمنفذ 1 جيجابت في الثانية لديك).

أود أن أقول أنك تواجه إحدى المشكلتين التاليتين،

  1. عبء عمل غير كافٍ (معدل طلب منخفض من عملائك)
    • الحظر في الخادم (إنشاء الاستجابة المتداخلة)

انظر الى cmeerwملاحظات وأرقام استخدام وحدة المعالجة المركزية الخاصة بك
(تسكع في 50% + 20% + 0% + 0%)
يبدو على الأرجح وجود قيود في تنفيذ الخادم الخاص بك.
أنا الثانية cmeerwالجواب (+1).

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

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

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

لما يستحق.يمكن أن يؤدي استخدام مكالمات مأخذ التوصيل الأولية على HTTP المخصص الخاص بي إلى تقديم 800 ألف طلب ديناميكي في الثانية باستخدام معالج I7 رباعي النواة.إنه يخدم من ذاكرة الوصول العشوائي (RAM)، وهو المكان الذي يجب أن تكون فيه لتحقيق هذا المستوى من الأداء.في هذا المستوى من الأداء، يستهلك برنامج تشغيل الشبكة ونظام التشغيل حوالي 40% من وحدة المعالجة المركزية.باستخدام ASIO يمكنني الحصول على حوالي 50 إلى 100 ألف طلب في الثانية، وأدائه متغير تمامًا ومقيد في الغالب في تطبيقي.يشرح منشور @cmeerw السبب في الغالب.

إحدى طرق تحسين الأداء هي تنفيذ وكيل UDP.من خلال اعتراض طلبات HTTP ثم توجيهها عبر UDP إلى خادم UDP-HTTP الخلفي، يمكنك تجاوز الكثير من حمل TCP في مكدسات نظام التشغيل.يمكنك أيضًا الحصول على واجهات أمامية تمر عبر UDP نفسها، وهو ما لا ينبغي أن يكون من الصعب جدًا القيام به بنفسك.تتمثل ميزة وكيل HTTP-UDP في أنه يسمح لك باستخدام أي واجهة أمامية جيدة دون تعديل، ويمكنك تبديلها حسب الرغبة دون أي تأثير.كل ما تحتاجه هو بضعة خوادم إضافية لتنفيذه.أدى هذا التعديل على المثال الخاص بي إلى خفض استخدام وحدة المعالجة المركزية لنظام التشغيل إلى 10%، مما أدى إلى زيادة طلباتي في الثانية إلى ما يزيد قليلاً عن مليون على تلك الواجهة الخلفية الفردية.وFWIW يجب أن يكون لديك دائمًا إعداد للواجهة الأمامية لأي موقع فعال لأن الواجهات الأمامية يمكنها تخزين البيانات مؤقتًا دون إبطاء الواجهة الخلفية للطلبات الديناميكية الأكثر أهمية.

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

نأمل أن يكون بعض هذا مفيدًا لك.

كم عدد مثيلات io_service لديك؟Boost asio لديه مثال يقوم بإنشاء خدمة io_service لكل وحدة المعالجة المركزية واستخدامها بطريقة RoundRobin.

لا يزال بإمكانك إنشاء أربعة سلاسل رسائل وتعيين واحدة لكل وحدة معالجة مركزية، ولكن يمكن لكل سلسلة رسائل الاستقصاء على io_service الخاص بها.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top