当前位置:首页 > 文章列表 > Golang > Go教程 > Go 1.26 runtime/metrics 调度指标怎么选:runnable、waiting 与线程数的诊断边界

Go 1.26 runtime/metrics 调度指标怎么选:runnable、waiting 与线程数的诊断边界

来源:17golang原创 2026-09-04 01:32:46 0浏览 收藏

服务偶发变慢时,只看 runtime.NumGoroutine() 往往不够:它告诉你活着多少个 goroutine,却不能说明它们是在排队、等待 I/O,还是正在占用执行额度。Go 1.26 给 runtime/metrics 补上了这层运行时视角。排查时最有用的做法,是把 runnablewaitingrunningGOMAXPROCS、线程总量和创建总量放在同一组快照里看。

runnable 高更像“准备运行但还没轮到”,waiting 高更像“在等资源”,threads/total 反映运行时拥有的线程;它们都是近似或不同时间属性的信号,不能用任意一个数字直接判定故障。

要点速览
  • runnablewaitingrunning 是 goroutine 当前状态的近似计数。
  • /sched/gomaxprocs:threads 是同时执行用户级 Go 代码的额度,/sched/threads/total:threads 是运行时拥有的线程数。
  • /sched/goroutines-created:goroutines 是进程启动以来的累计创建量,适合看创建速度,不适合当作当前存量。

先把 Go 1.26 的调度指标分成三组

先记住三个维度。第一组是状态:/sched/goroutines/runnable:goroutines 表示已经准备执行但尚未执行的 goroutine,/sched/goroutines/waiting:goroutines 表示等待 I/O 或同步原语的 goroutine,/sched/goroutines/running:goroutines 表示正在执行的 goroutine。它们都是 approximate count,而且官方明确提醒它们不保证相加后等于全部 goroutine。

第二组是执行资源:/sched/gomaxprocs:threads 表示同时执行用户级 Go 代码的额度;/sched/threads/total:threads 则是当前由 Go runtime 拥有的存活线程数。两者名字都带 threads,但一个是并行执行上限,一个是线程存量,不能混读。

第三组是历史计数:/sched/goroutines-created:goroutines 只从进程启动开始累计创建量。它持续增长本身不等于泄漏,必须结合采样间隔计算增长速度,再对照 live goroutines。

Go 1.26 runtime metrics 中采样入口、goroutine 状态、执行额度与累计创建量的静态关系
图1:查看采样入口与三类调度指标的边界,区分当前状态、执行额度和进程启动以来的累计创建量。

用 runtime/metrics.Read 读取一组可诊断样本

runtime/metrics.Read 接收一组预先填好名称的 Sample。生产代码不要每次拼接指标名,也不要把不存在的指标当成零值;固定名称后检查 Value.Kind(),升级 Go 版本时更容易发现清单变化。

package main

import (
    "fmt"
    "runtime/metrics"
)

func main() {
    samples := []metrics.Sample{
        {Name: "/sched/goroutines/runnable:goroutines"},
        {Name: "/sched/goroutines/waiting:goroutines"},
        {Name: "/sched/goroutines/running:goroutines"},
        {Name: "/sched/gomaxprocs:threads"},
        {Name: "/sched/threads/total:threads"},
        {Name: "/sched/goroutines-created:goroutines"},
    }
    metrics.Read(samples)
    for _, sample := range samples {
        if sample.Value.Kind() != metrics.KindUint64 {
            fmt.Printf("%s: kind=%v\n", sample.Name, sample.Value.Kind())
            continue
        }
        fmt.Printf("%s = %d\n", sample.Name, sample.Value.Uint64())
    }
}

验证点很简单:输出名应与代码中的六个名称逐一对应,值类型应为 uint64。这段采样本身没有业务侵入,也不需要把整个 metrics.All() 列表暴露到监控系统。

Go runtime metrics Read 采样后将 runnable、waiting、running 与线程资源放入诊断判断边界
图2:对照当前状态、执行资源与累计计数三个分组,判断下一步是看排队、资源等待,还是 goroutine 创建速度。

把瞬时状态和累计计数放进同一张判断表

单次快照只适合回答“现在大概发生什么”。真正排查要看相邻两次采样。下面这张表是一个起点,阈值不要照抄到所有服务,先看自己的基线和采样间隔。

