Runtime: Singleton HttpClient لا يحترم تغييرات DNS

تم إنشاؤها على ٢٩ أغسطس ٢٠١٦  ·  77تعليقات  ·  مصدر: dotnet/runtime

كما هو موضح في المنشور التالي: http://byterot.blogspot.co.uk/2016/07/singleton-httpclient-dns.html ، بمجرد أن تبدأ في الاحتفاظ بمثيل HttpClient لتحسين الأداء ، واجهت مشكلة حيث لا يحترم العميل تحديثات سجل DNS في حالة سيناريوهات تجاوز الفشل.

المشكلة الأساسية هي أن القيمة الافتراضية ConnectionLeaseTimeout تم ضبطها على -1 ، لانهائي. سيتم إغلاقها فقط عند التخلص من العميل ، وهو أمر غير فعال للغاية.

الإصلاح هو تحديث القيمة في نقطة الخدمة مثل هذا:

var sp = ServicePointManager.FindServicePoint(new Uri("http://foo.bar/baz/123?a=ab"));
sp.ConnectionLeaseTimeout = 60*1000; // 1 minute

لسوء الحظ ، لا توجد طريقة للقيام بذلك مع .NET Core اليوم.

يجب إحضار أي من ServicePointManager إلى .NET Core أو يجب تمكين وظيفة مماثلة مماثلة بطريقة أخرى.

area-System.Net.Http enhancement

التعليق الأكثر فائدة

هذه بالتأكيد قضية. يبدو أن الحل المقترح من darrelmiller يظهر عدم فهم

نستخدم Azure Traffic Managers لتقييم صحة مثيل. إنهم يعملون فوق DNS مع TTLs قصيرة. لا يعرف المضيف بطريقة سحرية أنه غير صحي ويبدأ في إصدار C onnection: إغلاق الرؤوس. يكتشف مدير المرور ببساطة الحالة غير الصحية ويعدل دقة DNS وفقًا لذلك. من خلال التصميم ، يكون هذا شفافًا تمامًا للعملاء والمضيفين ... كما هو الحال ، فإن التطبيق الذي يحتوي على HttpClient ثابت لحل DNS (دون علم) من قبل مدير المرور لن يتلقى أبدًا مضيفًا جديدًا عندما يصبح المضيف الذي تم حله مسبقًا غير صحي.

اعتبارًا من netcore 1.1 أبحث حاليًا عن حل لهذه المشكلة بالضبط. أنا لا أرى واحدة ، nativly على أي حال.

ال 77 كومينتر

لا أعتقد أن هذه هي نفس الملكية. هذه هي مهلة الاتصال ، وليس ConnectionLeaseTimeout.

كما هو موثق في https://msdn.microsoft.com/en-us/library/system.net.servicepoint.connectionleasetimeout.aspx ، يجب إسقاطه بشكل دوري في بعض السيناريوهات. ولكن لا توجد طريقة واضحة لتغيير السلوك على .NET Core.

onovotny نعم ، هذا شيء غريب يبدو أنه يفعل ارتباطًا صريحًا: الإغلاق بعد إطار زمني معين. لا يوجد سبب لعدم إمكانية تنفيذه كبرنامج وسيط إذا كنت تريد ذلك حقًا. إنه مجرد رأس HTTP.

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

onovotny ، لا توجد فئة ServicePointManager في .NET Core. هذا يبدو وكأنه مشكلة .NET Framework (سطح المكتب). الرجاء فتح مشكلة في UserVoice أو Connect.

onovotny المشكلة الأصلية ، كما أفهمها ، هي أنه على جانب الخادم ، يريد شخص ما تحديث إدخال DNS بحيث تنتقل جميع الطلبات المستقبلية لاستضافة A إلى عنوان IP الجديد. أفضل حل في رأيي هو عندما يتم تغيير إدخال DNS هذا ، يجب إخبار التطبيق الموجود على المضيف A بإرجاع C onnection: رأس onnection: close عند انتهاء صلاحية مهلة "التأجير".

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

هذه بالتأكيد قضية. يبدو أن الحل المقترح من darrelmiller يظهر عدم فهم

نستخدم Azure Traffic Managers لتقييم صحة مثيل. إنهم يعملون فوق DNS مع TTLs قصيرة. لا يعرف المضيف بطريقة سحرية أنه غير صحي ويبدأ في إصدار C onnection: إغلاق الرؤوس. يكتشف مدير المرور ببساطة الحالة غير الصحية ويعدل دقة DNS وفقًا لذلك. من خلال التصميم ، يكون هذا شفافًا تمامًا للعملاء والمضيفين ... كما هو الحال ، فإن التطبيق الذي يحتوي على HttpClient ثابت لحل DNS (دون علم) من قبل مدير المرور لن يتلقى أبدًا مضيفًا جديدًا عندما يصبح المضيف الذي تم حله مسبقًا غير صحي.

اعتبارًا من netcore 1.1 أبحث حاليًا عن حل لهذه المشكلة بالضبط. أنا لا أرى واحدة ، nativly على أي حال.

@ kudoz83 أنت محق ، المضيف لا يعرف بطريقة سحرية متى قام مدير المرور بتعديل دقة DNS ، ولهذا السبب قلت

عندما يتم تغيير إدخال DNS هذا ، يجب إخبار التطبيق الموجود على المضيف "أ"

