导读:本期聚焦于小伙伴创作的《c# 在高并发服务中,如何做优雅停机(Graceful Shutdown)》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《c# 在高并发服务中,如何做优雅停机(Graceful Shutdown)》有用,将其分享出去将是对创作者最好的鼓励。

在高并发服务运行过程中,直接终止进程会导致大量正在处理的请求被中断,数据库连接、缓存连接等资源没有正常释放,甚至会造成数据不一致的问题。c#实现优雅停机需要结合服务生命周期管理,在接收到停机信号后,先停止接收新的请求,等待现有请求处理完成,再释放相关资源后退出进程。

c# 在高并发服务中,如何做优雅停机(Graceful Shutdown)

优雅停机核心流程

完整的优雅停机需要遵循以下四个步骤:

  • 监听系统停机信号,比如Linux的SIGTERM、Windows的进程停止命令
  • 停止接收新的外部请求,避免新请求进入处理队列
  • 等待正在处理的请求全部完成,设置合理的等待超时时间
  • 释放占用的资源,比如数据库连接、消息队列连接、文件句柄等,最后退出进程

ASP.NET Core中的优雅停机实现

ASP.NET Core内置了应用生命周期管理接口IHostApplicationLifetime,可以方便地监听应用启动和停止事件,结合请求处理控制实现优雅停机。

基础配置示例

首先在Program.cs中配置服务的停机相关参数,设置请求处理超时时间:

using Microsoft.AspNetCore.Server.Kestrel.Core;

var builder = WebApplication.CreateBuilder(args);

// 配置Kestrel服务器,设置停机时等待请求完成的超时时间
builder.WebHost.ConfigureKestrel(options =>
{
    // 优雅停机等待时间,单位秒,这里设置为30秒
    options.Limits.MaxRequestBodySize = 1024 * 1024 * 10;
});

// 注册应用生命周期事件
builder.Services.AddSingleton<IHostedService, GracefulShutdownService>();

var app = builder.Build();

// 模拟一个高并发处理的接口
app.MapGet("/process", async (HttpContext context) =>
{
    // 模拟请求处理耗时,最长5秒
    var random = new Random();
    var delay = random.Next(1000, 5000);
    await Task.Delay(delay);
    return Results.Ok($"请求处理完成,耗时{delay}毫秒");
});

app.Run();

自定义优雅停机服务

通过实现IHostedService接口,自定义停机时的处理逻辑:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

public class GracefulShutdownService : IHostedService
{
    private readonly IHostApplicationLifetime _appLifetime;
    private readonly ILogger<GracefulShutdownService> _logger;
    // 用于标记是否已经开始停机流程
    private bool _isShuttingDown = false;
    // 正在处理的请求计数
    private int _processingRequestCount = 0;

    public GracefulShutdownService(IHostApplicationLifetime appLifetime, ILogger<GracefulShutdownService> logger)
    {
        _appLifetime = appLifetime;
        _logger = logger;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        // 监听应用停止事件
        _appLifetime.ApplicationStopping.Register(OnStopping);
        _logger.LogInformation("优雅停机服务启动");
        return Task.CompletedTask;
    }

    private void OnStopping()
    {
        if (_isShuttingDown)
        {
            return;
        }
        _isShuttingDown = true;
        _logger.LogInformation("开始执行优雅停机流程,停止接收新请求");

        // 等待正在处理的请求完成,最多等待30秒
        var maxWaitTime = TimeSpan.FromSeconds(30);
        var startTime = DateTime.Now;
        while (_processingRequestCount > 0 && (DateTime.Now - startTime) < maxWaitTime)
        {
            Thread.Sleep(100);
        }

        if (_processingRequestCount > 0)
        {
            _logger.LogWarning($"优雅停机超时,仍有{_processingRequestCount}个请求未完成,强制退出");
        }
        else
        {
            _logger.LogInformation("所有请求处理完成,准备释放资源");
        }

        // 这里可以添加释放资源的逻辑,比如关闭数据库连接、断开消息队列连接等
        ReleaseResources();
        _logger.LogInformation("资源释放完成,应用即将退出");
    }

    private void ReleaseResources()
    {
        // 示例:释放数据库连接、缓存连接等资源
        // DbContext.Dispose();
        // RedisConnection.Close();
    }

    // 请求进入时增加计数,请求完成时减少计数,需要在中间件中调用
    public void IncrementRequestCount()
    {
        if (!_isShuttingDown)
        {
            Interlocked.Increment(ref _processingRequestCount);
        }
    }

    public void DecrementRequestCount()
    {
        Interlocked.Decrement(ref _processingRequestCount);
    }

    public bool IsShuttingDown => _isShuttingDown;

    public Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("优雅停机服务停止");
        return Task.CompletedTask;
    }
}

请求计数中间件

添加中间件来统计正在处理的请求数量,配合停机服务使用:

