kratos 默认不提供qps和p99聚合结果,因metrics.server()仅注册原始计数器与预设bucket直方图,需prometheus通过rate()和histogram_quantile()计算,并配合withserverrequestlabels及细粒度bucket配置实现接口级指标。

直接回答:Kratos 本身不内置吞吐量(QPS)和 P99 耗时的聚合统计能力,必须依赖中间件 + 指标埋点 + Prometheus 采集链路来实现。光靠 kratos/middleware/metrics 默认配置只能拿到原始计数器/直方图,不聚合、不分位、不按接口维度切分。
为什么默认 metrics 中间件不显示 QPS 和 P99
Kratos 的 metrics.Server() 默认使用 prometheus 作为后端,它注册的是 http_server_requests_total 计数器和 http_server_request_duration_seconds 直方图——但直方图 bucket 是预设的(如 0.001s、0.01s、0.1s…),没有自动算出 P99;计数器也只累计总数,不带时间窗口,无法直接除出 QPS。
- QPS 需要 Prometheus 用
rate(http_server_requests_total[1m])计算每秒增量 - P99 需要 Prometheus 用
histogram_quantile(0.99, rate(http_server_request_duration_seconds_bucket[1m]))聚合直方图数据 - 默认直方图未按
route或method打标签,所有接口混在一起,查不出单个接口的 P99
如何让每个接口单独暴露 QPS 和 P99
关键在初始化 metrics 中间件时显式添加路由标签,并调整直方图 bucket 精度:
- 启用
WithServerRequestLabels,传入["method", "route", "status"]——其中route依赖你注册 handler 时用的 pattern,比如/v1/user/{id} - 自定义直方图 bucket:避免用默认的宽泛区间(如 10s),改用更细粒度,例如
[]float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5}(单位:秒),否则 P99 会卡在最大 bucket 值上,失去区分度 - 确保你的 HTTP Server 启用了
server.WithMetrics,且中间件顺序在路由解析之后(否则route标签为空)
srv := http.NewServer(
http.Middleware(
metrics.Server(
metrics.WithServerRequestLabels("method", "route", "status"),
metrics.WithServerDurationHistogramBuckets([]float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5}),
),
),
)
Prometheus 查询时容易漏掉的两个坑
即使指标打全了,PromQL 写错也会导致 QPS/P99 失真:
- 用
rate()时窗口不能小于采样间隔,也不能远大于服务典型响应周期。我们线上统一用[1m]:太短(如[10s])抖动大;太长(如[5m])掩盖突发毛刺 - 查 P99 必须用
histogram_quantile+rate,不能直接对_sum/_count做除法——那算出来是平均耗时,不是 P99 - 如果发现某接口 P99 显示为
5(即直方图最大 bucket),说明该接口大量请求超时,应检查是否 bucket 设置不合理,或服务本身已严重退化
要不要自己在代码里算 QPS/P99
不要。Kratos 的 metrics 是标准 Prometheus 客户端封装,所有聚合计算都该交给 Prometheus Server 完成。自行在进程内维护滑动窗口统计 QPS 或 P99:
- 会引入额外内存与锁开销,尤其高并发下影响 GC 和延迟稳定性
- 多实例部署时无法全局聚合,而 Prometheus 天然支持联邦与 remote_write
- 一旦需要调整统计口径(比如排除 5xx 请求),得改代码发版;PromQL 只需一行表达式即可重算
真正要动手的地方只有两处:中间件初始化时加对标签、Prometheus 配置里写对查询表达式。其余全是标准链路,别绕弯。











