goroutine堆栈跟踪不完整。

3

我使用golang编写了一个Web应用程序。在生产环境中运行时,有些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已经在通道上等待了948分钟。显然,有些问题。但是堆栈跟踪似乎不完整。这对我来说不足以找到错误。(我想要一些从我的程序开始的堆栈跟踪。)
如何获取此goroutine的完整堆栈跟踪?还有其他调试此问题的方法吗?
更新:
我已经阅读了database/sql/sql.go的源代码。原来database/sql/sql.go:1440在一个新的goroutine中。堆栈跟踪是不完整的,因为之前的堆栈跟踪属于父goroutine。
我的问题应该是:是否有更好的方法来调试此问题?

尝试运行 go run -race *.go - Ari Seyhun
@Acidic 我已经尝试过了。也许这不是某种竞争条件。无论如何,谢谢。 - Eagle
@Eagle /database/sql/sql.go:1440 正在等待事务提交或回滚。您可以检查代码中未解决的事务。 - John S Perayil
@JohnSPerayil 我已经检查了我的代码。有很多使用 SQL 事务的 API,但我找不到一个没有 RollbackCommit 的。这就是为什么我想要获取完整的堆栈跟踪。无论如何,谢谢。 - Eagle
公平地说,这个跟踪并不是不完整的。它被调用为 go tx.awaitDone()。每个 goroutine 都有自己的堆栈,所以这是您正在检查的 goroutine 的堆栈的开头。 - Adrian
@Adrian 是的,你说得对。我已经更新了问题。现在我正在尝试修改一些 Go 源代码来跟踪这个 bug。 - Eagle
1个回答

0

我认为没有办法在不手动跟踪每个go例程调用并为其生成标识符的情况下获取父goroutine堆栈。

在这种特定情况下,可能的情况是您有一个事务未提交或回滚,因为发生错误并且函数过早退出而没有调用任何一个。

避免相同问题的良好模板是使用'defer'。

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:注意错误遮蔽。


谢谢。使用“defer”更好。我只是在每个“return”之前添加了“Rollback”或“Commit”。不过,我想它应该能够实现与你的代码相同的效果。 - Eagle
@Eagle 是的,defer 生成了相同功能更干净的代码。我想不出其他阻塞 goroutine 的情况,如果我想到了,我会更新答案。 - John S Perayil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接