原文: Debugging an evil Go runtime bug
作者:Hector Martin
翻译:雁惊寒
摘要:本文静述了作者经由过程对硬件、内核进行分析来调试法度榜样bug的┞符个过程。以下是译文。
媒介
我是 Prometheus 和 Grafana 的超等粉丝。作为一名前谷歌SRE(Site Reliability Engineer, 网站靠得住性工程师),我学会了若何选择优良的监控应用法度榜样。这个组合在以前的一年一一向是我战无不堪的法宝。我应用它们监控我本身的小我办事器(包含黑盒和白盒监控)、为我的客户供给专业的技巧支撑,以及实现其他很多的功能。 应用Prometheus编写自定义导出法度榜样来监督数据异常地简单,并且你可以很便利地在其他处所找到一个合适于本身的可用的导出法度榜样。例如,我们应用 sql_exporter 为Encounter事宜制造了一个异常漂亮的仪表盘。
Euskal Encounter的事宜仪表盘
因为把 node_exporter 安排到任何一台机械上都异常简单,并且它能运行一个Prometheus实例来为机械做根本的体系级监控(包含CPU、内存、收集、磁盘、文件体系的应用情况等),那么我想,为什么不监督一下我的标记本电脑呢?我有一台Clevo“游戏”标记本电脑,它是我重要的工作电脑,大年夜部分时光都是假装在家里做台式机,有时也会和我一路参加像混沌通信大年夜会(
Chaos Communication Congress)如许的大年夜型晃荡。因为我已经在它和一台运行Prometheus的办事器之间建立了VPN链接,所以,我可以经由过程履行emerge prometheus-node_exporter来启动办事,指向Prometheus实例,并主动为其设备戒备。这意味着每当我打开太多Chrome选项卡并耗光32GB内存的时刻,我的手机就会收到报警。完美!
$ grep '^[0246][012389ab][0189][014589cd][028a][012389ab][014589cd]' objs_0.txt6b9cab4f arch/x86/entry/vdso/vclock_gettime.o
问题浮现
不过,在设置完的一个小时之后,我的手机确切出现了一个提示:新添加的目标无法拜访。我可以SSH到标记本电脑,解释电脑运行正常,但node_exporter已经崩溃了。
fatal error: unexpected signal during runtime execution[signal SIGSEGV: segmentation violation code=0x1 addr=0xc41ffc7fff pc=0x41439e]goroutine 2395 [running]:runtime.throw(0xae6fb8, 0x2a) /usr/lib64/go/src/runtime/panic.go:605 +0x95 fp=0xc4203e8be8 sp=0xc4203e8bc8 pc=0x42c815runtime.sigpanic() /usr/lib64/go/src/runtime/signal_unix.go:351 +0x2b8 fp=0xc4203e8c38 sp=0xc4203e8be8 pc=0x443318runtime.heapBitsSetType(0xc4204b6fc0, 0x30, 0x30, 0xc420304058) /usr/lib64/go/src/runtime/mbitmap.go:1224 +0x26e fp=0xc4203e8c90 sp=0xc4203e8c38 pc=0x41439eruntime.mallocgc(0x30, 0xc420304058, 0x1, 0x1) /usr/lib64/go/src/runtime/malloc.go:741 +0x546 fp=0xc4203e8d38 sp=0xc4203e8c90 pc=0x411876runtime.newobject(0xa717e0, 0xc42032f430) /usr/lib64/go/src/runtime/malloc.go:840 +0x38 fp=0xc4203e8d68 sp=0xc4203e8d38 pc=0x411d68github.com/prometheus/node_exporter/vendor/github.com/prometheus/client_golang/prometheus.NewConstMetric(0xc42018e460, 0x2, 0x3ff0000000000000, 0xc42032f430, 0x1, 0x1, 0x10, 0x9f9dc0, 0x8a0601, 0xc42032f430) /var/tmp/portage/net-analyzer/prometheus-node_exporter-0.15.0/work/prometheus-node_exporter-0.15.0/src/github.com/prometheus/node_exporter/vendor/github.com/prometheus/client_golang/prometheus/value.go:165 +0xd0 fp=0xc4203e8dd0 sp=0xc4203e8d68 pc=0x77a980
像其他的Prometheus组件一样,node_exporter是用Go编写的。 Go是一种相对安然的说话,尽管有的时刻你可能会搬起石头砸本身的脚,并且它不像Rust那样具有强有力的安然包管,然则,要在Go中产生段缺点也并不是那么轻易的。 何况,node_exporter是一个相对来说比较简单的Go应用法度榜样,只纯真的依附Go。 是以,这是一个异常有趣的崩溃,特别是崩溃在mallocgc琅绫擎。一般情况下,这里永远都不会崩溃。
重启几回之后,工作变得更有趣了:
2017/11/07 06:32:49 http: panic serving 172.20.0.1:38504: runtime error: growslice: cap out of rangegoroutine 41 [running]:net/http.(*conn).serve.func1(0xc4201cdd60) /usr/lib64/go/src/net/http/server.go:1697 +0xd0panic(0xa24f20, 0xb41190) /usr/lib64/go/src/runtime/panic.go:491 +0x283fmt.(*buffer).WriteString(...) /usr/lib64/go/src/fmt/print.go:82fmt.(*fmt).padString(0xc42053a040, 0xc4204e6800, 0xc4204e6850) /usr/lib64/go/src/fmt/format.go:110 +0x110fmt.(*fmt).fmt_s(0xc42053a040, 0xc4204e6800, 0xc4204e6850) /usr/lib64/go/src/fmt/format.go:328 +0x61fmt.(*pp).fmtString(0xc42053a000, 0xc4204e6800, 0xc4204e6850, 0xc400000073) /usr/lib64/go/src/fmt/print.go:433 +0x197fmt.(*pp).printArg(0xc42053a000, 0x9f4700, 0xc42041c290, 0x73) /usr/lib64/go/src/fmt/print.go:664 +0x7b5fmt.(*pp).doPrintf(0xc42053a000, 0xae7c2d, 0x2c, 0xc420475670, 0x2, 0x2) /usr/lib64/go/src/fmt/print.go:996 +0x15afmt.Sprintf(0xae7c2d, 0x2c, 0xc420475670, 0x2, 0x2, 0x10, 0x9f4700) /usr/lib64/go/src/fmt/print.go:196 +0x66fmt.Errorf(0xae7c2d, 0x2c, 0xc420475670, 0x2, 0x2, 0xc420410301, 0xc420410300) /usr/lib64/go/src/fmt/print.go:205 +0x5a
太有趣了。 此次Sprintf出现崩溃了。 为什么?
runtime: pointer 0xc4203e2fb0 to unallocated span idx=0x1f1 span.base()=0xc4203dc000 span.limit=0xc4203e6000 span.state=3runtime: found in object at *(0xc420382a80+0x80)object=0xc420382a80 k=0x62101c1 s.base()=0xc420382000 s.limit=0xc420383f80 s.spanclass=42 s.elemsize=384 s.state=_MSpanInUse <snip>fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)runtime stack:runtime.throw(0xaee4fe, 0x3e) /usr/lib64/go/src/runtime/panic.go:605 +0x95 fp=0x7f0f19ffab90 sp=0x7f0f19ffab70 pc=0x42c815runtime.heapBitsForObject(0xc4203e2fb0, 0xc420382a80, 0x80, 0xc41ffd8a33, 0xc400000000, 0x7f0f400ac560, 0xc420031260, 0x11) /usr/lib64/go/src/runtime/mbitmap.go:425 +0x489 fp=0x7f0f19ffabe8 sp=0x7f0f19ffab90 pc=0x4137c9runtime.scanobject(0xc420382a80, 0xc420031260) /usr/lib64/go/src/runtime/mgcmark.go:1187 +0x25d fp=0x7f0f19ffac90 sp=0x7f0f19ffabe8 pc=0x41ebedruntime.gcDrain(0xc420031260, 0x5) /usr/lib64/go/src/runtime/mgcmark.go:943 +0x1ea fp=0x7f0f19fface0 sp=0x7f0f19ffac90 pc=0x41e42aruntime.gcBgMarkWorker.func2() /usr/lib64/go/src/runtime/mgc.go:1773 +0x80 fp=0x7f0f19ffad20 sp=0x7f0f19fface0 pc=0x4580b0runtime.systemstack(0xc420436ab8) /usr/lib64/go/src/runtime/asm_amd64.s:344 +0x79 fp=0x7f0f19ffad28 sp=0x7f0f19ffad20 pc=0x45a469runtime.mstart() /usr/lib64/go/src/runtime/proc.go:1125 fp=0x7f0f19ffad30 sp=0x7f0f19ffad28 pc=0x430fe0
推荐阅读
NVIDIA Titan V显卡拆解:211亿晶体管堆出巨型怪物
NVIDIA近日忽然宣布了第一款基于下代12nm Volta架构核心的显卡Titan V(此前的Tesla V100是计算卡),轻轻松松成为地球上最强大年夜的显卡。Titan V基于最高规格的GV100核心,集成211亿个晶>>>详细阅读
本文标题:Go运行时,对bug的分析调试过程解析
地址:http://www.17bianji.com/lsqh/39892.html
1/2 1