using Microsoft.AspNetCore.Http;

public class RequestCountMiddleware
{
    private readonly RequestDelegate _next;
    private readonly GracefulShutdownService _shutdownService;

    public RequestCountMiddleware(RequestDelegate next, GracefulShutdownService shutdownService)
    {
        _next = next;
        _shutdownService = shutdownService;
    }

    public async Task InvokeAsync(HttpContext context)
    {
        // 如果已经开始停机,直接返回服务不可用
        if (_shutdownService.IsShuttingDown)
        {
            context.Response.StatusCode = 503;
            await context.Response.WriteAsync("服务正在停机维护,请稍后重试");
            return;
        }

        // 增加请求计数
        _shutdownService.IncrementRequestCount();
        try
        {
            await _next(context);
        }
        finally
        {
            // 请求处理完成后减少计数
            _shutdownService.DecrementRequestCount();
        }
    }
}

// 中间件扩展方法
public static class RequestCountMiddlewareExtensions
{
    public static IApplicationBuilder UseRequestCount(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<RequestCountMiddleware>();
    }
}

在Program.cs中注册该中间件,注意要放在路由配置之前:

// 注册中间件
app.UseRequestCount();

// 之前的路由配置
app.MapGet("/process", async (HttpContext context) =>
{
    var random = new Random();
    var delay = random.Next(1000, 5000);
    await Task.Delay(delay);
    return Results.Ok($"请求处理完成,耗时{delay}毫秒");
});

通用控制台程序的优雅停机实现

如果是非ASP.NET Core的c#控制台高并发服务,可以通过监听系统信号实现优雅停机:

using System.Runtime.InteropServices;

class Program
{
    private static bool _isShuttingDown = false;
    private static int _processingTaskCount = 0;
    private static readonly object _lockObj = new object();

    static void Main(string[] args)
    {
        // 监听Linux SIGTERM信号
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
        {
            AppDomain.CurrentDomain.ProcessExit += (s, e) =>
            {
                StartGracefulShutdown();
            };
        }
        // 监听Windows控制台关闭事件
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            SetConsoleCtrlHandler(ConsoleCtrlHandler, true);
        }

        // 启动工作线程模拟高并发任务处理
        StartWorkerThreads();

        // 等待停机信号
        Console.WriteLine("服务启动完成,按Ctrl+C停止");
        Console.ReadLine();
    }

    // Windows控制台事件处理
    [DllImport("Kernel32")]
    private static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool add);
    private delegate bool HandlerRoutine(int dwControlType);
    private static bool ConsoleCtrlHandler(int dwControlType)
    {
        if (dwControlType == 2) // CTRL_CLOSE_EVENT
        {
            StartGracefulShutdown();
        }
        return false;
    }

    private static void StartGracefulShutdown()
    {
        if (_isShuttingDown)
        {
            return;
        }
        _isShuttingDown = true;
        Console.WriteLine("开始执行优雅停机流程");

        // 等待所有任务完成,最多等待30秒
        var maxWaitTime = TimeSpan.FromSeconds(30);
        var startTime = DateTime.Now;
        while (_processingTaskCount > 0 && (DateTime.Now - startTime) < maxWaitTime)
        {
            Thread.Sleep(100);
        }

        if (_processingTaskCount > 0)
        {
            Console.WriteLine($"优雅停机超时,仍有{_processingTaskCount}个任务未完成");
        }
        else
        {
            Console.WriteLine("所有任务处理完成,准备退出");
        }

        // 释放资源
        ReleaseResources();
        Console.WriteLine("服务已停止");
        Environment.Exit(0);
    }

    private static void ReleaseResources()
    {
        // 释放相关资源
    }

    private static void StartWorkerThreads()
    {
        for (int i = 0; i < 10; i++)
        {
            var threadId = i;
            Task.Run(() =>
            {
                while (!_isShuttingDown)
                {
                    // 模拟任务处理
                    Interlocked.Increment(ref _processingTaskCount);
                    try
                    {
                        var delay = new Random().Next(1000, 3000);
                        Thread.Sleep(delay);
                        Console.WriteLine($"线程{threadId}处理完成一个任务");
                    }
                    finally
                    {
                        Interlocked.Decrement(ref _processingTaskCount);
                    }
                }
            });
        }
    }
}

注意事项

  • 停机等待时间需要结合业务实际设置,既不能太短导致请求未完成就被中断,也不能太长导致停机耗时过久
  • 如果使用了负载均衡,在停机前可以先从负载均衡列表中摘除该节点,避免新请求继续转发过来
  • 资源释放逻辑需要根据实际使用的组件调整,确保所有占用的资源都能被正确回收
  • 测试时需要模拟高并发场景,验证停机过程中没有请求丢失,资源都能正常释放

C#Graceful_Shutdown高并发ASP.NET_Core修改时间:2026-07-11 02:54:15

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。