إذا كنت لا تعتقد أنه من العملي إخطار خادم الأصل بأنه يجب أن يعيد c onnection: إغلاق الرؤوس ، فلا يزال أمامك عدد قليل من الخيارات:

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

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

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

يتم شرح Azure Traffic Manager هنا https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-monitoring

إنه يعمل على مستوى DNS ويتسم بالشفافية للعملاء والمضيفين - حسب التصميم. تعتبر مثيلات Azure التي تتواصل مع بعضها البعض عبر Traffic Manager لتحليل DNS في مأزق دون التمكن من تعيين TTL على تحديث DNS لـ HttpClient.

يبدو أن الطريقة التي يعمل بها HttpClient حاليًا تتعارض مع عروض خدمة Azure الخاصة بـ Microsoft - وهذا هو بيت القصيد. ناهيك عن أن أي خدمة مماثلة (EG Amazon Route 53) تعمل بنفس الطريقة تمامًا ، ولها نفس التبعية القصيرة لـ DNS TTL.

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

AFAIK ليس هناك طريقة لإخطار المضيف الفاشل أنه فشل؟

إذا لم يتمكن المضيف "الفاشل" من تنفيذ أي رمز ، فلن نحتاج إلى رمز حالة HTTP 503 لأن الخادم الأصلي لن يتمكن أبدًا من إعادته. هناك سيناريوهات قد لا يتمكن فيها المضيف الفاشل من معالجة إشعار ، ولكن في هذه الحالات ، من المحتمل ألا يحتفظ باتصال TCP / IP نشطًا مفتوحًا لفترة طويلة أيضًا.

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

أتفهم أن وضعك مختلف وأنه لا يمكنك الاعتماد على خادم أصلي قادر على إغلاق الاتصال بشكل موثوق. ما لست متأكدًا من فهمي له هو سبب حالتك ، لا يمكنك استخدام HttpMessageHandler لاكتشاف استجابات 5XX ، وإغلاق الاتصال وإعادة محاولة الطلب. أو حتى أبسط من ذلك ، ما عليك سوى إقناع خادم الويب الخاص بك بإرجاع c onnection: أغلق عندما يعرض رمز الحالة 5XX.

من الجدير بالذكر أيضًا أن السلوك الذي تشعر بالقلق ليس في HttpClient. إنه موجود في HttpHandler الأساسي أو حتى أقل منه ، وهناك عدد من التطبيقات المختلفة لـ HttpHandler قيد الاستخدام. في رأيي ، يتوافق السلوك الحالي مع الطريقة التي تم تصميم HTTP للعمل بها. أوافق على وجود تحد عند تحديث إعدادات DNS أثناء فتح الاتصالات ، لكن هذه ليست مشكلة .net. هذه مشكلة معمارية HTTP. هذا لا يعني أن .net لا تستطيع أن تفعل شيئًا لتقليل المشكلة.

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

آسف،

لم يكن يجب أن أكون قتالية كما بدوت بالأمس. كان يمر بيوم سيء.

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

@ kudoz83 لا تقلق ، لدينا جميعًا أيام من هذا القبيل :-)

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

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

في. net core على Windows ، تُترك إدارة اتصالات HTTP في الواقع لنظام التشغيل. أقرب ما تحصل عليه هو استدعاء Win32 API WinHttpOpen https://github.com/dotnet/corefx/blob/master/src/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs# L718 لا توجد واجهات برمجة تطبيقات عامة يمكنني العثور عليها للقيام بأي شيء باستخدام _sessionHandle. للحصول على نوع التغيير السلوكي الذي تبحث عنه ، سيتطلب الأمر من مستخدمي نظام التشغيل إجراء تغييرات. على الأقل هذا ما أفهمه.

ألن يكون من الأسهل الحصول على Azure Traffic Manager فقط لتعيين TTL منخفض جدًا على إدخالات DNS؟ إذا لم تكن مهتمًا بالاتصالات طويلة الأمد ، فيجب أن يقلل TTL المنخفض من فرصة إعداد اتصالات جديدة ضد خادم معطوب.

الجانب الإيجابي من طريقة إنشاء WinHttpHandler هو أننا نحصل على أشياء مثل HTTP / 2 مجانًا مع تحديث نظام التشغيل. الجانب السلبي هو أننا لا نحصل على قدر كبير من التحكم في التعليمات البرمجية المُدارة.

تضمين التغريدة

تم تنفيذ [ConnectionLeaseTimeout] في ServicePointManager ، وهو غير موجود في النواة.

يبدو أن ServicePoint.ConnectionLeaseTimeout يعود في .Net Standard 2.0 / .Net Core 1.2. (على الرغم من أنه ليس لدي أي فكرة عما إذا كانت اتصالات WinHttpHandler على سبيل المثال ستلتزم بها.)

أعتقد أن هناك بعض سوء الفهم هنا: لا علاقة لـ DNS TTLs تمامًا بعمر اتصال HTTP / TCP.

تقوم اتصالات HTTP الجديدة ببحث DNS والاتصال بعنوان المضيف الذي تم إرجاعه. يمكن إجراء طلبات HTTP متعددة عبر نفس الاتصال الفردي ولكن بمجرد فتح اتصال HTTP (واتصال TCP الأساسي) لا يقوم ببحث DNS مرة أخرى.

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

