Kestrel накапливает входящие одновременные запросы и не читает их, пока все не будут собраны - PullRequest
0 голосов
/ 18 сентября 2018

У меня есть требование обработать до 5000 за 10 секунд.Проблема в том, что где-то в Кестреле есть узкое место.Чем больше у меня одновременных клиентских запросов, тем больше задержка при чтении тела первого запроса.Приложение для минималистической тестовой консоли приведено ниже:

public interface IMyHandler
{
    Func<HttpContext, string> Handler { get; set; }
}

public class MyHandler : IMyHandler
{
    public Func<HttpContext, string> Handler { get; set; }
}

public class Startup : IStartup
{
    IMyHandler MyHandler;
    public Startup(IMyHandler h)
    {
        MyHandler = h;
    }

    public void Configure(IApplicationBuilder app)
    {
        var this_ = this;
        app.Run(context =>
        {
            MyHandler.Handler(context);
            var response = String.Format("Hello, Universe! It is {0}", DateTime.Now);
            return context.Response.WriteAsync(response);
        });
    }

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        // Add framework services
        return services.BuildServiceProvider();
    }
}

class Program
{
    static void Main(string[] args)
    {
        EventWaitHandle success = new AutoResetEvent(false);
        var sentRequests = 0;
        var serverTask = Task.Run(() =>
        {

            MyHandler h1 = new MyHandler();
            h1.Handler = (context) =>
            {
                using (BufferedStream buffer = new BufferedStream(context.Request.Body))
                {
                    using (var reader = new StreamReader(buffer))
                    {
                        var body = reader.ReadToEnd();
                        var _sent = sentRequests;
                        //success.Set();
                    }
                }
                return "OK";
            };

            var host = new WebHostBuilder()
                .UseKestrel((context, options) =>
                {
                    //options.ApplicationSchedulingMode = SchedulingMode.Inline;
                    options.ListenAnyIP(21122, listenOptions =>
                    {
                    });
                })
                .UseContentRoot(Directory.GetCurrentDirectory())

                 .ConfigureServices(services =>
                 {
                     services.Add(Microsoft.Extensions.DependencyInjection.ServiceDescriptor.Singleton(typeof(IMyHandler), h1));
                 })
                //.UseIISIntegration()
                .UseStartup<Startup>()
                //.UseApplicationInsights()
                .Build();

            host.Run();
        });
        Enumerable.Range(0, 100).ForEach((n) => {
            var clientTask = Task.Run(async () =>
            {
                var handler = new HttpClientHandler();
                HttpClient client = new HttpClient(handler);
                sentRequests++;
                var p1 = await client.PostAsync("http://localhost:21122", new StringContent("{test:1}", Encoding.UTF8, "application/json"));
            });
        });

        Assert.IsTrue(success.WaitOne(new TimeSpan(0, 0, 50)));
    }
}

Для 100 запросов на выдачу у меня уже есть приблизительно 12 секунд задержки при чтении первого тела.Чтобы увидеть это, просто установите точку останова в строке

var _sent = sentRequests;

Также значение sentRequests равно 100, что означает (это на самом деле немного предположений, но кажется правдоподобным), что в этот момент все запросы отправляются.Для меня это выглядит так, как будто две вещи были выполнены одним потоком, и пока он принимает запросы, он не начинает их читать.

Есть идеи, как это преодолеть?

...