转载

golang服务的问题分析

前段时间,维护的一个golang服务出现了一次问题:请求无响应且无日志输出。重启进程后,服务恢复了正常,但却没有足够信息来跟进分析此次问题了。

之前运维过java服务,java的分析工具还是比较丰富的,针对thread有jstack或者可以发送SIGQUIT信号,针对heap有jmap等,以及其它基于JMX的分析工具。

以类似的思维来分析golang服务的问题,先获取goroutine的stack trace信息。

golang提供了runtime这个包,其Stack函数可以输出所有goroutine的stack trace信息;另外,golang进程也可以接受SIGQUIT信号,默认会输出目前的goroutine的stack trace信息,但是主进程会以返回码2退出。

所以,如果不侵入代码且不影响进程正常运行,基本无法获得goroutine的stack trace信息。当然,这也提醒我们如果线上的golang服务出现了问题需要stack trace,至少应先发送个SIGQUIT信号保留现场goroutine的stack trace信息,然后再进行重启等处理。

如果利用golang的channel,侵入应用代码,则可以实现类似java的thread dump的效果,这样在收到SIGQUIT信号后会输出goroutine的stack trace,同时golang进程会正常运行。代码如下:

package main  import (     "log"     "os"     "os/signal"     "runtime"     "syscall" )  func main() {     go func() {         sigs := make(chan os.Signal, 1)         signal.Notify(sigs, syscall.SIGQUIT)         for {             <-sigs             // 给buf 1MB的空间,最好判断下空间是否足够             buf := make([]byte, 1<<20)             runtime.Stack(buf, true)             log.Printf("=== goroutine stack trace.../n%s/n=== end/n", buf)         }     }()      // 应用代码 } 

runtime/pprof提供了更详细的分析数据,包括cpu/heap/block/goroutinethreadcreate等数据。基于runtime/pprof,github.com/pkg/profile等更加方便了这些分析数据的采集。但是,这些采集对应用代码侵入较多,更适合于开发/测试环境。另外,golang也提供了基于runtime/pprof的net/http/pprof,以Http Server的方式提供,方便工程师查看分析数据。代码如下:

package main  import (     "log"     "net/http"     _ "net/http/pprof" )  func main() {     go func() {         log.Println(http.ListenAndServe(":6060", nil))     }()      // 应用代码 } 

访问http://127.0.0.1:6060/debug/pprof/,可以看到各项数据的菜单,http://127.0.0.1:6060/debug/pprof/goroutine?debug=2显示了goroutine的stack trace信息;同时,也可以使用go tool pprof分析数据。

参考链接

http://blog.golang.org/profiling-go-programs

https://github.com/quipo/goprofiler

https://github.com/pkg/profile

https://golang.org/pkg/net/http/pprof/

https://golang.org/pkg/runtime/

原文  http://mogu.io/179-179
正文到此结束
Loading...