لا علاقة لتحديث DNS هذا بـ HttpClient ، والذي يستخدم فقط HttpClientHandler افتراضيًا (والذي يستخدم بحد ذاته مكدس مآخذ HttpWebRequest ) ويتم التعامل مع أي دقة DNS بواسطة هذا المكدس. ServicePointManager يدير ServicePoint الكائنات في أن كومة التي هي وصلات لمجموعة محددة. ServicePointManager لديها الحد الأدنى بعض التخزين المؤقت من جانب العميل من عمليات البحث DNS التي يمكنك قرص.

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

إذا كنت تريد إجراء بحث DNS آخر ، فأنت بحاجة إلى إعادة تعيين الاتصال على العميل. يمكنك فرض أقصى عمر لاتصال TCP ، أو إرسال رأس connection: close أو التخلص من HttpClient أو ServicePoint . يمكنك أيضًا إجراء تحليل DNS باستخدام Dns.GetHostAddresses واستخدام عنوان IP بدلاً من ذلك لطلبات HTTP الخاصة بك.

آمل أن يساعد ذلك ، إذا كنت خارج هذا ، فيرجى إبلاغي بذلك.

تضمين التغريدة

أعتقد أن هناك بعض سوء الفهم هنا: لا علاقة لـ DNS TTLs تمامًا بعمر اتصال HTTP / TCP.

نعم ، تعتبر TTLs الخاصة بـ DNS غير مرتبطة إلى حد ما ، ولكن ليس تمامًا.

تقوم اتصالات HTTP الجديدة ببحث DNS والاتصال بعنوان المضيف الذي تم إرجاعه.

نعم هذا صحيح. لكن Windows لديه ذاكرة تخزين DNS محلية تحترم TTL. إذا كان TTL مرتفعًا وقام خادم DNS بتغيير سجل DNS ، فسيتم فتح الاتصال الجديد مقابل عنوان IP القديم بسبب التخزين المؤقت للعميل لسجل DNS. مسح ذاكرة التخزين المؤقت DNS للعميل هو الحل الوحيد لهذا الذي أعرفه.

يمكن إجراء طلبات HTTP متعددة عبر نفس الاتصال الفردي ولكن بمجرد فتح اتصال HTTP (واتصال TCP الأساسي) لا يقوم ببحث DNS مرة أخرى.

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

لا علاقة لتحديث DNS هذا بـ HttpClient ، الذي يستخدم HttpClientHandler افتراضيًا (والذي يستخدم في حد ذاته مكدس مآخذ HttpWebRequest)

نعم و لا. في .Net core ، تمت إعادة كتابة HttpClientHandler ولم يعد يستخدم HttpWebRequest وبالتالي لا يستخدم ServicePointManager. ومن هنا سبب هذه القضية.

لقد ألقيت نظرة فاحصة على IIS ولا يبدو أن هناك طريقة للحصول على استجابات 5XX لتأتي مع اتصال c متقاربة . سيكون من الضروري تنفيذ HttpModule للقيام بهذا السحر.

بصفتك FYI ، إليك منشور ذي صلة يغطي هذه المشكلة وحلًا مؤقتًا. احذر من HttpClient

يجب إحضار أي من ServicePointManager إلى .NET Core

بينما قمنا بإحضار ServicePointManager و HttpWebRequest لتكافؤ النظام الأساسي ، إلا أنه لا يدعم معظم الوظائف في .Net Core نظرًا لأن المكدس الأساسي يتحول إلى WinHTTP أو Curl اللذين لا يعرضان مقابض التحكم المتقدمة.

يعد استخدام ServicePointManager للتحكم في HttpClient في الواقع أحد الآثار الجانبية لاستخدام HttpWebRequest ومكدس HTTP المُدار على NET Framework. نظرًا لاستخدام WinHttpHandler / CurlHandler في .Net Core ، لا يتحكم SPM في مثيلات HttpClient.

أو وظيفة مماثلة مماثلة يجب أن يتم تمكينها بطريقة أخرى.

إليك إجابة فريق WinHTTP:

  1. لأسباب أمنية ، بينما يستمر العميل في إرسال الطلبات و _ هناك اتصالات نشطة _ ، سيستمر WinHTTP في استخدام عنوان IP الوجهة. لا توجد طريقة لتحديد الوقت الذي تظل فيه هذه الاتصالات نشطة.
  2. إذا أغلق الخادم جميع الاتصالات بنقطة النهاية البعيدة ، فسيتم إجراء اتصالات جديدة بالاستعلام عن DNS وبالتالي باتجاه IP الجديد.

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

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

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

كما ذكرنا أعلاه ، إذا كنت تقصد بكلمة غير صحية أن الخادم يعرض رمز خطأ HTTP ويغلق اتصال TCP أثناء ملاحظة انتهاء صلاحية TTL لـ DNS ، فهذا بالفعل خطأ.

يرجى وصف السيناريو الخاص بك بمزيد من التفاصيل:

  1. أثناء تجاوز الفشل ، ما هي ذاكرة التخزين المؤقت DNS و TTL الخاصة بجهاز العميل. يمكنك استخدام ipconfig /showdns و nslookup -type=soa <domain_name> لمقارنة ما يعتقد الجهاز أن TTL هو TTL و TTL الموثوق به.
  2. هل هناك اتصالات نشطة مع الخادم البعيد؟ يمكنك استخدام netstat /a /n /b لمشاهدة الاتصالات والعمليات التي تمتلكها.
  3. سيساعدنا إنشاء repro كثيرًا: يرجى إرفاق أي معلومات متاحة مثل: إصدار NET Core / Framework ، ورمز العميل / الخادم ، وتتبع الشبكة ، و DNS LB / Traffic Manager عن بُعد ، وما إلى ذلك.

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

