【发布时间】:2017-01-12 13:52:44
【问题描述】:
我在go中写了一个日志收集程序,它运行了一堆goroutines如下:
- 例程A运行HTTP服务器,允许用户查看日志信息
- 例程 B 运行 UDP 服务器,允许从 LAN 向其发送日志消息
- 例程 C 运行一个计时器,它定期从内部 HTTP 文件服务器(不是程序的一部分)查询/下载压缩日志档案
- 例程 B 和 C 都将处理后的消息发送到 Channel
- 例程 D 运行一个带有 select 语句的 for {} 循环,该语句从 Channel 接收消息并将其刷新到磁盘
- 还有一些其他的 go 例程,例如扫描例程 D 生成的日志存档以创建 SQLite 索引等的例程。
程序有一个问题,在运行几个小时后,日志查看器 http 服务器仍然可以正常工作,但是没有来自 UDP 或文件服务器例程的消息。我知道从各种渠道发送的日志消息无穷无尽,如果我重新启动程序,它会再次开始处理传入的日志。
我在编译器中添加了-race,它确实发现了一些有问题的代码,我修复了这些,但问题仍然存在。更重要的是,虽然存在不雅问题,但在我们的生产服务器上运行的旧版本代码运行良好,不管不雅代码。
我的问题是,我该如何继续查明问题。以下是我的日志处理例程中的关键循环:
for {
select {
case msg := <-logCh:
logque.Cache(msg)
case <-time.After(time.Second):
}
if time.Since(lastFlush) >= 3 * time.Second {
logque.Flush()
lastFlush = time.Now()
}
}
【问题讨论】:
-
查看服务器停止工作时的堆栈跟踪,并查看每个 goroutine 被阻塞的位置。
-
程序运行良好时如何查看堆栈跟踪?请注意,显然没有任何问题,只是定时器例程在触发时没有打印消息,并且 UDP 服务器停止接收消息,并且控制台上没有任何输出
-
您可以发送 SIGQUIT 以退出堆栈跟踪,设置 http 处理程序或信号处理程序以按需打印,使用 pprof goroutine 端点等。您的 goruotines 因某种原因被阻止,所以你想知道为什么。
-
另外,如果有办法查看实时 goroutine 的跟踪,我该如何指出问题?即从堆栈跟踪中,什么表示阻塞问题?跟踪将明确告诉我例程处于“阻塞”状态?
标签: go race-condition