我使用 golang 编写了一个网络应用程序。当它在生产环境中运行时,有一些 goroutines 被阻塞了。以下是信息(使用 pprof
生成):
goroutine 792247 [chan receive, 948 minutes]:
database/sql.(*Tx).awaitDone(0xc4206e2b80)
/usr/local/go/src/database/sql/sql.go:1440 +0x57
created by database/sql.(*DB).begin
/usr/local/go/src/database/sql/sql.go:1383 +0x274
goroutine 已经在 channel 上等待了 948 分钟。显然,出了点问题。但堆栈跟踪似乎不完整。我发现错误还不够。 (我想要一些堆栈跟踪从我的程序开始。)
我怎样才能得到这个 goroutine 的完整堆栈跟踪? 或者还有其他方法可以调试此问题吗?
更新:
我看过database/sql/sql.go的源码。结果 database/sql/sql.go:1440
在一个新的 goroutine 中。堆栈跟踪不完整
,因为之前的堆栈跟踪属于parent
goroutine。
我的问题应该是:有没有更好的方法来调试这个问题?
最佳答案
我认为没有任何方法可以获取父 goroutine 堆栈,而无需手动跟踪每个 go 例程调用并为其生成 id。
在这种特定情况下,很可能您有一个尚未提交或回滚的事务,因为发生错误并且函数在未调用任何一个的情况下过早退出。
避免相同情况的一个好模板是使用“延迟”。
func (s Service) DoSomething() (err error) {
tx, err := s.db.Begin()
if err != nil {
return
}
defer func() {
if err != nil {
tx.Rollback()
return
}
err = tx.Commit()
}()
if _, err = tx.Exec(...); err != nil {
return
}
if _, err = tx.Exec(...); err != nil {
return
}
// ...
return }
PS:小心错误阴影。
关于performance - goroutine 堆栈跟踪不完整,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43488986/