أو تخلص من ... الأساسي ServicePoint

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

تضمين التغريدة

NET Core 2.0 يعيد فئات ووظائف ServicePoint : https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepoint؟view=netcore-2.0

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

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

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

NET Core 2.0 يعيد فئات ووظائف ServicePoint: https://docs.microsoft.com/en-us/dotnet/api/system.net.servicepoint؟
يمكنك العودة إلى استخدام مهلة تأجير الاتصال لتعيين إطار زمني أقصى للاتصالات النشطة قبل إعادة تعيينها.

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

نسخة إلى : stephentoubgeoffkizer

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

لنفترض أن لدي مكتبة HTTP للأغراض العامة تستهدف العديد من الأنظمة الأساسية ، والتي لا تدعم جميعها ServicePointManager ، وأنا أحاول توفير سلوك يدير مثيلات HttpClient بذكاء ، وفقًا لأفضل الممارسات ، افتراضيًا. ليس لدي أي فكرة مسبقًا عن اسم المضيفين ، ناهيك عما إذا كانوا يتصرفون جيدًا فيما يتعلق بتغييرات DNS / اتصال C

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

  2. كيف يمكنني التعامل بشكل أكثر فاعلية مع مشكلة DNS هذه؟ التخلص من الحالات بعد 1 دقيقة؟ تعامل معها على أنها "غير مرجحة للغاية" ولا تقدم أي سلوك تخلص افتراضي؟

(ليس موقفًا افتراضيًا بالمناسبة ؛ أنا أتصارع مع هذه الأسئلة بالضبط في الوقت الحالي.)

شكرا!

لن تتم دعوتي حتى إلى تجارب فريق الأحلام ، لكن لدي فكرة واحدة تتعلق بتعليقك الفردي HttpClient . أولاً ، يمكنك دائمًا استخدام طريقة SendAsync لتحديد رؤوس وعناوين مختلفة ، لذا يمكنك التفاف ذلك مع فصلك الذي يوفر بيانات مشتركة مشابهة لـ HttpClient (مثل العناوين الافتراضية ، العنوان الأساسي) حتى الآن ينتهي الأمر بالاتصال بنفس العميل الفردي. ولكن الأفضل من ذلك ، يمكنك إنشاء عدة مثيلات HttpClient يشتركون جميعًا في نفس HttpClientHandler : https://github.com/dotnet/corefx/issues/5811.

بالنسبة لقضية DNS ، يبدو أن الإجماع هنا هو:

لإجبار العملاء على عنوان IP التالي ، فإن الحل الوحيد القابل للتطبيق هو التأكد من أن الخادم يرفض الاتصالات الجديدة ويغلق الاتصالات الحالية

إذا لم يكن هذا قابلاً للتطبيق بالنسبة لك ، فقد اقترح داريل ميلر بعض الخيارات الإضافية هنا: https://github.com/dotnet/corefx/issues/11224#issuecomment -270498159.

ohadschn شكرًا ، وآمل ألا

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

بالنسبة لي ، فإن الميزة الأكثر وضوحًا لمشاركة نفس HttpClient [ Handler ] هي البساطة. لن تضطر إلى الاحتفاظ بأشياء مثل التعيين بين المضيفين والعملاء. لن أعرف شيئًا عن TIME_WAIT ، حقًا ليس خبرتي أيضًا.

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

في حين أن الإجابات المقدمة التي تحدد ما يجب أن يحدث على جانب الخادم تكون دقيقة بالنسبة لعالم مثالي ، إلا أن المطورين في العالم الحقيقي لا يتحكمون غالبًا في المكدس الكامل من جانب الخادم ، الذي يتواصلون معه. في هذا الصدد ، أحب حقًا مفهوم ConnectionLeaseTimeout ، لأنه تنازل عن حقائق الحياة اليومية لجون وجين دوفوربر.
اقترح أحدهم كتابة برمجيات وسيطة لفرض مثل هذه المهلة على .NET Core. هل سيعتمد هذا الفصل على NodaTime و System.Collections. غير قابل للتغيير يقوم بهذه المهمة؟

    public class ConnectionLeaseTimeoutHandler : DelegatingHandler
    {
        private static string GetConnectionKey(Uri requestUri) => $"{requestUri.Scheme}://{requestUri.Host}:{requestUri.Port}";

        private readonly IClock clock;
        private readonly Duration leaseTimeout;
        private ImmutableDictionary<string, Instant> connectionLeases = ImmutableDictionary<string, Instant>.Empty;

        public ConnectionLeaseTimeoutHandler(HttpMessageHandler innerHandler, IClock clock, Duration leaseTimeout)
            : base(innerHandler)
        {
            this.clock = clock;
            this.leaseTimeout = leaseTimeout;
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            string key = GetConnectionKey(request.RequestUri);
            Instant now = clock.GetCurrentInstant();

            Instant leaseStart = ImmutableInterlocked.GetOrAdd(ref connectionLeases, key, now);

            if (now - leaseStart > leaseTimeout)
            {
                request.Headers.ConnectionClose = true;
                ImmutableInterlocked.TryRemove(ref connectionLeases, key, out leaseStart);
            }

            return base.SendAsync(request, cancellationToken);
        }
    }

