乘風破浪,遇見最佳跨平臺跨終端框架.Net Core/.Net生態 - 淺析ASP.NET Core內置全新跨平臺HTTP請求監聽器Kestrel

什麼是Kestrel

https://github.com/dotnet/aspnetcore

Kestrel是一個跨平臺的適用於Kestrel

image

Kestrel是包含在ASP.NET Core項目模板中的Web服務器,默認處於啓用狀態。

Kestrel支持以下方案:

  • HTTPS
  • HTTP/2(在macOS†上除外)
  • 用於啓用WebSocket的不透明升級
  • 用於獲得Nginx高性能的Unix套接字

macOS的未來版本將支持HTTP/2。

.NET Core支持的所有平臺和版本均支持Kestrel。

默認啓用

未使用IIS託管時,ASP.NET Core項目模板默認使用Kestrel。在下面的模板生成的Program.cs中,WebApplication.CreateBuilder方法在內部調用UseKestrel

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}
//
// 摘要:
//     Extension methods for configuring the IWebHostBuilder.
public static class GenericHostBuilderExtensions
{
    //
    // 摘要:
    //     Initializes a new instance of the Microsoft.AspNetCore.Hosting.IWebHostBuilder
    //     class with pre-configured defaults.
    //
    // 參數:
    //   builder:
    //     The Microsoft.Extensions.Hosting.IHostBuilder instance to configure
    //
    //   configure:
    //     The configure callback
    //
    // 返回結果:
    //     The Microsoft.Extensions.Hosting.IHostBuilder for chaining.
    //
    // 言論:
    //     The following defaults are applied to the Microsoft.AspNetCore.Hosting.IWebHostBuilder:
    //     use Kestrel as the web server and configure it using the application's configuration
    //     providers, adds the HostFiltering middleware, adds the ForwardedHeaders middleware
    //     if ASPNETCORE_FORWARDEDHEADERS_ENABLED=true, and enable IIS integration.
    public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder, Action<IWebHostBuilder> configure);
}

WebApplication.CreateBuilder的UseKestrel

internal static void ConfigureWebDefaults(IWebHostBuilder builder)
{
    builder.ConfigureAppConfiguration((ctx, cb) =>
    {
        if (ctx.HostingEnvironment.IsDevelopment())
        {
            StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration);
        }
    });
    builder.UseKestrel((builderContext, options) =>
    {
        options.Configure(builderContext.Configuration.GetSection("Kestrel"), reloadOnChange: true);
    })
    .ConfigureServices((hostingContext, services) =>
    {
        // Fallback
        services.PostConfigure<HostFilteringOptions>(options =>
        {
            if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
            {
                // "AllowedHosts": "localhost;127.0.0.1;[::1]"
                var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
                // Fall back to "*" to disable.
                options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
            }
        });
        // Change notification
        services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
                    new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));

        services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();
        services.AddTransient<IStartupFilter, ForwardedHeadersStartupFilter>();
        services.AddTransient<IConfigureOptions<ForwardedHeadersOptions>, ForwardedHeadersOptionsSetup>();

        services.AddRouting();
    })
    .UseIIS()
    .UseIISIntegration();
}

一般限制

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel
            });
            webBuilder.UseStartup<Startup>();
        });
{
  "Kestrel": {
    "Limits": {
      "MaxConcurrentConnections": 100,
      "MaxConcurrentUpgradedConnections": 100
    },
    "DisableStringReuse": true
  }
}

保持活動狀態超時

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 保持活動狀態超時
                kestrelServerOptions.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
            });
            webBuilder.UseStartup<Startup>();
        });

客戶端最大連接數

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 設置最大打開的連接數
                kestrelServerOptions.Limits.MaxConcurrentConnections = 100;

                // 設置最大打開、升級的連接數,升級的連接是已從HTTP切換到另一個協議(如WebSocket)的連接
                kestrelServerOptions.Limits.MaxConcurrentUpgradedConnections = 100;
            });
            webBuilder.UseStartup<Startup>();
        });

請求正文最大大小

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 設置允許的請求正文的最大大小(以字節爲單位)
                kestrelServerOptions.Limits.MaxRequestBodySize = 100_000_000;
            });
            webBuilder.UseStartup<Startup>();
        });

請求正文最小數據速率

