Service Fabric 上具有 CORS 的 Asp.net Core API 100% CPU 瓶颈

Fra*_*llo 6 azure-service-fabric asp.net-core asp.net-core-middleware asp.net-core-webapi

我在.Net Framework 4.5.2上有一个 ASP.net Core,作为无状态服务托管在 Service Fabric 上。

该 API 是一个普通 API,空的

 [Route("Test")]
public class TestController : Controller
{
    [HttpGet]
    public IActionResult Get()
    {
        return Ok("Done");
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的启动代码

  public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
            .AddEnvironmentVariables();

        Configuration = builder.Build();
    }
    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials());
        });

        services.AddResponseCompression();

        services.AddMvc().AddJsonOptions(opts =>
        {
            // Force Camel Case to JSON
            opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
        });

    }


    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        app.UseCors("CorsPolicy");
        app.UseResponseCompression();
        app.UseMvc();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是 OpenAsync 方法:

  Task<string> ICommunicationListener.OpenAsync(CancellationToken cancellationToken)
        {
            var endpoint = FabricRuntime.GetActivationContext().GetEndpoint(_endpointName);
            string serverUrl = $"{endpoint.Protocol}://{FabricRuntime.GetNodeContext().IPAddressOrFQDN}:{endpoint.Port}";

            //.UseWebListener()
            _webHost = new WebHostBuilder().UseKestrel()
                                           .UseContentRoot(Directory.GetCurrentDirectory())
                                           .UseStartup<Startup>()
                                           .UseUrls(serverUrl)
                                           .Build();

            _webHost.Start();

            return Task.FromResult(serverUrl);
        }
Run Code Online (Sandbox Code Playgroud)

一切都简单明了,没有定制。CORS 调用有效,一切都很完美。我使用 Visual Studio Team Services 进行了一次测试,负载为 15K 用户,一切都非常顺利,RPS 为 14K。顺便说一句,我认为 VS 的负载测试不使用 CORS 中间件。

现在的问题是,当我将这个完全空的 API投入生产时,仅接收来自大约100 个并发用户的调用,CPU 在 3 分钟内跃升至 100%。呼叫会得到应答,直到 CPU 达到 100%,然后开始发回错误。似乎在 15000 个用户且没有 CORS 的情况下一切正常,而在 100 个用户 + CORS 不起作用的情况下,CPU 会达到 100%,并保持这种状态,直到我重新启动 VM 规模集。

中央处理器

如果我停止发送呼叫,5个节点的CPU保持稳定在99%,没有收到任何呼叫。

这怎么可能? 我尝试了一切,该项目简单明了,VS 负载测试有效,只有当我将其放在来自不同站点和不同 IP 地址的真实 CORS 调用上时,才会发生这种情况。

在向服务器发送流量之前,我在服务器中进行了性能跟踪,再次使用 Visual Studio 使用 CORS 标头进行负载测试,一切都非常快。

对于现实世界的调用,这是我在分析器中看到的:

痕迹

除了 CORS 中间件和常用的 Kestrel 进程之外,什么都没有。无状态服务占用了 99% 的 CPU,即使我停止流量也会保留它。

这是另一个 30 秒的跟踪,没有流量到来,但 CPU 利用率为 90%

在此输入图像描述

我不知道还能做什么,CORS 有问题,我确信,即使它有效,不知何故出了问题。

这是一个 CORS 调用,已正确处理。

科尔斯呼叫

Asp.net Core CORS 中间件是否存在错误?

更新:

我尝试了多种组合来隔离问题:

  1. 新集群,相同的 Asp.net Core vanilla 服务 => 问题仍然存在

  2. 相同的集群新项目相同的 Asp.net Core vanilla 服务 => 问题仍然存在

  3. 相同的 Cluster WebAPI OWIN 服务,相同的代码 =>问题消失了!

Service Fabric 上的 Asp.Net Core 使用 CORS 且并发请求超过 50 个时会出现此问题。

这是使用 Visual Studio 模板、OWIN 和 CORS 的 Asp.Net 无状态服务的 CPU (0.85%),具有大约 100 个并发连接和上面相同的空 Web API

欧文

此时我需要微软官方的帮助来解决这个问题。我几乎可以肯定这是一个Asp.net Core CORS 错误,当您将其作为无状态服务托管在 Service Fabric 上并向其发送一些最小流量(而不仅仅是浏览器中的几次刷新)时,就会发生这种情况。