<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Goroutine on Zampo Blog</title><link>https://blog.cpdd.fyi/tags/goroutine/</link><description>Recent content in Goroutine on Zampo Blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Thu, 21 May 2026 13:45:00 +0800</lastBuildDate><atom:link href="https://blog.cpdd.fyi/tags/goroutine/index.xml" rel="self" type="application/rss+xml"/><item><title>Go 服务 goroutine 涨了，别先猜：按这条流程查 context 泄漏</title><link>https://blog.cpdd.fyi/posts/go-context-goroutine-leak-debugging/</link><pubDate>Thu, 21 May 2026 13:45:00 +0800</pubDate><guid>https://blog.cpdd.fyi/posts/go-context-goroutine-leak-debugging/</guid><description>&lt;p&gt;线上 goroutine 数开始往上爬，最怕的不是它涨。&lt;/p&gt;
&lt;p&gt;最怕的是你盯着监控看了十分钟，然后开始猜：是不是 &lt;code&gt;context&lt;/code&gt; 泄漏了？是不是超时没生效？是不是某个 channel 卡住了？&lt;/p&gt;
&lt;p&gt;这些猜法都有可能对，也都有可能错。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;runtime.NumGoroutine()&lt;/code&gt; 只能告诉你“现在有多少 goroutine”。它不会告诉你这些 goroutine 停在哪里，也不会告诉你是谁创建的，更不会告诉你为什么没有退出。&lt;/p&gt;
&lt;p&gt;排查这类问题，第一步不是解释 &lt;code&gt;context&lt;/code&gt; 原理。&lt;/p&gt;
&lt;p&gt;第一步是采样。&lt;/p&gt;
&lt;p&gt;&lt;img src="https://blog.cpdd.fyi/images/go-context-goroutine-leak-debugging/cover.png" alt="Go context goroutine 泄漏排查封面"&gt;&lt;/p&gt;
&lt;p&gt;这篇是 Go &lt;code&gt;context&lt;/code&gt; 系列第三篇。前两篇讲过 &lt;code&gt;context&lt;/code&gt; 的生命周期、&lt;code&gt;cancel&lt;/code&gt; 的边界，以及 Go 为什么坚持显式传 &lt;code&gt;ctx&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这一篇换一个角度：不从源码开始，从排查现场开始。&lt;/p&gt;
&lt;p&gt;一套最小流程就够了：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;goroutine 涨了
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;先采样，确认趋势
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用 pprof 找等待点
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用 go vet 查静态路径
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;按创建路径、取消路径、响应路径回到代码
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;修复，再验证
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;img src="https://blog.cpdd.fyi/images/go-context-goroutine-leak-debugging/inline-01.png" alt="Go context 泄漏最小排查流程"&gt;&lt;/p&gt;</description></item></channel></rss>