snboisen أعتقد أن هذا يبدو صحيحًا ولكن لا

بالنسبة لي ، السؤال الأكبر هو ما إذا كان إرسال رأس Connection: close هو حل قابل للتطبيق. يجدر بنا أن نكرر هنا ما قاله darrelmiller في تعليقات منشور المدونة الذي دفع هذا الموضوع:

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

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

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

tmds لم

snboisen هل تقول إن AWS وموفري الخدمات السحابية الآخرين (

tmds بالنسبة إلى AWS ، نعم ، على الأقل لتجاوز الفشل: https://aws.amazon.com/route53/faqs/#adjust_ttl_to_use_failover
لا أعرف عن موفري الخدمات السحابية الآخرين ، ولكن يبدو أن البعض يفعل ذلك أيضًا.

tmds بالنسبة إلى AWS ، نعم ، على الأقل لتجاوز الفشل: https://aws.amazon.com/route53/faqs/#adjust_ttl_to_use_failover
لا أعرف عن موفري الخدمات السحابية الآخرين ، ولكن يبدو أن البعض يفعل ذلك أيضًا.

هناك نوعان من السيناريوهين الإشكاليين هنا:

  • العميل متصل بخادم لم يعد موجودًا
  • العميل متصل بخادم يقوم الآن بتشغيل إصدار قديم من البرنامج

يرتبط فشل DNS بالملف الأول. من المناسب إزالة الخوادم التي يتعذر الوصول إليها من DNS (في AWS ، Azure ، ...).
الطريقة الصحيحة لاكتشافها لدى العميل هي آلية المهلة. لست متأكدًا من وجود مثل هذه الخاصية على HttpClient (مهلة الرد القصوى على اتصال قائم).
على مستوى البروتوكول ، تحدد بروتوكولات websocket و http2 الأحدث رسائل ping / pong للتحقق من فعالية الاتصال.

عندما أقترح فتح مشكلة مع Azure ، فهي للسيناريو الثاني.
لا يوجد سبب يدعو العميل إلى إغلاق اتصال يعمل. إذا لم يعد الخادم مناسبًا ، فيجب فصل العملاء ويجب جعل الخادم غير قابل للوصول.
لقد وجدت مستندًا رائعًا حول عمليات نشر AWS Blue / Green: https://d0.awsstatic.com/whitepapers/AWS_Blue_Green_Deployments.pdf.
يسرد العديد من التقنيات. بالنسبة لأولئك الذين يستخدمون DNS فإنه يذكر _تعقيدات DNS TTL_. بالنسبة لأولئك الذين يستخدمون موازن التحميل _ لا تعقيدات DNS_.

tmds شكرًا على الرابط ، هذا مثير جدًا للاهتمام.

لا أتساءل عن مدى شيوع الاعتماد على DNS TTL مقابل استخدام موازن التحميل. يبدو أن هذا الأخير حل أكثر موثوقية بشكل عام.

تعرضت لبعض السلوك المماثل عند العمل مع تطبيقين مختلفين من تطبيقات API في خدمات تطبيقات Azure التي تم الاتصال بها عبر HttpClient . لقد لاحظنا حوالي 250 طلبًا في اختبارات التحميل الخاصة بنا ، وبدأنا في الحصول على مهلات و "تعذر إنشاء اتصال" HttpRequestException - لا يهم ما إذا كان المستخدمون متزامنون أو طلبات متسلسلة.

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

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

لا يتعلق الأمر بالضرورة بالأداء ، بل يتعلق بعدم تسريب اتصالات TCP والحصول على SocketException s.

من MSDN :

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

راجع أيضًا https://aspnetmonsters.com/2016/2016-08-27-httpclientwrong/

khellang شكرًا على الرابط (والتوضيح على SocketException s ، كان لدي بالتأكيد سوء فهم هناك) - لقد صادفت هذا المنشور و 3 أو 4 منشورات أخرى تحدد هذا الشيء نفسه بالضبط.

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

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

يبدو وكأنه فوضى لشيء ما

المقصود أن يتم إنشاء مثيل له مرة واحدة وإعادة استخدامه طوال عمر التطبيق

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

snboisen لقد اختبرت ConnectionLeaseTimeoutHandler ووجدت أنه لا يعمل مع اتصالات متعددة. يتم إصدار "إغلاق" لاتصال واحد فقط في كل مرة تحدث فيها مهلة التأجير ، ولكن قد يكون هناك عدة اتصالات مفتوحة مع مثيل HttpClient واحد عند إرسال الطلبات بالتوازي. من ما أراه في fiddler (أستخدم عنوان IP سيئًا لإنشاء أخطاء للتحقق من مفتاح DNS) بعد إرسال "الإغلاق" ، تستخدم بعض الطلبات عنوان IP الجديد وتستخدم بعض الطلبات عنوان IP القديم. في حالتي ، لدي حد اتصال يبلغ 2 ويستغرق الأمر عدة تكرارات من مهلة تأجير الاتصال لتحديث كلا الاتصالين. من الواضح أنه سيكون أسوأ بكثير مع المزيد من الاتصالات المتزامنة من خادم الإنتاج ، ولكن من المحتمل أن يتم التبديل في النهاية بعد مرور بعض الوقت.

لا أعرف طريقة لإصدار "إغلاق" لكل اتصال فردي قيد الاستخدام بواسطة مثيل HttpClient. سيكون هذا مثاليًا بالتأكيد ، ولكن ما سأفعله هو استخدام طريقة المصنع GetOrCreate () لـ HttpClient وإنشاء مثيل HttpClient جديد كل 120 ثانية لضمان إنشاء جميع الاتصالات الجديدة. لست متأكدًا من كيفية التخلص من مثيل HttpClient القديم بمجرد الانتهاء من جميع الطلبات لإغلاق الاتصالات ، لكنني أعتقد أن .NET يعتني بذلك لأنه لم يكن أبدًا مشكلة في إنشاء مثيل HttpClient جديد لكل طلب.

كملاحظة جانبية ، أعتقد أن التحديث يجب أن يتم على العميل. لا يمكن أن يكون الخادم مسؤولاً عن توصيل تغييرات DNS أو أي برامج وسيطة. الغرض من DNS هو تعويض هذه المسؤولية حتى تتمكن من تغيير IP في أي وقت بدون تنسيق بين العميل والخادم وليس فقط لتوفير اسم مألوف لعنوان IP. حالة الاستخدام المثالية هي عنوان AWS Elastic IP. ينعكس التغيير فقط في DNS. لن تعرف AWS كيفية إرسال رؤوس "قريبة" من خادم الويب الخاص بك الذي يعمل على مثيل ec2. لن تكون AWS على دراية بكل خادم ويب يجلس فوق مثيل ec2 يديره. السيناريو الخاص بالخادم القديم الذي لا يرسل عبر رأس "مغلق" هو ​​عمليات نشر خادم جديدة حيث يتم نشر نفس البرنامج بالضبط على خادم جديد مع تحويل جميع حركة المرور بواسطة DNS. يجب ألا يتغير أي شيء على الخادم القديم ، خاصة إذا كان عليك العودة مرة أخرى. يجب تغيير كل شيء بسلاسة في مكان واحد باستخدام DNS.

بغض النظر عن المشكلات الأكبر التي تمت مناقشتها هنا ، هل تم تنفيذ ConnectionLeaseTimeout الآن بشكل أساسي؟ وإذا كان الأمر كذلك ، فلماذا لم يتم إغلاق هذه القضية؟ تمكنت من ترميز مثال تمامًا مثل المنشور الأصلي بدون مشاكل الآن. سواء كان ذلك يحل مشكلات DNS الخاصة بالاتصال أم لا ، فإنه _seems_ ConnectionLeaseTimeout _is_ تم تنفيذه في الأساس.

لم يتم تنفيذ ServicePointMananager.ConnectionLeaseTimeout في .NET Core. يعد استخدام هذه الخاصية في .NET Core أمرًا محظورًا. إنه يعمل فقط في .NET Framework. وبشكل افتراضي ، يتم تعيين هذه الخاصية على "إيقاف التشغيل" في .NET Framework.

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

لقد نجحنا في معالجة مشكلة استنفاد المقبس من خلال تغليف HttpClient في واجهة برمجة تطبيقات مخصصة تسمح لكل طلب http في تطبيق ما بإعادة استخدام مثيل HttpClient (إنه يفعل أكثر من هذا فقط ، مثل RestSharp لكن هذه إحدى الفوائد أيضًا). يتم استرداد هذا خلف lock{} لأننا نقوم كل 60 دقيقة بإنشاء HttpClient و إعادته بدلاً من ذلك. لقد سمح لنا ذلك بإجراء طلبات http كبيرة الحجم من تطبيق الويب الخاص بنا (بسبب عمليات الدمج المكثفة التي لدينا) مع عدم إعادة استخدام الاتصالات القديمة التي لم يتم إغلاقها. لقد كنا نقوم بذلك لمدة عام تقريبًا بنجاح (بعد أن أصابنا مشكلات استنفاد المقبس).

أنا متأكد من أنه لا يزال هناك تأثير ضمني على الأداء في هذا (خاصة بسبب كل عمليات القفل) ولكنه أفضل من كل شيء يموت بسبب استنفاد المقبس.

KallDrexx لماذا تحتاج إلى قفل المثيل "العام"؟ بسذاجة كنت أقوم بتخزينه في حالة ثابتة واستبدله كل 60 دقيقة بآخر جديد. ألن يكون ذلك كافيا؟

كودنا للحصول على HttpClient هو:

ج #
var timeSinceCreated = DateTime.UtcNow - _lastCreatedAt ؛
إذا (timeSinceCreated.TotalSeconds> SecondsToRecreateClient)
{
قفل (قفل)
{
timeSinceCreated = DateTime.UtcNow - _lastCreatedAt ؛
إذا (timeSinceCreated.TotalSeconds> SecondsToRecreateClient)
{
_currentClient = new HttpClient () ،
_lastCreatedAt = DateTime.UtcNow ،
}
}
}

        return _currentClient;

""

لذلك أعتقد أن القفل يحدث مرة واحدة فقط في الدقيقة بحيث لا تحاول سلاسل رسائل متعددة إنشاء HttpApiClient وقت واحد. اعتقدت أننا كنا نغلق بقوة أكبر.

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

أرى ذلك سبب ملائم.

لا أعرف ما إذا كنت سأصنفه على أنه وسيلة راحة.

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

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

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

هناك الكثير من الأشياء المجهولة وتعقيد إضافي للمخاطرة بفعل ذلك في الإنتاج.

تضمين التغريدة

  • يبدو أن ReaderWriterLockSlim سيكون أكثر ملاءمة لاستخدامك.
  • يجب أن يكون التعيين DateTime ذريًا إذا كنت تقوم بتشغيل x64 صحيحًا (لأنه يحتوي على حقل واحد ulong ). لاحظ أن الكود الحالي الخاص بك ليس آمنًا لمؤشر الترابط إذا لم يكن الأمر كذلك ، لأنك تراقب قيمة DateTime خارج القفل.
  • لن يتطلب النهج المستند إلى المؤقت الذي اقترحه karelz DateTime على الإطلاق ... سيقوم المؤقت ببساطة بتبديل HttpClient . ستظل بحاجة إلى إحاطة الحقل HttpClient ببعض حواجز الذاكرة على الرغم من ( volatile ، Interlocked.Exchange إلخ).

يبدو أن ReaderWriterLockSlim سيكون أكثر ملاءمة لاستخدامك.

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

لن يتطلب النهج المستند إلى جهاز ضبط الوقت الذي اقترحه

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

شكرا.

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

أتساءل عما إذا كانت لا تزال مشكلة في .net core 2.0؟ هل ما زلنا بحاجة إلى القلق بشأن تغيير DNS؟

أتساءل عما إذا كانت لا تزال مشكلة في .net core 2.0؟ هل ما زلنا بحاجة إلى القلق بشأن تغيير DNS؟

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

KallDrexx ، فهل هذا يعني أنه سيظل

withinoneyear من فهمي نعم. إذا أنشأت HttpClient واستخدمته مقابل الإنتاج الأخضر ، فتبادل الإنتاج إلى اللون الأزرق ، فسيظل اتصال HttpClient مفتوحًا مع Green حتى يتم إغلاق الاتصال.

أعلم أن هذا قديم ، لكنني أعتقد أنه لا يجب عليك استخدام DateTime.UtcNow لقياس الفاصل الزمني. استخدم مصدر وقت monitonic مثل Stopwatch.GetTimestamp. بهذه الطريقة تكون محصنًا من تعديل التوقيت المحلي بواسطة المشغل أو مزامنة الوقت. كانت هناك بعض شرائح عربات التي تجرها الدواب التي جعلت قيم QPC تعود ، لكنني لا أعتقد أن الكثير منها قيد الاستخدام الآن.

var sp = ServicePointManager.FindServicePoint (Uri الجديد ("http://foo.bar/baz/123؟a=ab")) ؛
sp.ConnectionLeaseTimeout = 60 * 1000 ؛ // 1 دقيقة

يتم وضع هذا الرمز في المنشئ؟

almuthashiAlmajlliss هههههههههههههههههههههههه إذا كنت HttpClient منفردًا وقمت بالوصول إلى نقاط متعددة ، فلن يكون المنشئ هو المكان الصحيح لوضعه.
تحقق من هذا التنفيذ . يوجد أيضًا في README الخاص بالمشروع رابط إلى منشور مدونة يشرح المشكلة. هذا المقال يشير أيضا إلى هذا الموضوع.

هل يمكن لأي شخص مساعدتي في فهم ما يعنيه ConnectionLeaseTimeout بالضبط؟

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

أرى الناس يتحدثون عن تحديث DNS في النهاية الخلفية؟ في تطبيق Azure Web القياسي ، هل سيؤدي نشر ASP.NET الخلفي الخاص بي إلى تحديث DNS؟

ألن تترك مهلة دقيقة واحدة نافذة يحتمل أن يتم فيها تحديث نظام أسماء النطاقات حتى الآن لم تحدث المهلة بعد؟

تعديل. إدراك أن هذا لا يعمل في .NET Standard 2.0. ما هو العمل حول؟

في انتظار ذلك https://www.stevejgordon.co.uk/introduction-to-httpclientfactory-aspnetcore أو تنفيذ أجزاء منه بنفسك.

تغيير ConnectionLeaseTimeout لم يعمل على Xamarin مع .netstandard 2.0 !!!

paradisehuman أفترض أنك تعني ServicePoint.ConnectionLeaseTimeout . AFAIK لا يعمل سواء على .NET Core. في .NET Core 2.1 قدمنا SocketsHttpHandler.PooledConnectionLifetime . كما أن HttpClientFactory في ASP.NET يمكنه الاستفادة من كليهما ويفعل المزيد من أجلك.
لدى Mono / Xamarin تطبيق مكدس الشبكات الخاص به (لا يستهلكان رمز مصدر CoreFX للشبكات) - لذلك سيكون من الأفضل تسجيل الخطأ في الريبو بمزيد من التفاصيل.

لسوء الحظ ، لا توجد طريقة للقيام بذلك مع .NET Core اليوم. يجب إحضار أي من ServicePointManager إلى .NET Core أو يجب تمكين وظيفة مماثلة مماثلة بطريقة أخرى.

onovotny ، يكشف SocketsHttpHandler في .NET Core 2.1 عن PooledConnectionLifetime ، الذي يخدم غرضًا مشابهًا لـ ConnectionLeaseTimeout ، فقط على مستوى المعالج. هل يمكننا النظر في هذه المسألة التي تم تناولها في هذه المرحلة؟

stephentoub فقط عند رؤية هذا الآن ، نعم ، أعتقد أن على PooledConnectionLifetime معالجته. يمكن للمجتمع فتح مشكلة أخرى إذا كانت هناك حاجة إلى شيء ما.

onovotnykarelzstephentoub،

هل توافقون جميعًا على أن هذا ملخص دقيق لأفضل السبل لحل مشكلة HttpClient / DNS الأصلية المفردة؟

  • في .NET Framework 2.0+ ، استخدم ServicePoint.ConnectionLeaseTimeout .

  • في .NET Core 2.1 ، استخدم SocketsHttpHandler.PooledConnectionLifetime .

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

بينما أستمر في تعلم الأشياء من هذا الموضوع وغيره (مثل ConnectionLeaseTimeout لا يعمل بشكل موثوق عبر الأنظمة الأساسية في .NET Standard 2.0) ، عدت إلى لوحة الرسم في محاولة لحل هذا من مكتبة بطريقة ما يعمل على أكبر عدد ممكن من الأنظمة الأساسية / الإصدارات. استنشاق المنصة أمر جيد. لا بأس بالتخلص من / إعادة إنشاء HttpClient بشكل دوري ، إذا كان ذلك فعالاً. أنا متأكد تمامًا من أنني أخطأت في محاولتي الأولى ، والتي كانت ببساطة إرسال رأس connection:close إلى المضيف على فترات منتظمة. شكرا مقدما على أي نصيحة!

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

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

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

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

tmenier أنت لا تريد إعادة استخدام المثيلات كل HttpClient مكالمة ، حيث سيؤدي ذلك إلى استنفاد مقبس tcp. يجب إدارة إعادة التدوير (انتهاء المهلة أو الحفاظ على تجمع HttpClient s التي يمكن أن تنتهي صلاحيتها.

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

آه آسف أساء فهم ما كنت تعنيه بإعادة التدوير.

لا يجب عليك التخلص من القديم. دع GC يجمعهم.
يجب أن يكون الكود بسيطًا مثل إعداد سينغلتون "زائف" جديد بشكل دوري على أساس المؤقت. لا شيء آخر.

لقد اكتشفت أن عدم التخلص منها يمكن أن يؤدي إلى تباطؤ نظرًا لنفاد اتصالات http في سيناريوهات الأداء العالي.

tmenier حول استخدام SocketsHttpHandler.PooledConnectionLifetime في .NET Core 2.1 ، إنشاء HttpClientHandler مغلف بالكامل في https://github.com/dotnet/wcf/blob/master/src/System.Private.ServiceModel/src/System/ ServiceModel / Channels / HttpChannelFactory.cs. هل هناك طريقة للقيام بذلك عند استخدام عميل WCF؟

edavedian أقترح أن أسأل على dotnet / wcf repo. تضمين التغريدة

يتحول المكدس الأساسي إلى WinHTTP أو Curl اللذين لا يعرضان مقابض التحكم المتقدمة

هل يوجد في .Net Core عميل HTTP يعمل عبر المقابس؟

هل يوجد في .Net Core عميل HTTP يعمل عبر المقابس؟

نعم ، SocketsHttpHandler ، واعتبارًا من 2.1 يكون الإعداد الافتراضي.

هل يضرب HttpClient Cache URIs ، على نحو مشابه لما يفعله RestClient على ما أعتقد؟ إذا كان الأمر كذلك ، فيرجى إبلاغي بأي إصدار (.NET Core 3.0 / .NET Framework 3.0 وما إلى ذلك) يدعم هذا الإصدار.

أرى أن التخزين المؤقت يتم فقط في RestClient إذا كان المشروع عبارة عن تطبيق .Net Core 2.1+؟

هل يقوم HttpClient بتخزين URIs ، بشكل مشابه لما يفعله RestClient على ما أعتقد؟

لا يقوم HttpClient بأي تخزين مؤقت.

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

scalablecory أعتقد أن ديفيد استجاب بما كان يدور في خلدي. شكرا!

انتهيت للتو من قراءة هذا الموضوع ، ويبدو أن هناك حالة استخدام لم يتم تناولها.

عند استخدام HttpClientFactory ، فسيقوم HttpClient s الناتج تلقائيًا بإغلاق الاتصالات وإجراء بحث جديد عن DNS عندما يتلقون HttpRequestException مع SocketException داخلي يشير إلى أن لم يعد المضيف صالحًا ومن المحتمل أن يكون DNS قد تغير (رمز الخطأ 11001 - لم يعد هذا المضيف معروفًا)؟

إذا لم يكن كذلك، فما هو الحل لجعل HttpClient تنفيذ عمليات البحث DNS قبل انتهاء صلاحية TTL في سجلات DNS؟

أنا أستخدم حاليًا HttpClientFactory مع HttpMessageHandler مخصص (تم تكوينه عن طريق إدخال التبعية باستخدام AddHttpClient<T, U>().ConfigurePrimaryHttpMessageHandler(...) ) وعندما يتغير سجل DNS قبل انتهاء صلاحية TTL ، فإنه يخرج من الخطأ. على وجه التحديد ، أرى أنه يحدث عند إجراء مجموعة من التحميلات على Azure Blob Storage.

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات

القضايا ذات الصلة

jzabroski picture jzabroski  ·  3تعليقات

jamesqo picture jamesqo  ·  3تعليقات

bencz picture bencz  ·  3تعليقات

btecu picture btecu  ·  3تعليقات

GitAntoinee picture GitAntoinee  ·  3تعليقات