Aspnetcore: BadHttpRequestException: انتهت مهلة قراءة نص الطلب نظرًا لوصول البيانات ببطء شديد

تم إنشاؤها على ١٦ أكتوبر ٢٠١٨  ·  129تعليقات  ·  مصدر: dotnet/aspnetcore

لدينا تطبيق asp.net core 2.1 يعمل على .net 4.7 في خدمة تطبيقات الويب azure.

بدأنا مؤخرًا في الحصول على الكثير من الأخطاء التالية:

Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: انتهت مهلة قراءة نص الطلب بسبب وصول البيانات ببطء شديد. راجع MinRequestBodyDataRate.

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

اعتدنا التشغيل على asp.net core 2.0 / .net 4.6.1 لعدة أشهر ولم نر هذا الخطأ من قبل.
يبدو أنه بدأ يحدث بعد الترقية الأخيرة إلى asp.net core 2.1 / .net 4.7.

نود الوصول إلى جوهر هذه المشكلة ، لكننا لسنا متأكدين من أين نبدأ.
أي أفكار؟

affected-medium area-servers enhancement servers-kestrel severity-nice-to-have

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

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

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

سيكون من الرائع أن يقوم فريق asp.net الأساسي بإنشاء اختبار إجهاد تصاعدي على تطبيق ويب بسيط لتأكيد ما إذا كان هناك بالفعل عنق زجاجة على مستوى مجموعة الخيوط ، أو في أي مكان آخر.

ال 129 كومينتر

sebastienros هل قمت بإعداد موقع wiki

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

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

هل لديك أي سجلات أخرى من Kestrel؟

لا توجد تحذيرات / أخطاء أخرى. ربما مستوى المعلومات ولكني لا أصر على ذلك ، على الرغم من وجود طريقة للحصول عليها.

هل يمكنك التقاط ملف تفريغ أو ملف تعريف؟

يجب أن أكون قادرًا على التقاط ملف تفريغ من بوابة Azure إذا كنت تعتقد أن هذا سيساعد؟
لست متأكدا ما هو ملف التعريف؟

أي أفكار حول كيفية الوصول إلى جوهر هذه المشكلة؟

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

لقد حصلنا على بضع مئات من هذه المقاييس يوميًا ، على الرغم من أن جميع المقاييس تبدو صحية.

ربما أي مصدر سجل معين يمكنني تشغيله في جوهر azure / asp.net؟

لا يعطينا تتبع المكدس الكثير.

Exception: Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate.
   at Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException.Throw(RequestRejectionReason reason)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.TryRead(ReadResult& result)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.OnConsumeAsync()

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

[HttpPost]
        public async Task<OkResult> Webhook()
        {
            var memoryStream = new MemoryStream();
            await Request.Body.CopyToAsync(memoryStream);
            bool isValidRequest = await AuthorizationService.IsAuthenticWebhook(Request.Headers, memoryStream, _shopifyLibOptions.SecretKey);
            if (!isValidRequest)
            {
                throw new UnauthorizedAccessException("This request is not an authentic webhook request.");
            }
            memoryStream.Position = 0;
            string body = new StreamReader(memoryStream).ReadToEnd();

        //omitted code here unrelated to asp.net

            return Ok();
        }

مكدس المكالمات يشير إلى الخط
bool isValidRequest = await AuthorizationService.IsAuthenticWebhook(Request.Headers, memoryStream, _shopifyLibOptions.SecretKey);
على الرغم من تجربتي ، فإن أرقام الأسطر في مكدس المكالمات تكون في بعض الأحيان متوقفة قليلاً وأتساءل عما إذا كانت المشكلة الحقيقية هي السطر قبل await Request.Body.CopyToAsync(memoryStream);

ثم المكدس أدناه هو

Exception: Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate.
   at Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException.Throw(RequestRejectionReason reason)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.GetReadAsyncResult()
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.MessageBody.d__22.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.d__23.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at LINE FROM OUR CODE

.ReadToEnd(); علامة حمراء تمنع IO المزامنة. غالبًا ما تم الإبلاغ عن خطأ معدل البيانات هذا في التطبيقات التي تواجه مشكلة مع عدد كبير جدًا من سلاسل رسائل Threadpool المحظورة. في هذه الحالة ، هناك بديل سهل لـ ReadToEndAsync() . هل تحققت من مشاكل التجويع في مكان آخر؟

لكن الدفق هنا عبارة عن دفق ذاكرة. لهذا السبب يستخدم إصدار المزامنة. لا I / O أليس كذلك؟

عدد الخيوط منخفض والمقاييس صحية.
تبدو هذه المشكلة متقطعة جدًا ولكننا نحصل على هذه الأخطاء على دفعات من 5 أو 10 ...
هل يمكن أن يكون سببه التسبب في توقف GC؟

آه ، لقد حصلت علي. لم أكن أقرأ عن كثب بما فيه الكفاية.

ما هو حجم المنشورات؟

إنها حمولات صغيرة جدًا من نوع json. الطلب ، العميل ، المنتج ، هذا النوع من الأشياء ...

ما هو الحجم الصغير جدا؟

عادةً ما يكون أقل من 10 آلاف حرف ، على الرغم من وجود عدد قليل من القيم المتطرفة التي تزيد عن 100 ألف حرف.
على الرغم من أننا نتلقى الكثير من الطلبات. ما يقرب من 500 ألف في اليوم.

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

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

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

باستخدام IHttpContextAccessor ؟ كيف يبدو هذا الرمز؟

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

ديفيد ، تضمن هذا النشر إصلاحًا متعلقًا بـ IHttpContextAccessor الذي ساعدتني في حله هنا . اعتقدت بشكل غير صحيح أن هذا قد يكون قد أصلح هذه المشكلة أيضًا.

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

مبسطة قليلاً من أجل الوضوح:

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Middlewares
{
    public class RequestLogScopeMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<RequestLogScopeMiddleware> _logger;

        public RequestLogScopeMiddleware(RequestDelegate next, ILogger<RequestLogScopeMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task Invoke(HttpContext context)
        {
            using (_logger.BeginScope(await GetHttpInfo(context)))
            {
                await _next(context);
            }
        }

        private async Task<HttpInfo> GetHttpInfo(HttpContext ctx)
        {
            try
            {
                var req = ctx.Request;
                req.EnableRewind();
                string body = await new StreamReader(req.Body).ReadToEndAsync();
                req.Body.Position = 0;
                try
                {
                    body = JsonConvert.SerializeObject(JsonConvert.DeserializeObject(body), Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
                }
                catch
                {
                    //body may not be json
                }
                return new HttpInfo(req.Method, req.GetDisplayUrl(), body, string.Join(Environment.NewLine, req.Headers.Select(kv => $"{kv.Key}: {kv.Value}")));
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex, "Failed to extract http info from request");
                return null;
            }
        }
    }
}

خطأ مسجّل:

Failed to extract http info from request

    HttpInfo: 

    Exception: Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate.
   at Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException.Throw(RequestRejectionReason reason)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.TryRead(ReadResult& result)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.OnConsumeAsync()

أنا متأكد تمامًا من أنها مرتبطة بـ await new StreamReader(req.Body).ReadToEndAsync();

إليك مكدس آخر يشير بوضوح إلى أن قراءة الدفق هي المشكلة:

Error from Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware:
    An unhandled exception has occurred while executing the request.

    HttpInfo: 

    Exception: Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate.
   at Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException.Throw(RequestRejectionReason reason)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.ReadAsync(CancellationToken token)
   at System.IO.Pipelines.Pipe.DefaultPipeReader.ReadAsync(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.MessageBody.d__21.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.d__21.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.d__35.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.IO.StreamReader.d__97.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.IO.StreamReader.d__62.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Middlewares.RequestLogScopeMiddleware.d__5.MoveNext()

@ halter73 أي أفكار؟

ملاحظة: هل تستخدم تلك البرامج الوسيطة في الإنتاج؟ يبدو غير فعال بشكل رهيب.

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

يعد الحصول على سجل للجسم مفيدًا جدًا للتحقيق في سبب وجود أخطاء في طلب معين ...

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

لم نعاني من أي مشكلات في الأداء ولكني أستمع إذا كانت لديك أفكار حول كيفية جعل هذا أكثر أداءً.

إنه انتظار حدوث DoS. يمكنني فقط إرسال حمولة كبيرة إلى التطبيق الخاص بك والازدهار ، نفاد الذاكرة. (انظر https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/Scenarios/Controllers/BigJsonInputController.cs للحصول على مثال). سيكون أيضًا أحد ASP.NET Core no-no (راجع https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AspNetCoreGuidance.md#avoid-reading-the-entire-request-body-or -استجابة للجسد في الذاكرة)

يعد الحصول على سجل للجسم مفيدًا جدًا للتحقيق في سبب وجود أخطاء في طلب معين ...

نعم ، لقد رأيت ذلك مرات كافية الآن لدرجة أنني أعتقد أنه يجب علينا بناء شيء أكثر كفاءة من خارج الصندوق https://github.com/aspnet/AspNetCore/issues/3700

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

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

أيضًا ، الغالبية العظمى من الطلبات التي نتلقاها هي خطافات الويب ، والتي يمكن أن تتخذ أشكالًا مختلفة (ولكن دائمًا بتنسيق json) ويجب علينا التحقق من صحتها عن طريق تجزئة الجسم.
(راجع طريقة Webhook() نشرتها أعلاه)
لذلك لا يمكننا استخدام [FromBody] لأن الحمولة يمكن أن تختلف كثيرًا من طلب لآخر.

إنه انتظار حدوث DoS. يمكنني فقط إرسال حمولة كبيرة إلى التطبيق الخاص بك والازدهار ، نفاد الذاكرة.

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

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

ما الفرق بين الآتيتين؟

await new StreamReader(Request.Body).ReadToEndAsync();
await new HttpRequestStreamReader(Request.Body, Encoding.UTF8).ReadToEndAsync();

لقد نشرنا مرة أخرى اليوم لمحاولة إصلاح هذا.
لم نعد نجمع الجثة عند التسجيل ، بناءً على تعليقاتdavidfowl الجيدة حول الأداء والأمان.
أزلنا جميع استخدامات HttpAccessor وبقي لنا الجزء الوحيد الآخر من الكود الذي يقرأ النص بالكامل ويسبب الخطأ ، في إجراءنا Webhook() ، والذي يبدو الآن كالتالي:

        [HttpPost]
        public async Task<OkResult> Webhook()
        {
            var body = await new HttpRequestStreamReader(Request.Body, Encoding.UTF8).ReadToEndAsync();
            bool isValidRequest = AuthorizationService.IsAuthenticWebhook(Request.Headers, body, _options.SecretKey);
            if (!isValidRequest)
            {
                throw new UnauthorizedAccessException("This request is not an authentic webhook request.");
            }
            //handle webhook
            return Ok();
        }

استخدام HttpRequestStreamReader لم يحل المشكلة.

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

public override void OnException(ExceptionContext context)
{
    context.ExceptionHandled = true;
    ThreadPool.GetAvailableThreads(out var workerThreads, out var completionPortThreads);
    ThreadPool.GetMaxThreads(out var maxWorkerThreads, out var maxCompletionPortThreads);
    _logger.LogError(context.Exception, $"Error in global mvc exception filter. Available Threads = ({workerThreads:N0}/{maxWorkerThreads:N0}, {completionPortThreads:N0}/{maxCompletionPortThreads:N0}).");
}
Error in global mvc exception filter. Available Threads = (32,757/32,767, 1,000/1,000).

    Exception: Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate.
   at Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException.Throw(RequestRejectionReason reason)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.TryRead(ReadResult& result)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.OnConsumeAsync()

الأفكار تنفد.

@ clement911 ما هو مقياس خدمة التطبيقات لديك؟

لدينا ما يشبه نفس المشكلة. تطبيق ASP.NET Core 2.1 في نشر Azure App Service (Windows) بسلوك مشابه - جيد لبضع دقائق ، ثم تطرح مجموعة من الاتصالات هذا الاستثناء ، ثم بخير مرة أخرى.

كل الطلبات عبارة عن POST بهيئة JSON تتم قراءتها وإلغاء تسلسلها في برمجية وسيطة.

مرحبًا tstuts ،
إنه نشر مع 3 إلى 5 مثيلات S2 ونحصل على عدد كبير من الطلبات ، معظمها خطاطيف ويب.
عدة 100 ألف في اليوم.

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

Warning from Microsoft.AspNetCore.Server.Kestrel:
    Heartbeat took longer than "00:00:01" at "11/01/2018 19:48:02 +00:00".

هذا يعني عادة أن هناك مجاعة في تجمع الخيوط ... همم

davidfowl لا أفهم كيف يكون ذلك ممكنًا نظرًا لأن ThreadPool.GetAvailableThreads يبلغ عن وجود الكثير من سلاسل الرسائل المتاحة؟
نحن لا ننشئ خيوط يدوية.
لدينا عدد قليل من Task.Run () وكذلك العديد من الوظائف الدورية في الخلفية المجدولة عبر Observable.Timer ، والذي يستخدم ThreadPool تحت الغطاء.

إليك لقطة شاشة من Azure Portal تُظهر عدد سلاسل الرسائل الخاصة بنا على مدار الـ 12 ساعة الماضية.
لا أعتقد أن أكثر من 200 موضوع مفرط؟

image

200 خيط هو أكثر بكثير من النوى لديك. إذا كانت كل هذه الخيوط نشطة ، فقد لا يحصل بعضها على وقت كافٍ لوحدة المعالجة المركزية (على غرار تجويع مجموعة الخيوط). نجري بعض التغييرات في مؤقتات معدل البيانات للتخفيف من حدة هذه السيناريوهات. https://github.com/aspnet/KestrelHttpServer/pull/3070. ومع ذلك ، من المحتمل أن نظامك لا يزال مرهقًا.

إذا كان هذا هو الحال ، فأعتقد أن زيادة عدد الحالات قد يحل المشكلة.

عفوا جهلي هنا لكني لا أفهم.
تبدو وحدة المعالجة المركزية والذاكرة صحية بالنسبة لي (انظر لقطات الشاشة أدناه).
نقوم بتشغيل مثيلات S2 لكن بوابة Azure توصي باستخدام S1.
حاولت معرفة عدد النوى الموجودة في S2 ولكن كل ما يمكنني قوله هو أن لديهم 200 وحدة حسابية من نوع Azure ، مهما كان ذلك يعني.

لقد مررت بأحدث أخطاء MinRequestBodyDataRate وكان الفرق بين المعالجات المتاحة والحد الأقصى للخيوط دائمًا أقل من 100 ، لذلك هناك أقل من 100 مؤشر ترابط عامل من أصل الحد الأقصى الافتراضي المفترض (؟) وهو 32757! 100/32757 أقل من 1/3 من 1٪.

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

image

image

هل تستخدم Task.Wait أو Task.Result في أي مكان؟

شكرًا لك davidfowl الذي كان

هل تستخدم Task.Wait أو Task.Result في أي مكان؟

لا.
سأستمر في البحث عن أي مكالمات محظورة ربما فاتني.

بالمناسبة نحن لا نستخدم. net core.
نحن نستخدم .net 4.7.1 ، لكنني أفترض أن تجمع مؤشرات الترابط يعمل بطريقة مماثلة.

@ clement911 نعم ، إنه نفس الشيء بشكل أساسي (النواة أكثر

يحاول .NET Threadpool حقن المزيد من الخيوط ، ولكنه يفعل ذلك بمعدل متواضع (على سبيل المثال 1 أو 2 في الثانية) ، لذلك لا يحدث فرقًا كبيرًا على المدى القصير (تحتاج إلى عدة دقائق للحصول على ما يصل إلى 1000).

أتساءل ما إذا كانت هذه مشكلة. لا يبدو هذا كإستراتيجية رائعة للتعامل مع الارتفاعات المؤقتة.

شكرًا ، سوف أتحقق من Ben.BlockingDetector.

كل ما تقوم به طريقة webhook الخاصة بنا هو التحقق من أنها أصلية (مرتبطة بوحدة المعالجة المركزية) وحفظها في db مع ef core (async IO).

لقد لاحظت أنه عند حدوث خطأ MinRequestBodyDataRate ، فمن المحتمل (ولكن ليس دائمًا) أن يحدث جنبًا إلى جنب مع تحذير لعدة خطافات ويب أخرى تقول إن الحفظ في قاعدة البيانات استغرق وقتًا سخيفًا (على سبيل المثال ، أكثر من 40 ثانية وحتى ما يصل إلى 180 ثانية!) لحفظ بيانات الرد التلقائي على الويب.
اعتقدت أنه قد تكون إستراتيجية إعادة المحاولة الأساسية لـ EF هي التي تقوم بإعادة المحاولة المتعددة ، ولكن بقدر ما أستطيع أن أقول أن قاعدة البيانات سريعة الاستجابة ولم أجد حدثًا في EF الأساسي لتسجيله عند حدوث إعادة المحاولة ...
يبدو أنها مصادفة غريبة لذا سأفترض أنها قد تكون بسبب نفس استنفاد الخيط.

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

سأفعل شكرا يا رفاق ، أنا حقا أقدر المساعدة

ما هو رمز حالة HTTP الذي سيتم إرجاعه إلى العميل عند حدوث MinRequestBodyDataRate / BadHttpRequestException؟
أعتقد أن 4xx؟ (على الرغم من أنه من المحتمل أن يكون مشكلة داخلية في حالتي)

لقد حصلنا على الكثير من هذه الأخطاء في سجلاتنا ولكن مقاييس بوابة Azure تدعي أنه لا يكاد يوجد أي استجابات HTTP 4xx أو 5xx. أنا لا أفهم.

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

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

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

بدافع الاستياء ، قمت (على مضض) بتمكين تطبيق رؤى التطبيق التي قرأتها ، والتي يمكن أن تجمع المقاييس دون إعادة النشر. لم تنجح. لا يعرض أي من المقاييس أي بيانات. قد أضطر إلى النظر في تكوين رؤى تطبيق وقت البناء.

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

يبدو أن المشكلة تزداد خطورة مع النشاط المتزايد الذي نحصل عليه بمرور الوقت.
: مرهق:: confused:

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

image

بالمناسبة ، لقد فوجئت برؤية 3 من الخيوط التي تم التقاطها بواسطة ConsoleLogger MessageProcessor Queue. هذا جعلني أتساءل لماذا يتم تمكينه بشكل افتراضي ...

لذلك كنت أقاتل مع هذا وأردت الإبلاغ عن النتائج التي توصلت إليها.

كان علينا أن نتصرف بسرعة ، وقررنا نشر نسخة طبق الأصل من تطبيقنا في خطة خدمة تطبيق جديدة.
بعد ذلك ، نقلنا جميع اشتراكات الرد التلقائي على الويب للإشارة إلى المثيل الجديد.
لذلك ، لا تتعامل خدمة التطبيق الأصلية إلا مع الطلبات التي تواجه المستخدم وجعلتها مستقرة جدًا. لا اخطاء.
خدمة التطبيق الجديدة تتعامل مع webhooks ولا تفعل شيئًا آخر.
لا يتم عرض خدمة التطبيق الجديدة للمستخدمين ، والطلبات الوحيدة التي يتم تلقيها هي إجراء Webhook () بسيط يقوم بتجزئة الجسم ويخزن الجسم في db عن طريق إجراء مكالمة غير متزامنة عبر SqlCommand بـ await cmd.ExecuteNonQueryAsync();
حسنًا ، لا يزال خطأ MinRequestBodyDataRate يحدث! (في المثال الجديد بالطبع).

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

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

أفكر في تجربة إعداد ThreadPool.SetMinThreads وإعداد ADO.net "MinPoolSize".
قد يكون من الإستراتيجية الجيدة الاحتفاظ بالكثير من الخيوط و / أو الوصلات قيد التشغيل للتعامل مع القمم.
إذا كان لدى أي شخص خبرة في هذا المجال فأنا أستمع.
من السهل ضبط هذه الإعدادات ، ولكن هناك القليل جدًا من الوثائق حول كيفية عملها خلف الكواليس وتشعر بأنها صندوقية سوداء للغاية. ربما يكون سببًا جيدًا إلا عندما تصادف سيناريو كهذا ...

يبدو أنك على الطريق الصحيح. أحد البدائل التي أخذناها في الاعتبار لسيناريوهات مثل هذه هو تقييد الطلب. هذا من شأنه أن يقلل من الطلب على Threadpool.

ألست متأكدًا تمامًا من كيفية تنفيذك للخنق وكيف سيؤدي ذلك إلى حل المشكلة؟

تتمثل إحدى المشكلات في أن معظم موفري الويب هوك (الأنظمة / واجهات برمجة التطبيقات التي ترسل الطلبات) يحتاجون عادةً إلى مستمع (مثلنا) للرد باستخدام HTTP 200 بسرعة كبيرة أو أنهم يعتبرون ذلك فاشلاً.
في حالتنا 5 ثوان.

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

@ clement911 هل يمكنك إعادة

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

تستضيف خدمتا التطبيق

SemaphoreSlim لديه نادل غير متزامن لذلك لا يمنع الخيوط.

davidfowl أعتقد أن لدي مشكلة مشابهة جدًا مع 2.1.5 التعامل مع خطافات الويب Azure DevOps في خدمة ويب تجريبية. عدد الطلبات منخفض (رشقات نارية من 6 فقط عند إنشاء قائمة انتظار). في حالتي ، يتم إعادة عرضه ربما على 5-10 ٪ من رشقات نارية. مرة أخرى أقوم بقراءة / تجزئة الجسم للتحقق من صحة التوقيع.

@ clement911mmitche هل يا رفاق رؤية الكثير من هذا الاستثناء أيضا؟

Microsoft.AspNetCore.Connections.ConnectionResetException: تم إغلاق اتصال موجود بالقوة من قبل المضيف البعيد

tstuts نعم.

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

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

لا أتذكر هذا الاستثناء ، لكنني سأختبر خدمتي أكثر قليلاً الآن لذا سأخبرك بما يحدث.

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

يبدو أيضًا أنه تجويع الخيط ، فنحن نعمل على مثيل S3 واحد:
image

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

ليس هناك الكثير من التقدم للإبلاغ عنه حتى الآن. أحتاج إلى تصحيح تعليقي السابق: نحن نستضيف عددًا من تطبيقات ASP.NET و ASP.NET Core في خدمة تطبيق واحدة ، مثل التطبيقات الافتراضية.

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

فيما يتعلق بعدد الخيوط ، نصل إلى متوسط ​​180 عند الخمول بسبب w3wp + التطبيقات المختلفة التي تعمل عليه. لذلك ربما لا توجد مشكلة كبيرة في هذا المجال. سأستمر في اختبار الحمل وإجراء التشخيصات لتحديد مصدر المشكلة.

نشاهد نفس رسائل الخطأ ، لكننا تمكنا من إعادة إنتاجها باستخدام ملفات تعريف Chrome's Network Throttling. بعد إنشاء واحد بسرعة 1 كيلو بايت / ثانية (لأعلى / لأسفل) ووقت استجابة 5 كيلو مللي ثانية ، تمكنا من رؤية تأثيرات الحصول على BadHttpRequestExceptions مع "انتهت مهلة قراءة نص الطلب بسبب وصول البيانات ببطء شديد. راجع MinRequestBodyDataRate".

في حالة الإنتاج لدينا ، كانت المشكلة تتعلق بعميل محمول ، مع اتصال إنترنت متقطع للغاية ، وتنزيل البيانات.

davidfowl هل الاستثناء الصعب هو أفضل طريقة للتعامل مع هذا؟ هل نحتاج فقط إلى برمجيات وسيطة للتعامل مع العملاء البطيئين وابتلاع الاستثناء؟

كما في حالتنا ، يتم إعادة تدوير خدمات التطبيقات (يُفترض أن ذلك يرجع إلى شيء مثل الحماية من الفشل السريع). لا أذكر أي شيء مثل هذا في IIS 7 الذي يشغل ASP.NET 4.5. على الرغم من أن IIS قد قام بتعطيل تجمع التطبيقات ، وأخذ التطبيق في وضع عدم الاتصال تمامًا ...

نفس المشكلة بالنسبة لي كذلك.
فيما يلي الكود الخاص بي الذي يقدم تحميلات الصور من عدة كاميرات متصلة عبر GPRS (التشغيل ثم إيقاف التشغيل لتوفير الطاقة):

        [HttpPost("photo/post")]
        public async Task PostLegacyAsync()
        {
            var content = new MultipartFormDataContent();
            foreach (var pair in this.Request.Form)
            {
                content.Add(new StringContent(pair.Value), pair.Key);
            }
            foreach (IFormFile ff in this.Request.Form.Files)
            {
                byte[] data;
                using (var br = new BinaryReader(ff.OpenReadStream()))
                {
                    data = br.ReadBytes((int)ff.OpenReadStream().Length);
                }
                content.Add(new ByteArrayContent(data), ff.Name, ff.FileName);
            }

            // ...

            this.Ok();
        }

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

كملاحظة جانبية ، يمكنني قبول فشل عشوائي في وقت ما ، لكني لا أحب تعطل التطبيق بسبب ذلك.

أدى التحديث إلى أحدث إصدار من System.IO.Pipelines إلى إصلاح المشكلة بالنسبة لي.

highfield يجب أن تتجنب استخدام Request.Form وبدلاً من ذلك استخدم ReadFormAsync

تحية للجميع،

لدينا نفس المشكلة في الإنتاج ، حالتان S1. في بيئتنا يبدو أنه مرتبط بالانفجارات في الاتصالات / الطلبات ، انظر الرسم البياني المرفق. أخطاء الخادم في المخطط هي الأخطاء التي تمت مناقشتها في هذه المسألة. بمعنى آخر:

BadHttpRequestException: Reading the request body timed out due to data arriving too slowly

image

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

نحن نشهد نفس المشكلة في الإنتاج ، إلى جانب BadHttpRequestException يؤدي إلى استجابة 400: "نهاية غير متوقعة لمحتوى الطلب". لدينا القليل من البصيرة حول سبب هذه المشكلة ، ولكن أقل من طلب واحد / ثانية مع نص طلب 600 كيلوبايت سيؤدي إلى تشغيلها. يبدو أنه يتفاقم بسبب اتصالات العملاء غير الموثوقة ، مثل شبكات 3G المتنقلة / الخلوية. لا نرى أي ارتفاعات ذات صلة في استهلاك وحدة المعالجة المركزية أو الذاكرة في وقت حدوث ذلك.

تحاول تعقب هذه المشكلة بسبب استمرار تعطل حاويات ASP.NET Core 2.1 على K8s. اعتقدت أنها ستجهض الطلب لكنها فوجئت أنه يبدو أنها تعطل العملية ...

لا يؤدي إحباط الطلب إلى تعطل العملية

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

@ clement911 لقد تمكنت من إصلاح هذه المشكلة في مشروع عملي عن طريق إزالة استخدام HTTP2 في تكوين Kestrel في Program.cs. هل يمكنك محاولة الرد على التأثير - أنا أشعر بالفضول حيال ذلك لأنه في الشركة فقط خارج المشروع لديه هذه المشكلة.

@ Chakalaka11 لم نقم بتمكين http 2 ولكن هل يمكنك من فضلك نسخ الكود الخاص بك هنا؟

@ clement911 لذلك ، قام الفريق خلال الساعات الماضية ببعض التغييرات ، وإزالة UseKestrel ، باستخدام ConfigureKestrel لإعادة إرفاق http2 ، يعمل بشكل جيد أيضًا. يقول الرجل الذي أجرى الإصلاح أن UseKestrel يمكنه إعادة كتابة بعض التكوين القياسي وارتكب خطأ.
image

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

محدث: العمل على ما يرام.

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

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

أود الانضمام إلى "الحفلة".
في الكود الخاص بنا ، نقوم بما يلي:
C# await context.Request.Body.CopyToAsync(requestBodyStream);
لا شيء متزامن مع دفق الطلب. حصلنا على الخطأ "انتهت مهلة قراءة نص الطلب نظرًا لوصول البيانات ببطء شديد. راجع MinRequestBodyDataRate."

أي نتائج يمكن أن تساعدنا؟ قرأت الموضوع أعلاه ويبدو أن السبب الأساسي غير معروف حتى الآن.

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

لقد جربت ما يلي بطريقة Startup.cs ConfigureServices ...

services.Configure<KestrelServerOptions>(options =>
            {
                options.Limits.MinRequestBodyDataRate = new MinDataRate(1, TimeSpan.FromMinutes(5));
                options.Limits.MinResponseDataRate = new MinDataRate(1, TimeSpan.FromMinutes(5));
                options.Limits.MaxRequestBodySize = 100000000;
            });

قبل إجراء هذا التغيير ، كان لدي حاويات asp.net الأساسية في Kubernetes والتي كانت تتعطل / تعيد تشغيل 90 مرة في الساعة ، وكانت الرسالة الأخيرة في سجل الحاوية هي تتبع مكدس BadHttpRequestException . (كما قال davidfowl أعلاه ، بدا هذا غريبًا حقًا لأنني أتوقع حدوث هذا الاستثناء عند مستوى الطلب وليس تعطل العملية ... لذلك أميل إلى الاعتقاد بأنه ربما كان هناك شيء آخر يساهم أيضًا في الانهيار؟)

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

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

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

سيكون من الرائع أن يقوم فريق asp.net الأساسي بإنشاء اختبار إجهاد تصاعدي على تطبيق ويب بسيط لتأكيد ما إذا كان هناك بالفعل عنق زجاجة على مستوى مجموعة الخيوط ، أو في أي مكان آخر.

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

هذا يحدث لنا في
Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.<PumpAsync>
دعا من قبل
Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.MessageBody.<ReadAsync>
دعا من قبل
Microsoft.AspNetCore.WebUtilities.FormReader.<ReadFormAsync>
دعا من قبل
Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenStore.<GetRequestTokensAsync>
مما يعني أنه يحدث عند فحص csrf.

المزيد من تتبع المكدس:
Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate. at Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException.Throw(RequestRejectionReason reason) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.<PumpAsync>d__4.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.IO.Pipelines.PipeCompletion.ThrowLatchedException() at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result) at System.IO.Pipelines.Pipe.GetReadAsyncResult() at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.MessageBody.<ReadAsync>d__21.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.<ReadAsyncInternal>d__21.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.IO.StreamReader.<ReadBufferAsync>d__97.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.IO.StreamReader.<ReadAsyncInternal>d__64.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.WebUtilities.FormReader.<BufferAsync>d__41.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.WebUtilities.FormReader.<ReadNextPairAsyncImpl>d__34.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.WebUtilities.FormReader.<ReadFormAsync>d__43.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Http.Features.FormFeature.<InnerReadFormAsync>d__18.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenStore.<GetRequestTokensAsync>d__3.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.<ValidateRequestAsync>d__9.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ValidateAntiforgeryTokenAuthorizationFilter.<OnAuthorizationAsync>d__3.MoveNext() -

كان لدينا هذا مرة واحدة الآن. ترسل العملية سلسلة معرّف وسلسلة إجابات مع بعض ملفات تعريف الارتباط. جسم صغير جدًا حقًا.

2019-05-09 11:31:50.9573|30131|TRACE|9.5.3.0|189|Base|BaseController.QuestionsSaveAnswer|27 ms|
2019-05-09 11:32:17.6812|30131|TRACE|9.5.3.0|97 |Base|BaseController.QuestionsSaveAnswer|24 ms|
2019-05-09 11:32:27.2114|30131|ERROR|9.5.3.0|106|Base|BaseController.GetErrorMessage|Error Page Path=/questionsSaveAnswer, error = Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate.
   at Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException.Throw(RequestRejectionReason reason)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1MessageBody.PumpAsync()
   at System.IO.Pipelines.PipeCompletion.ThrowLatchedException()
   at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
   at System.IO.Pipelines.Pipe.GetReadAsyncResult()
   at System.IO.Pipelines.Pipe.DefaultPipeReader.GetResult(Int16 token)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.MessageBody.ReadAsync(Memory`1 buffer, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.ReadAsyncInternal(Memory`1 buffer, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.DrainAsync(Stream stream, ArrayPool`1 bytePool, Nullable`1 limit, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Mvc.Formatters.JsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
   at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)
   at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---

نقوم بتشغيل ASP Net Core 2.2.0 في العملية على IIS. في السجل الرقم قبل | Base | هو معرف الموضوع.

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

ThreadPool.SetMaxThreads(32_767, 2_000);
ThreadPool.SetMinThreads(1_000, 1_000);

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

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

لا يساعد في أن يكون ThreadPool معتمًا وأن الوثائق محدودة للغاية.

سم مكعبstephentoubkouvel

هذه مقالة ممتازة تصف سبب ذلك ولماذا يجب أن يكون رفع الحد الأدنى تدبيرًا مؤقتًا
https://blogs.msdn.microsoft.com/vancem/2018/10/16/diagnosing-net-core-threadpool-starvation-with-perfview-why-my-service-is-not-saturating-all-cores- أو-يبدو-إلى-المماطلة /

نعم شكرا لك ، لقد قرأت ذلك وهو بالفعل مقال رائع.
تقول أن زيادة الحد الأدنى من الخيوط هو إجراء مؤقت إذا كان سبب تجويع الموضوع ناتجًا عن حظر المكالمات .
لكن في حالتنا ، لا نحظر أبدًا. نحن نستخدم فقط واجهات برمجة التطبيقات غير المتزامنة IO.
لذلك ، بقدر ما أستطيع أن أقول ، فإن الطريقة الوحيدة للتعامل مع الانفجار المفاجئ هي زيادة الحد الأدنى من الخيوط.
لقد قلصنا الآن إلى مثيل azure أرخص وتم توسيع نطاقه من 4 مثيلات إلى مثيلين ولم نعد نحصل على خطأ واحد بعد الآن. إنه أمر رائع جدًا!
ومن المثير للاهتمام ، أن عدد الخيوط لم يزد بشكل كبير ولكن يمكن أن يزيد بشكل أسرع
لاحظ أيضًا أن عدد سلاسل الرسائل أقل من الحد الأدنى الذي قمنا بتعيينه وهو 1000 ، لأن تجمع مؤشرات الترابط لا ينتج عنها إلا إذا كانت هناك عناصر تنتظر في قائمة الانتظار.
على الأقل ، هذا ما أفهمه.
قد يكون من المفيد أن تكون قادرًا على إنشاء مجموعات مؤشرات الترابط ومنحها خيارات مختلفة لأحمال العمل المختلفة ...

أنا مندهش للغاية لأنك ترى المجاعة دون حظر ، حتى من أجل رشقات نارية.

@ clement911 ربما حاول استخدام https://github.com/benaadams/Ben.BlockingDetector لمعرفة رمز إطار العمل الذي يحظره

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

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

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

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

قد يكون من المفيد النظر في الحظر الذي يحدث على الأرجح مع تتبع PerfView بما في ذلك Thread Time (والذي يتضمن أحداث تبديل السياق والوقت المستغرق في الحظر).

شكرا أقدر التعليقات.

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

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

عند التشغيل على IIS ، توجد قائمة انتظار طلبات عميقة في kernel (http.sys) ولكن لا توجد طلبات انتظار في قائمة انتظار في ASP.NET الأساسية. قائمة الانتظار الوحيدة هي قائمة انتظار تجمع مؤشر الترابط. الاستثناء الذي تراه قادم من kestrel (لذلك أفترض أنك تستخدم وحدة IIS خارج المعالجة). إذا كان لا يزال بإمكانك إعادة إظهار المشكلة ، فسيكون التتبع رائعًا. نحن فقط نضيف عدادات في .NET Core 3.0 والذي لا يساعدك الآن ولكن هذا الشيء الفردي يجب أن يكون أكثر وضوحًا في المستقبل مع تلك العدادات.

راجع للشغل ، كنت أشير إلى قائمة انتظار تجمع مؤشرات الترابط.

ربما يمكنك وضع الطلبات من Shopify في قائمة انتظار الخلفية الخاصة بك ومعالجتها واحدة تلو الأخرى. بهذه الطريقة ، لن يكون لديك السنبلة أبدًا.
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services؟view=aspnetcore-2.2

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

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

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

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

كانت لدينا نفس المشكلة وقمنا بحلها عن طريق نقل قراءة نص الطلب خارج وحدة التحكم.

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

BadHttpRequestException: انتهت مهلة قراءة نص الطلب نظرًا لوصول البيانات ببطء شديد

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

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

لهذا السبب أنشأنا InputFormatter سمح بقراءة نص الطلب بتنسيق json كسلسلة واستردنا نص الطلب كمعامل في وحدة التحكم مثل هذا:

public async Task<IActionResult> ProcessAsync([FromBody]string jsonBody = null)

بعد تطبيق هذا الحل البديل ، لم يكتشف BlockingDetector الحظر بعد الآن ولم يعد لدينا BadHttpRequestExceptions لمدة ثلاثة أسابيع حتى الآن.

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

يمكنك مشاركة نتائج هذا؟

نعم ، كان هذا ناتجًا عن الأداة:
image

وهنا رمز وحدة التحكم السابق الذي أدى إلى تشغيل هذا:
using (HttpRequestStreamReader reader = new HttpRequestStreamReader(Request.Body, Encoding.UTF8)) { _jsonBody = await reader.ReadToEndAsync(); }

باستخدام (HttpRequestStreamReader reader = new HttpRequestStreamReader (Request.Body، Encoding.UTF8)) {_jsonBody = await reader.ReadToEndAsync () ؛ }

هل كان هذا الرمز الذي كتبته في وحدة التحكم الخاصة بك؟

نعم ، كان هذا هو الرمز مع المنع.

berndku لماذا يتم إزالة تسلسل JSON يدويًا من سلسلة بدلاً من استخدام المنسق المدمج؟

davidfowl : الأداء ، ليست كل طلباتنا تتطلب إلغاء تسلسل كامل للجسم بأكمله. لكنني أعتقد أننا اختبرناها أيضًا بسرعة باستخدام المُنسق المدمج عن طريق استبدال السلسلة بمعامل JObject ولم نرى حظرًا هناك أيضًا.

davidfowl : الأداء ، ليست كل طلباتنا تتطلب إلغاء تسلسل كامل للجسم بأكمله. لكنني أعتقد أننا اختبرناها أيضًا بسرعة باستخدام المُنسق المدمج عن طريق استبدال السلسلة بمعامل JObject ولم نرى حظرًا هناك أيضًا.

الأداء مثقل؟ أفضل مقايضة الإنتاجية من استخدام الذاكرة؟ يعني تخزين الجسم بالكامل في ذاكرة أن لديك هذه السلسلة المؤقتة فقط لغرض تحويلها إلى كائن آخر. لا تحظر المُنسِّقات المضمنة ، فهي تبذل قصارى جهدها لتجنب التخزين المؤقت في كتلة واحدة متجاورة من الذاكرة (مثل سلسلة أو بايت []).

بغض النظر ، سأبلغ عن مشكلة تتعلق بسلوك ReadToEndAsync https://github.com/aspnet/AspNetCore/issues/13834

شكرا لتقديم القضية!

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

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

https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AspNetCoreGuidance.md#avoid -reading-large-request-body-or-response-body -odies-in-memory

😄

davidfowl يوفر هذا الرابط سياقًا لـ _لماذا_ لا تفعل هذا (رائع! 😃) ، ولكن ليس _ ماذا تفعل بدلاً من ذلك_ (أوه 😞). لنفترض أنك بحاجة إلى قبول نصوص ملفات عشوائية في أحد الطلبات ، وإرسال نص طلب الملف التعسفي هذا إلى نظام آخر ، مثل قاعدة بيانات أو قائمة انتظار رسائل. كيف تتجنب قراءة هذا الطلب في الذاكرة؟

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

نظرًا لأن # 13834 يتعلق بـ _HttpRequestStreamReader_ ، فقد راجعت المنسق المخصص (الكود أدناه) مرة أخرى ، ولكن هناك استخدمنا _StreamReader_. هل يمكن أن يكون هذا هو السبب ، لماذا لا نرى الحظر باستخدام المنسق المخصص؟

إذا كانت الإجابة بنعم ، فهل هذا يعني أنه يجب علينا تجنب _HttpRequestStreamReader_ حتى يتم إصلاح المشكلة؟

 public class RawJsonBodyInputFormatter : InputFormatter
    {
        public RawJsonBodyInputFormatter()
        {
            this.SupportedMediaTypes.Add("application/json");
        }

        public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context)
        {
            var request = context.HttpContext.Request;
            using (var reader = new StreamReader(request.Body))
            {
                var content = await reader.ReadToEndAsync();
                return await InputFormatterResult.SuccessAsync(content);
            }
        }

        protected override bool CanReadType(Type type)
        {
            return type == typeof(string);
        }
    }

مم ، آسف إذا لم يكن هذا مرتبطًا ، لكنني أحصل على هذا الإخراج من مراقب الحظر عند إعادة تشغيل IIS. يحدث عدة مرات. يمكنني استخدام taghelper asp-append-version. بعد إزالة ذلك مؤقتًا ، لم يعد يتم الإبلاغ عن مكالمة الحظر.

2019-09-10 15: 06: 25.0604 | 35.230.16.48 || WARN | 9.9.19.0 | 39 | Base | BlockingMonitor.BlockingStart | تم استدعاء طريقة الحظر وحظرها ، وهذا يمكن أن يؤدي إلى مجاعة Threadpool.
في System.IO.FileStream.Read (صفيف بايت [] ، إزاحة Int32 ، عدد Int32)
في System.Security.Cryptography.HashAlgorithm.ComputeHash (Stream inputStream)
في Microsoft.AspNetCore.Mvc.Razor.Infrastructure.DefaultFileVersionProvider.GetHashForFile (IFileInfo fileInfo)
في Microsoft.AspNetCore.Mvc.Razor.Infrastructure.DefaultFileVersionProvider.AddFileVersionToPath (PathString requestPathBase، String path)
في Microsoft.AspNetCore.Mvc.TagHelpers.ScriptTagHelper.Process (سياق TagHelperContext ، إخراج TagHelperOutput)
في Microsoft.AspNetCore.Razor.TagHelpers.TagHelper.ProcessAsync (سياق TagHelperContext ، إخراج TagHelperOutput)
في Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.RunAsync (تنفيذ TagHelperExecutionContext)
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperRunner.RunAsync (تنفيذ TagHelperExecutionContext)
في AspNetCore.Views_Shared__Layout. <> c__DisplayClass14_0. <b__1> d.MoveNext ()
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في AspNetCore.Views_Shared__Layout. <> c__DisplayClass14_0.ب__1 ()
في Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync ()
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperExecutionContext.SetOutputContentAsync ()
في AspNetCore.Views_Shared__Layout.ExecuteAsync ()
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في AspNetCore.Views_Shared__Layout.ExecuteAsync ()
في Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync (صفحة IRazorPage ، سياق ViewContext)
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync (صفحة IRazorPage ، سياق ViewContext)
في Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync (صفحة IRazorPage ، سياق ViewContext ، استدعاء منطقيViewStarts)
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync (صفحة IRazorPage ، سياق ViewContext ، استدعاء منطقيViewStarts)
في Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync (سياق ViewContext ، ViewBufferTextWriter bodyWriter)
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderLayoutAsync (سياق ViewContext ، ViewBufferTextWriter bodyWriter)
في Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync (سياق ViewContext)
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync (سياق ViewContext)
في Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync (ViewContext viewContext، String contentType، Nullable 1 statusCode) at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ViewContext viewContext, String contentType, Nullable 1 statusCode)
في Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync (ActionContext actionContext، IView view، ViewDataDictionary viewData، ITempDataDictionary tempData، String contentType، Nullable 1 statusCode) at System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start[TStateMachine](TStateMachine& stateMachine) at Microsoft.AspNetCore.Mvc.ViewFeatures.ViewExecutor.ExecuteAsync(ActionContext actionContext, IView view, ViewDataDictionary viewData, ITempDataDictionary tempData, String contentType, Nullable 1 statusCode)
في Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync (سياق ActionContext ، نتيجة ViewResult)
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.ViewFeatures.ViewResultExecutor.ExecuteAsync (سياق ActionContext ، نتيجة ViewResult)
في Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync (سياق ActionContext)
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.ViewResult.ExecuteResultAsync (سياق ActionContext)
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync (نتيجة IActionResult)
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultAsync (نتيجة IActionResult)
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext TFilter، TFilterAsync
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync TFilter ، TFilterAsync
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResultFilterAsync TFilter ، TFilterAsync
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.ResultNext TFilter، TFilterAsync
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters ()
في System.Runtime.CompilerServices.AsyncMethodBuilderCore.Start TStateMachine
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeResultFilters ()
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next (الحالة والتالي ، النطاق والنطاق ، الكائن والحالة ، القيمة المنطقية والمكتملة)
في Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter ()
في System.Threading.ExecutionContext.RunInternal (تنفيذ ExecutionContextContext، ContextCallback callback، Object state)
في System.Runtime.CompilerServices.AsyncTaskMethodBuilder 1.AsyncStateMachineBox 1.MoveNext ()
في System.Runtime.CompilerServices.TaskAwaiter. <> ج.b__12_0 (متابعة داخلية للإجراء ، مهمة داخلية للمهمة)
في System.Threading.QueueUserWorkItemCallback 1.<>c.<.cctor>b__6_0(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.QueueUserWorkItemCallback 1.ExecuteWorkItem ()
في System.Threading.ThreadPoolWorkQueue.Dispatch ()

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

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

عن طريق تقطيعها إلى مخازن مؤقتة <85K ثم نقلها قطعة تلو الأخرى. إنها إحدى الحيل التي يستخدمها Stream لنسخ البيانات من دفق واحد إلى دفق آخر https://github.com/dotnet/corefx/blob/ee9995f31b684a0c6e5488eceb2500bf0057da89/src/Common/src/CoreLib/System/IO/Stream.cs#L31 -L34.

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

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

نظرًا لأن # 13834 يتعلق بـ HttpRequestStreamReader ، فقد راجعت المنسق المخصص (الكود أدناه) مرة أخرى ، ولكن هناك استخدمنا StreamReader للتو. هل يمكن أن يكون هذا هو السبب ، لماذا لا نرى الحظر باستخدام المنسق المخصص؟

نعم ، StreamReader يتجاوز الطرق الصحيحة.

.UseKestrel(opt => { opt.Limits.MinRequestBodyDataRate = null; })
هل يمكن أن ينجح هذا؟

لديك نفس المشكلة عندما تتواصل خدمتان مع بعضهما البعض (داخل المضيف المحلي). MustafaHosny اللهم امين ...

تواجه نفس المشكلة

تحية للجميع،
نحن نبدأ مشروعًا جديدًا يتضمن حفظ webhooks مرة أخرى في قاعدة البيانات لمزيد من المعالجة.
نتوقع حمولات صغيرة ولكن عددًا كبيرًا من الطلبات.

هل الكود التالي هو الأمثل؟

[HttpPost]
        public async Task<OkResult> Webhook()
        {
            var body = await new HttpRequestStreamReader(Request.Body, Encoding.UTF8).ReadToEndAsync();
            //save to Db asynchronously?
            return Ok();
        }

أتلقى هذا الخطأ أيضًا ، لكنني أعتقد أن مشكلتي موجودة هنا:
blob.UploadFromByteArrayAsync(fileByteArray, 0, fileByteArray.Length).Wait();
ضد
await blob.UploadFromByteArrayAsync(fileByteArray, 0, fileByteArray.Length);

باستخدام Wait() سيؤدي التحميل إلى حظر الموضوع ، بينما استخدام await لن يفعل ذلك.

@ clement911 هي طريقة جيدة لمعالجة webhooks ، وسيكون من الرائع أن تتم المعالجة بعد ذلك من خلال قائمة انتظار الأحداث بدلاً من خادم الويب.

مشكلتي هي تلقي عنوان url وتنزيله ثم تحميله! من الغباء القيام بكل ذلك في طلب الويب. لذا ، سيكون إصلاح مشكلة Wait() محل نقاش بمجرد إعادة صياغة هذا الرمز للتحقق فقط من أن عنوان url للصورة جيد ، ثم تفريغ عمليات حفظ db الفعلية وتحميل الصور إلى معالج الأحداث.

لكن شكرا لك على مواكبة هذه المشكلة!

لمعلوماتك ، منذ وقت عملي هنا ، بدأت مشروعًا جديدًا مع Asp Net core 2.2 (كان سابقًا 2.1). علاوة على ذلك ، يعمل التطبيق الآن على Ubuntu 18 (كان سابقًا في 14).

لم يفشل أحد منذ ذلك الوقت.

davidfowl هل يتم تصحيح جزء الكود أدناه لإعادة توجيه تحميل إلى خدمة أخرى؟ كل عملية تحميل عبارة عن صورة (10-15 ميجابايت) وعدد قليل من أزواج المفاتيح والقيمة.

    [HttpPost("photo/post3")]
    public async Task PostV3Async()
    {
        IFormCollection fcoll = await this.Request.ReadFormAsync();

        var content = new MultipartFormDataContent();
        foreach (var pair in fcoll)
        {
            content.Add(new StringContent(pair.Value), pair.Key);
        }
        foreach (IFormFile ff in fcoll.Files)
        {
            byte[] data;
            using (var br = new BinaryReader(ff.OpenReadStream()))
            {
                data = br.ReadBytes((int)ff.OpenReadStream().Length);
            }
            content.Add(new ByteArrayContent(data), ff.Name, ff.FileName);
        }

        var client = this._httpClientFactory.CreateClient(ClientName);
        await client.PostAsync("/photo/post3", content);

        this.Ok();
    }

ما زلت أتساءل ما هي أفضل طريقة لقراءة نص الطلب بالكامل بشكل غير متزامن.

كنا نقوم بعمل await new HttpRequestStreamReader(Request.Body, Encoding.UTF8).ReadToEndAsync();
ولكن بعد الترقية إلى net core 3.1 ، حصلنا على هذه المشكلة: https://github.com/aspnet/AspNetCore/issues/13834

بما أن الإصلاح مخطط لـ .net 5.0 ، فما هي الطريقة الصحيحة لـ .net 3.1؟

أي التزام لهذه القضية؟

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

انا لدى نفس المشكله

وجود نفس المشكلة أيضا.

بالنسبة لأولئك الذين لا يزالون يواجهون المشكلة ، هل قرأت رسالتي؟ https://github.com/dotnet/aspnetcore/issues/4707#issuecomment -557538742

كما هو الحال اليوم ، لم أواجه أية مشكلات منذ أكثر من عام على خادمين مختلفين.

أي تحديث حول هذه المشكلة ، أواجه نفس الاستثناء. الطلب صغير جدًا ولكن kestrel يرمي 408 برسالة "الطلب يصل بطيئًا جدًا".

"message": "Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate.", "exception": {"Type":"Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException", "StatusCode":408, "TargetSite":"Void Throw(Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.RequestRejectionReason)", "StackTrace":"   at Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException.Throw(RequestRejectionReason reason)\r\n   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1ContentLengthMessageBody.ReadAsyncInternal(CancellationToken cancellationToken)\r\n   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream.ReadAsyncInternal(Memory`1 buffer, CancellationToken cancellationToken)\r\n   at Microsoft.AspNetCore.WebUtilities.FileBufferingReadStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)\r\n   at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.DrainAsync(Stream stream, ArrayPool`1 bytePool, Nullable`1 limit, CancellationToken cancellationToken)\r\n   at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonInputFormatter.ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)\r\n   at Microsoft.AspNetCore.Mvc.ModelBinding.Binders.BodyModelBinder.BindModelAsync(ModelBindingContext bindingContext)\r\n   at Microsoft.AspNetCore.Mvc.ModelBinding.ParameterBinder.BindModelAsync(ActionContext actionContext, IModelBinder modelBinder, IValueProvider valueProvider, ParameterDescriptor parameter, ModelMetadata metadata, Object value)\r\n   at Microsoft.AspNetCore.Mvc.Controllers.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ExceptionContextSealed context)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)\r\n   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)\r\n
    [HttpPost]
    [ProducesResponseType(typeof(BaseResponse<bool>), 1)]
    public async Task<BaseResponse> SyncMsg()
    {

        string data = string.Empty;
        try
        {
            using (var sr = new StreamReader( Request.Body))
            {
                data = await sr.ReadToEndAsync();

                //todo: lenth more then 1024, Decompress
                data = StringHandleHelper.Decompress(data);

                var url = ConfigurationManager.GetValue("CallBackUrl");

pragma warning تعطيل CS4014 // بما أن هذه المكالمة لن تنتظر ، سيستمر تنفيذ الطريقة الحالية قبل اكتمال المكالمة

                Task.Factory.StartNew((obj) =>
                {
                     _messageService.SyncMsg((string)obj, url);
                }, data);

pragma تحذير استعادة CS4014 // نظرًا لأن هذه المكالمة لن تنتظر ، سيستمر تنفيذ الطريقة الحالية قبل اكتمال المكالمة

                var j_data = JToken.Parse(data);
                var type = j_data["type"].ToObject<PcWxMsgType>();
                var wxid = j_data["wxid"].ToObject<string>();

                return Response2WeChatRobot(wxid, type);
            }
        }
        catch (Exception ex)
        {
            return new BaseResponse() { Code = -2, Msg = "站点:" + ex.Message };
        }
    }

أنا

لقد شاهدت كل المناقشات ، هل يوجد حل فعال الآن

هل سيتم إصلاح هذا في الإصدار القادم؟

تحية للجميع،
نحن نبدأ مشروعًا جديدًا يتضمن حفظ webhooks مرة أخرى في قاعدة البيانات لمزيد من المعالجة.
نتوقع حمولات صغيرة ولكن عددًا كبيرًا من الطلبات.

هل الكود التالي هو الأمثل؟

[HttpPost]
        public async Task<OkResult> Webhook()
        {
            var body = await new HttpRequestStreamReader(Request.Body, Encoding.UTF8).ReadToEndAsync();
            //save to Db asynchronously?
            return Ok();
        }

@ clement911 إذا كان الانتقال إلى معالجة قاعدة البيانات أولاً سيحل مشكلة ReadToEndAsync؟

أم أنك حاولت استخدام فئة منظمة بدلاً من قراءة الكائن من Stream بدلاً من ذلك؟

حسنًا ، لقد بدأت في قراءة هذا الموضوع منذ ساعة وأنا أسمع في النهاية لم أحصل على حل. ما هو الحل الآن لـ .NEt 3.1 ، لدي نفس المشكلة

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

Gopichandar صادفت هذا وحل المشكلة على النحو التالي

  • المنكسر في معظم الطرق باستخدام نمط () await + Async Task method ()

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

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

القصة الأطول:
تم إجراء بضعة ملايين من مكالمات PUT إلى خوادمنا وفشل حوالي 0،08٪ منها أيضًا بعد عدة محاولات لإعادة المحاولة - كانت جميعها تحتوي على نفس الرسالة على جانب الخادم: “Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate” . من المؤكد أن الخادم لم يكن خاملاً أثناء المكالمات العديدة. لكن في اليوم التالي كان الخادم خاملاً تقريبًا ، وتمكنت من تلقي المكالمات الفاشلة وإعادة تنفيذها كطلب واحد في ذلك الوقت. لدهشتي الكبيرة كان من الثابت أن الحمولة فشلت وما زلت أرى نفس رسالة الخطأ في سجلات الخادم لدينا.
حاول أيضًا زيادة المهلة ، لإعطاء الخادم وقتًا للعثور على سلسلة رسائل مجانية ، ولكن لا تزال نفس الأخطاء بعد 10 ثوانٍ ، بدلاً من 5 ثوانٍ الافتراضية:
options.Limits.MinRequestBodyDataRate = new MinDataRate(120, TimeSpan.FromSeconds(10))

بعد ساعات من التحقيق اكتشفت أن هناك شيئان يمكنني تغييرهما لإنجاح المكالمة:
1) افصل Ciso VPN.
تقسم VPN الحمولة إلى حزم TCP أصغر (هنا 5 حزم). إنها دائمًا الحزمة الأخيرة التي يجب إعادة إرسالها. انظر الصورة ، “.135” هو جهاز الكمبيوتر الخاص بي و “.57” هو الخادم. (عند قطع الاتصال بشبكة VPN ، سترسل الحمولة في حزمة TCP واحدة). كان متصلاً أيضًا بشبكة VPN عند إجراء بضعة ملايين من المكالمات.
image

2) تغيير حجم الحمولة بمقدار 1 بايت - إما إضافة أو إزالة حرف واحد إلى حمولة json (خارج الدورة التدريبية في حقل لم يتم تحليله على جانب الخادم)
لا تزال الحمولة مقسمة إلى 5 حزم TCP - بسبب الاتصال بشبكة VPN.

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

لا أعتقد أنها مشكلة في تجمع مؤشرات الترابط من جانب الخادم ، نظرًا لأنني قادر على إعادة إنتاجها مرارًا وتكرارًا ويمكن أن يؤثر تغيير 1 بايت في حجم الحمولة على النتيجة. وفي اليوم الآخر ، تعامل الخادم مع المزيد من الطلبات.

لقد رأيت رسالة الخطأ “Reading the request body timed out due to data arriving too slowly. See MinRequestBodyDataRate” على كل من طلب التوجيهات باستخدام نموذج أساسي بسيط لـ aspnet Binding [FromBody] ، والمسارات التي تقرأ النص نفسه await Request.Body.ReadAsBytesAsync() .

لذا فإن السؤال هو ، ما الذي يمكن أن يسبب هذه المشكلة في aspnetcore؟ وكيف أشارك المزيد من البيانات معكم يا رفاق؟

يبدو أنني وجدت حلاً حتى يتم إصلاح ذلك.
عانيت من نفس المشكلات مثل @ rasmus-s. استمر في العمل حتى تم تقسيم حزم TCP إلى حزم منفصلة ، والتي (بالنسبة لي) كانت بالضبط 1398 بايت. عند إضافة الحمل ، يكون هذا قريبًا بشكل غريب من 1500 بايت لإطار إيثرنت.
بعد إجراء بعض الأبحاث ، وجدت منشورًا اقترح فيه شخص ما التحقق من حجم MTU ، وهو ما فعلته بـ ping ip -f -l xxx . بالتأكيد ، أعاد -l 1473 الرسالة Packet needs to be fragmented but DF set ، لذا يبدو أن 1472 هو الحد الذي لا يتم فيه تقسيم الحزم وحيث لا يحدث الاستثناء.
لمقارنة نتيجتي بشيء آخر ، قفزت على نظام يعمل فيه بشكل جيد وقمت بتشغيل هذا الأمر مرة أخرى - هذه المرة لم يتم إرجاع Packet needs to be fragmented but DF set . حتى أنني استخدمت -l 65500 وهو الحد الأقصى - لا توجد رسالة.
في الواقع يبدو أن MTU هي المشكلة هنا.

سوف أقوم بتغيير MTU للنظام الأول حيث لا يعمل وسأبقي هذا محدثًا.

  • يبدو أن الإطارات الجامبو هي الحل. سأقوم بنشر تحديث بمجرد التحقق من ذلك.
هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات