登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go教程

Go runtime/metrics 怎样读取运行时指标样本

来源:17golang原创

时间:2026-10-21 20:18:46 169浏览 收藏

读取 Go 运行时指标样本,要先用 metrics.All()取得描述符,再把需要的名称填入 []metrics.Sample,调用 metrics.Read,最后根据 Value.Kind()选择读取方法。不要把所有指标都当成 uint64,也不要把不支持的指标当成数值零。

设想一个报表服务准备升级工具链:原来只记录内存数字,现在还要观察调度等待分布。问题不只是加一个名称,而是采集器能否识别不同类型,以及下一次读取是否会覆盖前一次保留的直方图。下面只解决描述符、样本类型与读取,不扩展成监控平台部署教程。

官方文档:https://pkg.go.dev/runtime/metrics

升级工具链前先发现支持的指标

API 接口稳定不等于每个 Go 实现、每个版本都有完全相同的指标集合。迁移时先依据实际进程支持的描述符选择名称,而不是复制另一台机器的整份清单。

旧采集假设迁移后的处理
名字存在就有值先在 All 返回集合中匹配完整名称
数字都用 Uint64 读取按照 Value.Kind 分派
保存 Value 就保存了快照直方图数据需要独立复制

Description 包含 Name、Description、Kind 和 Cumulative。Name 的单位后缀属于标识的一部分,不能删掉后再匹配;Kind 指明表示类型,Cumulative 提醒你是否应把它视为累计量。图中的“指标目录”是 All 与 Description,“字段定义”是 Name、Kind、Cumulative;它们是目录和字段的组成关系。

指标目录和描述符字段的组成关系
图1:指标描述符结构说明图。分组区分目录与字段,连线表示包含关系,不是执行流程或采样结果。

把描述符转换为可读取的样本

以 goroutine 数量和调度延迟分布为例,下面程序先求所需名称与支持集合的交集,未找到的名称明确记录为不支持。保存为 main.go,使用包含 runtime/metrics 的 Go 工具链;程序不依赖第三方包。

package main

import (
    "fmt"
    "runtime"
    "runtime/metrics"
)

func main() {
    wanted := []string{
        "/sched/goroutines:goroutines",
        "/sched/latencies:seconds",
    }
    supported := make(map[string]metrics.Description)
    for _, d := range metrics.All() {
        supported[d.Name] = d // 完整名称包含单位后缀
    }

    samples := make([]metrics.Sample, 0, len(wanted))
    for _, name := range wanted {
        d, ok := supported[name]
        if !ok {
            fmt.Printf("不支持: %s\n", name)
            continue
        }
        fmt.Printf("指标=%s 类型=%v 累计=%t\n", name, d.Kind, d.Cumulative)
        samples = append(samples, metrics.Sample{Name: name})
    }
    fmt.Println("工具链:", runtime.Version())
    metrics.Read(samples) // 原地填充各样本的 Value

    for _, s := range samples {
        switch s.Value.Kind() {
        case metrics.KindUint64:
            fmt.Printf("%s 数值=%d\n", s.Name, s.Value.Uint64())
        case metrics.KindFloat64:
            fmt.Printf("%s 数值=%g\n", s.Name, s.Value.Float64())
        case metrics.KindFloat64Histogram:
            h := s.Value.Float64Histogram()
            fmt.Printf("%s 桶数=%d 边界数=%d\n", s.Name, len(h.Counts), len(h.Buckets))
        case metrics.KindBad:
            fmt.Printf("%s 不可用\n", s.Name) // 不能记作零值
        default:
            fmt.Printf("%s 未处理类型=%v\n", s.Name, s.Value.Kind())
        }
    }
}

代码展示的是读取方式,不给出伪造的运行数字。读者执行后应看到受支持名称的类型说明和各自对应的数据形式;实际数量、桶数和样本值取决于运行环境。采样一次并不能推出服务是否异常。

读取结果必须按 Kind 分派

Uint64、Float64 和 Float64Histogram 不是任意可互换的转换函数,调用与类型不符的访问器会 panic。即使当前选择的两个指标类型已知,保留 switch 仍能把采集器对类型的假设写清楚。

直方图包含 Counts 与 Buckets:第 i 个计数对应区间 [Buckets[i], Buckets[i+1]),边界数比桶数多一。它不是“边界值对应的精确样本列表”,不能直接把某个边界打印成真实 P99。本文仅读取结构,不实现分位数估算。

Sample 包含 Name 与 Value,Value 的 Kind 决定读取类型;对于直方图,Value 关联 Float64Histogram,后者包含 Counts、Buckets。图中的“样本容器”“类型数据”按这六个实体分组说明。

样本值与直方图计数边界的静态关系
图2:指标值结构说明图。Counts 和 Buckets 是直方图组成,不是两个独立指标;连线不暗示读取先后或运行结果。

复用样本时怎样保留独立快照

重复使用同一 samples 切片可减少重复准备,但 Read 正在写入时,其他 goroutine 不应读取或修改关联值。直方图底层存储还可能被后续 Read 复用;只复制 Sample 或保存直方图指针并不能保证独立。

下面是独立复制函数,放在导入 runtime/metrics 的文件中。应在没有并发 Read 的受控位置调用,再把副本交给消费者;复制过程本身不是同步手段。

// 在采样器独占样本时调用,复制两组底层数据
func copyHistogram(h *metrics.Float64Histogram) *metrics.Float64Histogram {
    if h == nil {
        return nil
    }
    return &metrics.Float64Histogram{
        Counts: append([]uint64(nil), h.Counts...),
        Buckets: append([]float64(nil), h.Buckets...),
    }
}

一种简单所有权安排是由单个采样 goroutine 管理 samples,在两次 Read 之间提取标量、深拷贝直方图,再通过通道传递自有记录。不要把原始 Value 指针交出去后立刻复用切片,也不要为了避开复制而让消费者无锁读取正在更新的桶计数。

升级前后需要对比什么

迁移清单包括:实际工具链版本、完整指标名称、描述文字、Kind、Cumulative,以及你自己的缺失指标策略。可选指标缺失可以跳过并报告;核心指标缺失是否阻止服务启动由业务明确决定,不能静默填零。

比较累计量时还需注意进程是否重启。累计值是总量,不是当前速率;不同进程直接相减没有意义。直方图差分还需确认两份边界一致,不能仅按相同下标把不同版本的桶相减。采集开销应在真实采样频率下测量,不承诺所有读取都零分配或没有影响。

Read 有错误返回值吗?

没有。单个值的不可用状态通过 KindBad 表达,因此不能靠 err 判断这次选择的所有名称都有效。

能用它查看另一进程吗?

它读取当前 Go 进程的运行时指标,不是操作系统的远程进程查询接口。若需外部访问,要另行设计导出机制和访问边界。

一次 Read 能当作整个系统的严格同时刻快照吗?

不要作这种假设。它用于批量采集所选指标,不应据此宣称所有互不相关指标都形成全局事务快照。

最终应交付一份能发现、分派和保留样本的采集器,而不是固定写死数值类型的指标名称列表。参考:runtime/metrics 文档、Go 官方采样接口源码。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>