健康检查端点需显式注册AddHealthChecks()并启用UseHealthChecks中间件,否则/health返回404或500;并发监控须自定义检查逻辑,推荐用Degraded标识过载,生产环境须配置ResponseWriter过滤敏感信息并禁用异常详情。

健康检查端点必须注册 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 对齐,而不是拍脑袋定。










