c# 如何在 ASP.NET Core 中实现健康检查端点来监控并发服务

来源:这里教程网 时间:2026-02-21 17:37:14 作者:

健康检查端点必须注册
AddHealthChecks()
且启用中间件

ASP.NET Core 健康检查不是开箱即用的,漏掉任一环节都会导致

/health
返回 404 或 500。你需要显式注册服务并挂载中间件:

Program.cs
中调用
builder.Services.AddHealthChecks()
—— 否则所有检查器(包括内置的)都不会被注入
app.UseHealthChecks("/health")
之前,不能有
app.UseRouting()
之后的其他终结点(如
app.MapControllers()
)提前拦截请求
若使用
UseEndpoints
(旧版),需确保
endpoints.MapHealthChecks
MapControllers
之前

并发服务检查要用
AddCheck()
自定义逻辑,不能只依赖
AddSqlServer()
等内置检查

内置检查(如数据库、Redis)只验证连接通断,不反映服务当前并发压力。要监控“并发服务能力”,得自己写检查逻辑,比如:

检查线程池队列长度是否超过阈值:
ThreadPool.GetAvailableThreads(out _, out int availableIO)
统计当前正在处理的 HTTP 请求数量(需配合
 IHttpContextAccessor 
和线程安全计数器)
读取自定义指标(如通过
IMemoryCache
缓存的最近 10 秒请求数)
注意:检查函数必须是同步或返回
Task
,且不能阻塞太长(默认超时 30 秒,可通过
timeout
参数调整)
builder.Services.AddHealthChecks()
    .AddCheck("concurrent-requests", async (ctx, ct) =>
    {
        var current = Interlocked.Read(ref _activeRequestCount);
        if (current > 200)
            return HealthCheckResult.Unhealthy($"Too many active requests: {current}");
        return HealthCheckResult.Healthy();
    });

HealthCheckResult.Degraded()
Unhealthy()
更适合并发过载场景

当并发接近瓶颈但尚未崩溃时,返回

Degraded
能让上游负载均衡器(如 Kubernetes、Nginx)触发告警或限流,而不是直接摘除实例:

Unhealthy
通常触发实例下线,可能加剧剩余节点压力
Degraded
保留服务入口,但标记为“能力下降”,适合用于熔断前的缓冲信号
Kubernetes 的
livenessProbe
默认只认
Healthy
/
Unhealthy
;若要用
Degraded
,需配
startupProbe
或自定义探针解析响应体中的
status
字段
响应体默认是 JSON,包含
status
Health
/
Unhealthy
/
Degraded
)、
results
和耗时,无需额外序列化

生产环境必须配置
ResponseWriter
并限制暴露敏感信息

默认响应会输出所有检查项的详细异常堆栈(如果检查失败),这属于信息泄露风险:

禁用详细错误:设置
includeExceptionDetails: false
(开发环境可设为
true
自定义响应体:用
responseWriter
参数过滤字段,例如只返回
status
和检查名,隐藏
data
exception
避免在检查中记录日志到控制台或文件——健康检查可能每秒被调用多次,容易打爆 I/O 不要在检查逻辑里调用外部 API(如调第三方鉴权服务),否则健康端点本身就成了故障放大器
app.UseHealthChecks("/health", new HealthCheckOptions
{
    ResponseWriter = async (ctx, result) =>
    {
        ctx.Response.ContentType = "application/json";
        var json = JsonSerializer.Serialize(new
        {
            status = result.Status.ToString(),
            checks = result.Entries.ToDictionary(
                e => e.Key,
                e => new { e.Value.Status, e.Value.Duration })
        });
        await ctx.Response.WriteAsync(json, Encoding.UTF8);
    },
    IncludeExceptionDetails = false
});
并发健康检查真正难的不是写代码,而是定义“过载”的业务含义——是 CPU > 90%?还是请求排队超 500ms?还是某个关键资源(如连接池)剩余不足 10%?这些阈值必须和你的服务 SLA 对齐,而不是拍脑袋定。

相关推荐