观察组合更接近的解释下一项检查
runnable 持续上升,running 接近 GOMAXPROCS可运行任务在排队,执行额度可能吃满看 CPU、调度延迟和热点调用
waiting 高,runnable大量 goroutine 在等 I/O 或同步资源看阻塞/互斥锁/网络调用的 pprof
threads/total 上升,GOMAXPROCS 不变线程存量变化,不等于并行额度变化结合 cgo、系统调用和线程画像判断
goroutines-created 增长很快,live goroutines 也长期抬高创建速度与回收速度可能失衡检查 goroutine 生命周期、取消和退出路径

这里有一个常见误区:waiting 高不一定是问题,连接池空闲等待、定时器和消费者阻塞都可能是正常状态;反过来,runnable 短时尖峰也可能只是流量突发。只有趋势与业务延迟、CPU 或资源耗尽同时出现,才值得升级为事故线索。

用连续采样确认趋势再决定排查方向

建议以 5 秒或 10 秒为间隔保存快照,至少保留一段稳定时段作为基线。每条记录同时写入进程启动时间、采样时间、服务实例和 Go 版本;不要只上报一个聚合后的 goroutine 数。对于 goroutines-created,用相邻样本差值除以时间间隔得到创建速率,重启后要重新标记计数归零。

runnable 与端到端延迟同步上扬,优先继续看调度延迟和 CPU;当 waiting 与数据库连接等待、锁等待一起抬升,优先看对应资源;当 live goroutines 上升而创建速率长期偏高,才把生命周期检查提到前面。若指标彼此矛盾,先保留“现象”结论,转到 pprof 或 execution trace 获取调用栈和阻塞原因。

常见问题

runtime/metrics 能替代 runtime.NumGoroutine 吗?

不能。live goroutines 是总量视角,调度指标是状态和资源视角,两者应该一起采集。

threads/total 为什么可能大于 GOMAXPROCS?

因为 GOMAXPROCS 是同时执行用户级 Go 代码的额度,而 threads/total 是运行时拥有的线程存量,系统调用、cgo 等场景会让两者承担不同职责。

只看到 waiting 很高,能直接判定 goroutine 泄漏吗?

不能。waiting 可能来自正常 I/O 或同步等待;需要结合持续趋势、调用栈、取消路径和资源指标确认。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
Go strings.CutLast 遇到空分隔符怎么判:最后一次切分与兼容写法Go strings.CutLast 遇到空分隔符怎么判:最后一次切分与兼容写法
上一篇
Go strings.CutLast 遇到空分隔符怎么判:最后一次切分与兼容写法
journalctl 重启后查不到旧日志:启动编号与持久化存储怎么一起核对
下一篇
journalctl 重启后查不到旧日志:启动编号与持久化存储怎么一起核对
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • SuperCLUE中文大模型评测基准:功能、能力维度与应用指南
    SuperCLUE
    SuperCLUE是权威的中文大语言模型综合评测基准,涵盖语言理解、知识应用、AI Agent智能体及安全性等12项核心能力。通过多轮对话与客观测试,定期发布榜单与技术报告,为模型研发、优化及行业选型提供科学依据。
    120次使用
  • C-Eval中文评测基准:大语言模型多学科能力评估指南
    C-Eval
    深入了解C-Eval中文评估套件,涵盖52个学科与4级难度。本文详解其功能特点、Zero-shot/Few-shot使用方法及代码示例,助您全面评测LLM中文理解与泛化能力。
    40次使用
  • Google AI提示词库:免费官方Prompt模板与使用指南
    Google AI提示词库
    探索Google Cloud官方生成式AI提示词库,提供免费、无需登录的中英双语Prompt模板。涵盖内容创作、代码优化、数据分析等场景,助您快速提升AI交互效率与质量。
    16次使用
  • Gradio是什么?Python开源库快速构建机器学习Web演示界面
    Gradio
    Gradio是一个用于构建机器学习和数据科学Web应用的开源Python库。支持快速创建交互界面,获Google、Meta等大厂青睐,适合模型演示、部署反馈及调试。
    122次使用
  • AgentGPT是什么?开源自主AI代理工具详解与本地部署指南
    AgentGPT
    深入了解AgentGPT:一款基于浏览器的自主人工智能代理工具。本文解析其核心功能、技术栈、应用场景,并提供详细的在线使用及本地部署教程,助您高效利用AI自动化完成任务。
    15次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码