教程集 www.jiaochengji.com
教程集 >  Golang编程  >  golang教程  >  正文 golang 协程追踪术

golang 协程追踪术

发布时间:2021-12-28   编辑:jiaochengji.com
教程集为您提供golang 协程追踪术等资源,欢迎您收藏本站,我们将为您提供最新的golang 协程追踪术资源
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"/></svg><h2>简介</h2>

对于绝大部分服务,跟踪刨析是用不到的。但是如果遇到了下面问题,可以不妨一试:

<ul><li>怀疑哪个协程慢了</li><li>系统调用有问题</li><li>协程调度问题 (chan 交互、互斥锁、信号量等)</li><li>怀疑是 gc (Garbage-Collect) 影响了服务性能</li><li>网络阻塞</li><li>等等</li></ul>

坦白的讲,通过跟踪刨析可以看到每个协程在某一时刻在干什么。

做跟踪刨析,首先需要获取trace 数据。可以通过代码中插入trace, 或者上节提到的通过pprof 下载即可。

<h2>
Example</h2> <h3>Code</h3>

下面通过代码直接插入的方式来获取trace. 内容会涉及到网络请求,涉及协程异步执行等。

<pre><code class="lang-go hljs"><span class="token keyword">package</span> main <span class="token keyword">import</span> <span class="token punctuation">(</span> <span class="token string">"io/ioutil"</span> <span class="token string">"math/rand"</span> <span class="token string">"net/http"</span> <span class="token string">"os"</span> <span class="token string">"runtime/trace"</span> <span class="token string">"strconv"</span> <span class="token string">"sync"</span> <span class="token string">"time"</span> <span class="token punctuation">)</span> <span class="token keyword">var</span> wg sync<span class="token punctuation">.</span>WaitGroup <span class="token keyword">var</span> httpClient <span class="token operator">=</span> <span class="token operator">&</span>http<span class="token punctuation">.</span>Client<span class="token punctuation">{</span>Timeout<span class="token punctuation">:</span> <span class="token number">30</span> <span class="token operator">*</span> time<span class="token punctuation">.</span>Second<span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">SleepSomeTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> time<span class="token punctuation">.</span>Duration<span class="token punctuation">{</span> <span class="token keyword">return</span> time<span class="token punctuation">.</span>Microsecond <span class="token operator">*</span> time<span class="token punctuation">.</span><span class="token function">Duration</span><span class="token punctuation">(</span>rand<span class="token punctuation">.</span><span class="token function">Int</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">%</span><span class="token number">1000</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">create</span><span class="token punctuation">(</span>readChan <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">defer</span> wg<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">for</span> i <span class="token operator">:=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator"><</span> <span class="token number">500</span><span class="token punctuation">;</span> i<span class="token operator"> </span> <span class="token punctuation">{</span> readChan <span class="token operator"><-</span> <span class="token function">getBodySize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token function">SleepSomeTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">close</span><span class="token punctuation">(</span>readChan<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">convert</span><span class="token punctuation">(</span>readChan <span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">,</span> output <span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">defer</span> wg<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">for</span> readChan <span class="token operator">:=</span> <span class="token keyword">range</span> readChan <span class="token punctuation">{</span> output <span class="token operator"><-</span> strconv<span class="token punctuation">.</span><span class="token function">Itoa</span><span class="token punctuation">(</span>readChan<span class="token punctuation">)</span> <span class="token function">SleepSomeTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token function">close</span><span class="token punctuation">(</span>output<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">outputStr</span><span class="token punctuation">(</span>output <span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">defer</span> wg<span class="token punctuation">.</span><span class="token function">Done</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">for</span> <span class="token boolean">_</span> <span class="token operator">=</span> <span class="token keyword">range</span> output <span class="token punctuation">{</span> <span class="token comment">// do nothing</span> <span class="token function">SleepSomeTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// 获取taobao 页面大小</span> <span class="token keyword">func</span> <span class="token function">getBodySize</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">int</span> <span class="token punctuation">{</span> resp<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> httpClient<span class="token punctuation">.</span><span class="token function">Get</span><span class="token punctuation">(</span><span class="token string">"https://taobao.com"</span><span class="token punctuation">)</span> res<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> ioutil<span class="token punctuation">.</span><span class="token function">ReadAll</span><span class="token punctuation">(</span>resp<span class="token punctuation">.</span>Body<span class="token punctuation">)</span> <span class="token boolean">_</span> <span class="token operator">=</span> resp<span class="token punctuation">.</span>Body<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">len</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> readChan<span class="token punctuation">,</span> output <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">int</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token keyword">chan</span> <span class="token builtin">string</span><span class="token punctuation">)</span> wg<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">create</span><span class="token punctuation">(</span>readChan<span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">convert</span><span class="token punctuation">(</span>readChan<span class="token punctuation">,</span> output<span class="token punctuation">)</span> <span class="token keyword">go</span> <span class="token function">outputStr</span><span class="token punctuation">(</span>output<span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token keyword">func</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> f<span class="token punctuation">,</span> <span class="token boolean">_</span> <span class="token operator">:=</span> os<span class="token punctuation">.</span><span class="token function">Create</span><span class="token punctuation">(</span><span class="token string">"trace.out"</span><span class="token punctuation">)</span> <span class="token keyword">defer</span> f<span class="token punctuation">.</span><span class="token function">Close</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token boolean">_</span> <span class="token operator">=</span> trace<span class="token punctuation">.</span><span class="token function">Start</span><span class="token punctuation">(</span>f<span class="token punctuation">)</span> <span class="token keyword">defer</span> trace<span class="token punctuation">.</span><span class="token function">Stop</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> wg<span class="token punctuation">.</span><span class="token function">Wait</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span> </code></pre>

编译,并执行,然后启动trace;

<pre><code class="lang-shell hljs"><span class="token punctuation">[</span>lipengfei5@localhost ~/blog<span class="token punctuation">]</span>$ go build trace_example.go <span class="token punctuation">[</span>lipengfei5@localhost ~/blog<span class="token punctuation">]</span>$ ./trace_example <span class="token punctuation">[</span>lipengfei5@localhost ~/blog<span class="token punctuation">]</span>$ go tool trace -http<span class="token operator">=</span><span class="token string">":8000"</span> trace_example trace.out 2020/04/15 17:34:48 Parsing trace<span class="token punctuation">..</span>. 2020/04/15 17:34:50 Splitting trace<span class="token punctuation">..</span>. 2020/04/15 17:34:51 Opening browser. Trace viewer is listening on http://0.0.0.0:8000 </code></pre>

然后打开浏览器,访问8000 端口即可。

<h3>
Trace 功能</h3>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-S5NSUPff-1587091032817)(trace_home.jpg)]

其中:
View trace:查看跟踪 (按照时间分段,上面我的例子时间比较短,所以没有分段)
Goroutine analysis:Goroutine 分析
Network blocking profile:网络阻塞概况
Synchronization blocking profile:同步阻塞概况
Syscall blocking profile:系统调用阻塞概况
Scheduler latency profile:调度延迟概况
User defined tasks:用户自定义任务
User defined regions:用户自定义区域
Minimum mutator utilization:最低 Mutator 利用率 (主要是GC 的评价标准, 暂时没搞懂)

<h3>
goroutine 调度分析</h3>

下图包含了两种事件:

<ol><li>网络相关 main.create 触发网络写的协程,网络写操作的协程 writeLoop,然后等待网络返回。</li><li>GC 相关操作</li></ol>


下面是web请求到数据,从epoll 中触发,然后readLoop协程响应,直接触发main.create 的协程得到执行。


当然我们也可以筛选协程做具体分析,从 Goroutine analysis 进入,选择具体的协程进行分析:


我们选择对 main.create 的协程做分析(这个协程略复杂,可以分析的东西比较多)

可以从图中看出,network 唤醒 readLoop 协程,进而readLoop 又通知了main.create 协程。

当然,我们也可以选择 main.convert 协程。可以看出协程被main.create 唤醒了(由于给chan 提供了数据)


除了可以分析goroutine 调度之外,还可以做网络阻塞分析,异步阻塞分析,系统调度阻塞分析,协程调度阻塞分析(下图)

<h3>
自定义 Task 和 Region</h3>

当然,还可以指定task 和 Region 做分析,下面是官方举的例子:

<pre><code class="lang-golang hljs">//filepath: src/runtime/trace/trace.go ctx, task := trace.NewTask(ctx, "makeCappuccino") trace.Log(ctx, "orderID", orderID) milk := make(chan bool) espresso := make(chan bool) go func() { trace.WithRegion(ctx, "steamMilk", steamMilk) milk <- true }() go func() { trace.WithRegion(ctx, "extractCoffee", extractCoffee) espresso <- true }() go func() { defer task.End() // When assemble is done, the order is complete. <-espresso <-milk trace.WithRegion(ctx, "mixMilkCoffee", mixMilkCoffee) }() </code></pre> <h3>
MMU 图</h3>

除此之外,还提供了Minimum Mutator Utilization 图 (mmu 图 )

mmu 图,数轴是服务可以占用cpu的百分比 (其他时间为gc操作)


从图中可以看出,在2ms之后,可利用的cpu逐步上升,直到接近100%.所以gc 毫无压力。

<h2>
重点提醒</h2> <ol><li>必须用chrome,并且高版本不行。我使用的是76.</li><li>trace 的文件都比较大,几分钟可能上百兆,所以网络一定要好,或者使用本机做验证。</li><li>造作是 w 放大, s 缩小, a 左移, d 右移</li><li>gc 的mmu 图解释 (备注下,还没有来得及看)https://www.cs.cmu.edu/~guyb/papers/gc2001.pdf</li></ol> 到此这篇关于“golang 协程追踪术”的文章就介绍到这了,更多文章或继续浏览下面的相关文章,希望大家以后多多支持JQ教程网!

您可能感兴趣的文章:
Go 协程的开启和退出
Go:通过 GODEBUG 提升对协程的利用
基于Golang设计一套微服务架构[转]
golang 协程追踪术
2020-08-20:GO语言中的协程与Python中的协程的区别?
如何实现云原生?这些云原生工具很关键!
golang append性能_GoLang定时器实现原理
Go:协程,操作系统线程和 CPU 管理
php程序员需要会什么技术?
golang微服务框架对比_斗鱼开源首秀——基于 Go 的微服务框架 Jupiter

[关闭]
~ ~