Kestrel每秒檢查一次數據是否以指定的速率(字節/秒)傳入。如果速率低於最小值,則連接超時。寬限期是Kestrel允許客戶端將其發送速率提升到最小值的時間量。在此期間不會檢查速率。寬限期有助於避免最初由於TCP慢啓動而以較慢速率發送數據的連接中斷。最小速率也適用於響應。

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 設置請求正文的最小數據速率(以字節/秒爲單位)
                kestrelServerOptions.Limits.MinRequestBodyDataRate = new MinDataRate(
                    bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));

                // 設置響應最小數據速率(以字節/秒爲單位)
                kestrelServerOptions.Limits.MinResponseDataRate = new MinDataRate(
                    bytesPerSecond: 100, gracePeriod: TimeSpan.FromSeconds(10));
            });
            webBuilder.UseStartup<Startup>();
        });

請求標頭超時

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 設置服務器接收請求頭所需的最大時間量
                kestrelServerOptions.Limits.RequestHeadersTimeout = TimeSpan.FromMinutes(1);
            });
            webBuilder.UseStartup<Startup>();
        });

HTTP/2限制

每個連接的最大流

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 限制每個HTTP/2 連接的併發請求流的數量(拒絕過多的流)
                kestrelServerOptions.Limits.Http2.MaxStreamsPerConnection = 100;
            });
            webBuilder.UseStartup<Startup>();
        });

標題表大小

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 限制了服務器上HPACK編碼器與解碼器可以使用的標頭壓縮表的大小(以八進制數表示)
                kestrelServerOptions.Limits.Http2.HeaderTableSize = 4096;
            });
            webBuilder.UseStartup<Startup>();
        });

最大幀大小

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 指示允許接收的最大幀有效負載的大小(以八進制數表示)
                kestrelServerOptions.Limits.Http2.MaxFrameSize = 16_384;
            });
            webBuilder.UseStartup<Startup>();
        });

最大請求標頭大小

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 指示請求頭字段序列的最大允許大小
                kestrelServerOptions.Limits.Http2.MaxRequestHeaderFieldSize = 8192;
            });
            webBuilder.UseStartup<Startup>();
        });

初始連接窗口大小

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 服務器一次願意接收和緩衝多少請求正文數據
                kestrelServerOptions.Limits.Http2.InitialConnectionWindowSize = 131_072;
            });
            webBuilder.UseStartup<Startup>();
        });

初始流窗口大小

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 服務器願意爲每個流一次接收和緩衝多少請求正文數據
                kestrelServerOptions.Limits.Http2.InitialStreamWindowSize = 98_304;
            });
            webBuilder.UseStartup<Startup>();
        });

保持活動ping配置

Kestrel可以配置爲向連接的客戶端發送HTTP/2 Ping。

HTTP/2 Ping有多種用途:

  • 使空閒連接保持活動狀態。某些客戶端和代理服務器會關閉空閒的連接。HTTP/2 Ping是對連接執行的活動,可防止空閒連接被關閉。
  • 關閉不正常的連接。服務器會關閉在配置的時間內客戶端未響應保持活動ping的連接。
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 配置ping間隔的TimeSpan。如果服務器在此時間段內沒有收到任何幀,則服務器會向客戶端發送保持活動ping。將此選項設置爲TimeSpan.MaxValue時,會禁用保持活動ping。
                kestrelServerOptions.Limits.Http2.KeepAlivePingDelay = TimeSpan.FromSeconds(30);

                // 配置ping超時的TimeSpan。如果服務器在此超時期間沒有收到任何幀(如響應ping),則連接將關閉。將此選項設置爲TimeSpan.MaxValue時,會禁用保持活動狀態超時。
                kestrelServerOptions.Limits.Http2.KeepAlivePingTimeout = TimeSpan.FromMinutes(1);
            });
            webBuilder.UseStartup<Startup>();
        });

同步I/O

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureKestrel(kestrelServerOptions =>
            {
                // 配置Kestrel

                // 控制是否允許對請求和響應使用同步I/O
                kestrelServerOptions.AllowSynchronousIO = true;
            });
            webBuilder.UseStartup<Startup>();
        });

大量阻止同步I/O的操作可能會導致線程池資源不足,進而導致應用無響應。僅在使用不支持異步I/O的庫時,才啓用AllowSynchronousIO

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章